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