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