• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
TEST(SimpleProcess,Basic)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 
TEST(SimpleProcess,NoSearchPath)53 TEST(SimpleProcess, NoSearchPath) {
54   ProcessImpl process;
55   process.AddArg("echo");
56   EXPECT_EQ(127, process.Run());
57 }
58 
TEST(SimpleProcess,SearchPath)59 TEST(SimpleProcess, SearchPath) {
60   ProcessImpl process;
61   process.AddArg("echo");
62   process.SetSearchPath(true);
63   EXPECT_EQ(EXIT_SUCCESS, process.Run());
64 }
65 
TEST(SimpleProcess,BindFd)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.
TEST(DISABLED_SimpleProcess,BindFdToSameFd)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:
SetUp()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 
SetUpTestCase()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 
TEST_F(ProcessTest,Basic)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 
TEST_F(ProcessTest,AddStringOption)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 
TEST_F(ProcessTest,AddIntValue)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 
TEST_F(ProcessTest,NonZeroReturnValue)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 
TEST_F(ProcessTest,RedirectInputDevNull)159 TEST_F(ProcessTest, RedirectInputDevNull) {
160   process_.AddArg(kBinCat);
161   process_.RedirectInput("/dev/null");
162   EXPECT_EQ(0, process_.Run());
163 }
164 
TEST_F(ProcessTest,BadInputFile)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 
TEST_F(ProcessTest,BadOutputFile)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 
TEST_F(ProcessTest,BadExecutable)177 TEST_F(ProcessTest, BadExecutable) {
178   process_.AddArg("false");
179   EXPECT_EQ(static_cast<pid_t>(Process::kErrorExitStatus), process_.Run());
180 }
181 
CheckStderrCaptured()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 
TEST_F(ProcessTest,StderrCaptured)193 TEST_F(ProcessTest, StderrCaptured) {
194   CheckStderrCaptured();
195 }
196 
TEST_F(ProcessTest,StderrCapturedWhenPreviouslyClosed)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 
GetFdPath(int fd)204 FilePath ProcessTest::GetFdPath(int fd) {
205   return FilePath(base::StringPrintf("/proc/self/fd/%d", fd));
206 }
207 
TEST_F(ProcessTest,RedirectStderrUsingPipe)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 
TEST_F(ProcessTest,RedirectStderrUsingPipeWhenPreviouslyClosed)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 
TEST_F(ProcessTest,RedirectStdoutUsingPipe)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 
TEST_F(ProcessTest,RedirectStdinUsingPipe)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 
TEST_F(ProcessTest,WithSameUid)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 
TEST_F(ProcessTest,WithSameGid)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 
TEST_F(ProcessTest,WithIllegalUid)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 
TEST_F(ProcessTest,WithIllegalGid)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 
TEST_F(ProcessTest,NoParams)311 TEST_F(ProcessTest, NoParams) {
312   EXPECT_EQ(-1, process_.Run());
313 }
314 
315 #if !defined(__BIONIC__)  // Bionic intercepts the segfault on Android.
TEST_F(ProcessTest,SegFaultHandling)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 
TEST_F(ProcessTest,KillHandling)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 
TEST_F(ProcessTest,KillNoPid)334 TEST_F(ProcessTest, KillNoPid) {
335   process_.Kill(SIGTERM, 0);
336   EXPECT_TRUE(FindLog("Process not running"));
337 }
338 
TEST_F(ProcessTest,ProcessExists)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 
TEST_F(ProcessTest,ResetPidByFile)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 
TEST_F(ProcessTest,KillSleeper)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 
TEST_F(ProcessTest,Reset)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 
ReturnFalse()375 bool ReturnFalse() { return false; }
376 
TEST_F(ProcessTest,PreExecCallback)377 TEST_F(ProcessTest, PreExecCallback) {
378   process_.AddArg(kBinTrue);
379   process_.SetPreExecCallback(base::Bind(&ReturnFalse));
380   ASSERT_NE(0, process_.Run());
381 }
382 
TEST_F(ProcessTest,LeakUnusedFileDescriptors)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 
TEST_F(ProcessTest,CloseUnusedFileDescriptors)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