1// Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "brillo/process.h" 6 7#include <unistd.h> 8 9#include <base/files/file_path.h> 10#include <base/files/file_util.h> 11#include <base/files/scoped_temp_dir.h> 12#include <gtest/gtest.h> 13 14#include "brillo/process_mock.h" 15#include "brillo/unittest_utils.h" 16#include "brillo/test_helpers.h" 17 18using base::FilePath; 19 20// This test assumes the following standard binaries are installed. 21#if defined(__ANDROID__) 22# define SYSTEM_PREFIX "/system" 23static const char kBinStat[] = SYSTEM_PREFIX "/bin/stat"; 24#else 25# define SYSTEM_PREFIX "" 26static const char kBinStat[] = "/usr/bin/stat"; 27#endif 28 29static const char kBinSh[] = SYSTEM_PREFIX "/bin/sh"; 30static const char kBinCat[] = SYSTEM_PREFIX "/bin/cat"; 31static const char kBinCp[] = SYSTEM_PREFIX "/bin/cp"; 32static const char kBinEcho[] = SYSTEM_PREFIX "/bin/echo"; 33static const char kBinFalse[] = SYSTEM_PREFIX "/bin/false"; 34static const char kBinSleep[] = SYSTEM_PREFIX "/bin/sleep"; 35static const char kBinTrue[] = SYSTEM_PREFIX "/bin/true"; 36 37namespace brillo { 38 39// Test that the mock has all the functions of the interface by 40// instantiating it. This variable is not used elsewhere. 41struct CompileMocks { 42 ProcessMock process_mock; 43}; 44 45TEST(SimpleProcess, Basic) { 46 // Log must be cleared before running this test, just as ProcessTest::SetUp. 47 ClearLog(); 48 ProcessImpl process; 49 process.AddArg(kBinEcho); 50 EXPECT_EQ(0, process.Run()); 51 EXPECT_EQ("", GetLog()); 52} 53 54TEST(SimpleProcess, NoSearchPath) { 55 ProcessImpl process; 56 process.AddArg("echo"); 57 EXPECT_EQ(127, process.Run()); 58} 59 60TEST(SimpleProcess, SearchPath) { 61 ProcessImpl process; 62 process.AddArg("echo"); 63 process.SetSearchPath(true); 64 EXPECT_EQ(EXIT_SUCCESS, process.Run()); 65} 66 67TEST(SimpleProcess, BindFd) { 68 int fds[2]; 69 char buf[16]; 70 static const char* kMsg = "hello, world!"; 71 ProcessImpl process; 72 EXPECT_EQ(0, pipe(fds)); 73 process.AddArg(kBinEcho); 74 process.AddArg(kMsg); 75 process.BindFd(fds[1], 1); 76 process.Run(); 77 memset(buf, 0, sizeof(buf)); 78 EXPECT_EQ(read(fds[0], buf, sizeof(buf) - 1), strlen(kMsg) + 1); 79 EXPECT_EQ(std::string(kMsg) + "\n", std::string(buf)); 80} 81 82class ProcessTest : public ::testing::Test { 83 public: 84 void SetUp() { 85 CHECK(temp_dir_.CreateUniqueTempDir()); 86 output_file_ = temp_dir_.path().Append("fork_out").value(); 87 process_.RedirectOutput(output_file_); 88 ClearLog(); 89 } 90 91 static void SetUpTestCase() { 92 base::CommandLine::Init(0, nullptr); 93 ::brillo::InitLog(brillo::kLogToStderr); 94 ::brillo::LogToString(true); 95 } 96 97 protected: 98 void CheckStderrCaptured(); 99 FilePath GetFdPath(int fd); 100 101 ProcessImpl process_; 102 std::vector<const char*> args_; 103 std::string output_file_; 104 base::ScopedTempDir temp_dir_; 105}; 106 107TEST_F(ProcessTest, Basic) { 108 process_.AddArg(kBinEcho); 109 process_.AddArg("hello world"); 110 EXPECT_EQ(0, process_.Run()); 111 ExpectFileEquals("hello world\n", output_file_.c_str()); 112 EXPECT_EQ("", GetLog()); 113} 114 115TEST_F(ProcessTest, AddStringOption) { 116 process_.AddArg(kBinEcho); 117 process_.AddStringOption("--hello", "world"); 118 EXPECT_EQ(0, process_.Run()); 119 ExpectFileEquals("--hello world\n", output_file_.c_str()); 120} 121 122TEST_F(ProcessTest, AddIntValue) { 123 process_.AddArg(kBinEcho); 124 process_.AddIntOption("--answer", 42); 125 EXPECT_EQ(0, process_.Run()); 126 ExpectFileEquals("--answer 42\n", output_file_.c_str()); 127} 128 129TEST_F(ProcessTest, NonZeroReturnValue) { 130 process_.AddArg(kBinFalse); 131 EXPECT_EQ(1, process_.Run()); 132 ExpectFileEquals("", output_file_.c_str()); 133 EXPECT_EQ("", GetLog()); 134} 135 136TEST_F(ProcessTest, BadOutputFile) { 137 process_.AddArg(kBinEcho); 138 process_.RedirectOutput("/bad/path"); 139 EXPECT_EQ(static_cast<pid_t>(Process::kErrorExitStatus), process_.Run()); 140} 141 142TEST_F(ProcessTest, BadExecutable) { 143 process_.AddArg("false"); 144 EXPECT_EQ(static_cast<pid_t>(Process::kErrorExitStatus), process_.Run()); 145} 146 147void ProcessTest::CheckStderrCaptured() { 148 std::string contents; 149 process_.AddArg(kBinSh); 150 process_.AddArg("-c"); 151 process_.AddArg("echo errormessage 1>&2 && exit 1"); 152 EXPECT_EQ(1, process_.Run()); 153 EXPECT_TRUE(base::ReadFileToString(FilePath(output_file_), &contents)); 154 EXPECT_NE(std::string::npos, contents.find("errormessage")); 155 EXPECT_EQ("", GetLog()); 156} 157 158TEST_F(ProcessTest, StderrCaptured) { 159 CheckStderrCaptured(); 160} 161 162TEST_F(ProcessTest, StderrCapturedWhenPreviouslyClosed) { 163 int saved_stderr = dup(STDERR_FILENO); 164 close(STDERR_FILENO); 165 CheckStderrCaptured(); 166 dup2(saved_stderr, STDERR_FILENO); 167} 168 169FilePath ProcessTest::GetFdPath(int fd) { 170 return FilePath(base::StringPrintf("/proc/self/fd/%d", fd)); 171} 172 173TEST_F(ProcessTest, RedirectStderrUsingPipe) { 174 std::string contents; 175 process_.RedirectOutput(""); 176 process_.AddArg(kBinSh); 177 process_.AddArg("-c"); 178 process_.AddArg("echo errormessage >&2 && exit 1"); 179 process_.RedirectUsingPipe(STDERR_FILENO, false); 180 EXPECT_EQ(-1, process_.GetPipe(STDERR_FILENO)); 181 EXPECT_EQ(1, process_.Run()); 182 int pipe_fd = process_.GetPipe(STDERR_FILENO); 183 EXPECT_GE(pipe_fd, 0); 184 EXPECT_EQ(-1, process_.GetPipe(STDOUT_FILENO)); 185 EXPECT_EQ(-1, process_.GetPipe(STDIN_FILENO)); 186 EXPECT_TRUE(base::ReadFileToString(GetFdPath(pipe_fd), &contents)); 187 EXPECT_NE(std::string::npos, contents.find("errormessage")); 188 EXPECT_EQ("", GetLog()); 189} 190 191TEST_F(ProcessTest, RedirectStderrUsingPipeWhenPreviouslyClosed) { 192 int saved_stderr = dup(STDERR_FILENO); 193 close(STDERR_FILENO); 194 process_.RedirectOutput(""); 195 process_.AddArg(kBinCp); 196 process_.RedirectUsingPipe(STDERR_FILENO, false); 197 EXPECT_FALSE(process_.Start()); 198 EXPECT_TRUE(FindLog("Unable to fstat fd 2:")); 199 dup2(saved_stderr, STDERR_FILENO); 200} 201 202TEST_F(ProcessTest, RedirectStdoutUsingPipe) { 203 std::string contents; 204 process_.RedirectOutput(""); 205 process_.AddArg(kBinEcho); 206 process_.AddArg("hello world\n"); 207 process_.RedirectUsingPipe(STDOUT_FILENO, false); 208 EXPECT_EQ(-1, process_.GetPipe(STDOUT_FILENO)); 209 EXPECT_EQ(0, process_.Run()); 210 int pipe_fd = process_.GetPipe(STDOUT_FILENO); 211 EXPECT_GE(pipe_fd, 0); 212 EXPECT_EQ(-1, process_.GetPipe(STDERR_FILENO)); 213 EXPECT_EQ(-1, process_.GetPipe(STDIN_FILENO)); 214 EXPECT_TRUE(base::ReadFileToString(GetFdPath(pipe_fd), &contents)); 215 EXPECT_NE(std::string::npos, contents.find("hello world\n")); 216 EXPECT_EQ("", GetLog()); 217} 218 219TEST_F(ProcessTest, RedirectStdinUsingPipe) { 220 std::string contents; 221 const char kMessage[] = "made it!\n"; 222 process_.AddArg(kBinCat); 223 process_.RedirectUsingPipe(STDIN_FILENO, true); 224 process_.RedirectOutput(output_file_); 225 EXPECT_TRUE(process_.Start()); 226 int write_fd = process_.GetPipe(STDIN_FILENO); 227 EXPECT_EQ(-1, process_.GetPipe(STDERR_FILENO)); 228 EXPECT_TRUE(base::WriteFile(GetFdPath(write_fd), kMessage, strlen(kMessage))); 229 close(write_fd); 230 EXPECT_EQ(0, process_.Wait()); 231 ExpectFileEquals(kMessage, output_file_.c_str()); 232} 233 234TEST_F(ProcessTest, WithSameUid) { 235 gid_t uid = geteuid(); 236 process_.AddArg(kBinEcho); 237 process_.SetUid(uid); 238 EXPECT_EQ(0, process_.Run()); 239} 240 241TEST_F(ProcessTest, WithSameGid) { 242 gid_t gid = getegid(); 243 process_.AddArg(kBinEcho); 244 process_.SetGid(gid); 245 EXPECT_EQ(0, process_.Run()); 246} 247 248TEST_F(ProcessTest, WithIllegalUid) { 249 ASSERT_NE(0, geteuid()); 250 process_.AddArg(kBinEcho); 251 process_.SetUid(0); 252 EXPECT_EQ(static_cast<pid_t>(Process::kErrorExitStatus), process_.Run()); 253 std::string contents; 254 EXPECT_TRUE(base::ReadFileToString(FilePath(output_file_), &contents)); 255 EXPECT_NE(std::string::npos, contents.find("Unable to set UID to 0: 1\n")); 256} 257 258TEST_F(ProcessTest, WithIllegalGid) { 259 ASSERT_NE(0, getegid()); 260 process_.AddArg(kBinEcho); 261 process_.SetGid(0); 262 EXPECT_EQ(static_cast<pid_t>(Process::kErrorExitStatus), process_.Run()); 263 std::string contents; 264 EXPECT_TRUE(base::ReadFileToString(FilePath(output_file_), &contents)); 265 EXPECT_NE(std::string::npos, contents.find("Unable to set GID to 0: 1\n")); 266} 267 268TEST_F(ProcessTest, NoParams) { 269 EXPECT_EQ(-1, process_.Run()); 270} 271 272#if !defined(__BIONIC__) // Bionic intercepts the segfault on Android. 273TEST_F(ProcessTest, SegFaultHandling) { 274 process_.AddArg(kBinSh); 275 process_.AddArg("-c"); 276 process_.AddArg("kill -SEGV $$"); 277 EXPECT_EQ(-1, process_.Run()); 278 EXPECT_TRUE(FindLog("did not exit normally: 11")); 279} 280#endif 281 282TEST_F(ProcessTest, KillHandling) { 283 process_.AddArg(kBinSh); 284 process_.AddArg("-c"); 285 process_.AddArg("kill -KILL $$"); 286 EXPECT_EQ(-1, process_.Run()); 287 EXPECT_TRUE(FindLog("did not exit normally: 9")); 288} 289 290 291TEST_F(ProcessTest, KillNoPid) { 292 process_.Kill(SIGTERM, 0); 293 EXPECT_TRUE(FindLog("Process not running")); 294} 295 296TEST_F(ProcessTest, ProcessExists) { 297 EXPECT_FALSE(Process::ProcessExists(0)); 298 EXPECT_TRUE(Process::ProcessExists(1)); 299 EXPECT_TRUE(Process::ProcessExists(getpid())); 300} 301 302TEST_F(ProcessTest, ResetPidByFile) { 303 FilePath pid_path = temp_dir_.path().Append("pid"); 304 EXPECT_FALSE(process_.ResetPidByFile(pid_path.value())); 305 EXPECT_TRUE(base::WriteFile(pid_path, "456\n", 4)); 306 EXPECT_TRUE(process_.ResetPidByFile(pid_path.value())); 307 EXPECT_EQ(456, process_.pid()); 308 // The purpose of this unit test is to check if Process::ResetPidByFile() can 309 // properly read a pid from a file. We don't really want to kill the process 310 // with pid 456, so update the pid to 0 to prevent the Process destructor from 311 // killing any innocent process. 312 process_.UpdatePid(0); 313} 314 315TEST_F(ProcessTest, KillSleeper) { 316 process_.AddArg(kBinSleep); 317 process_.AddArg("10000"); 318 ASSERT_TRUE(process_.Start()); 319 pid_t pid = process_.pid(); 320 ASSERT_GT(pid, 1); 321 EXPECT_TRUE(process_.Kill(SIGTERM, 1)); 322 EXPECT_EQ(0, process_.pid()); 323} 324 325TEST_F(ProcessTest, Reset) { 326 process_.AddArg(kBinFalse); 327 process_.Reset(0); 328 process_.AddArg(kBinEcho); 329 EXPECT_EQ(0, process_.Run()); 330} 331 332bool ReturnFalse() { return false; } 333 334TEST_F(ProcessTest, PreExecCallback) { 335 process_.AddArg(kBinTrue); 336 process_.SetPreExecCallback(base::Bind(&ReturnFalse)); 337 ASSERT_NE(0, process_.Run()); 338} 339 340TEST_F(ProcessTest, LeakUnusedFileDescriptors) { 341 ScopedPipe pipe; 342 process_.AddArg(kBinStat); 343 process_.AddArg(GetFdPath(pipe.reader).value()); 344 process_.AddArg(GetFdPath(pipe.writer).value()); 345 process_.SetCloseUnusedFileDescriptors(false); 346 EXPECT_EQ(0, process_.Run()); 347} 348 349TEST_F(ProcessTest, CloseUnusedFileDescriptors) { 350 ScopedPipe pipe; 351 process_.AddArg(kBinStat); 352 process_.AddArg(GetFdPath(pipe.reader).value()); 353 process_.AddArg(GetFdPath(pipe.writer).value()); 354 process_.SetCloseUnusedFileDescriptors(true); 355 // Stat should fail when running on these file descriptor because the files 356 // should not be there. 357 EXPECT_EQ(1, process_.Run()); 358} 359 360} // namespace brillo 361