• 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 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 
TEST(SimpleProcess,Basic)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 
TEST(SimpleProcess,NoSearchPath)54 TEST(SimpleProcess, NoSearchPath) {
55   ProcessImpl process;
56   process.AddArg("echo");
57   EXPECT_EQ(127, process.Run());
58 }
59 
TEST(SimpleProcess,SearchPath)60 TEST(SimpleProcess, SearchPath) {
61   ProcessImpl process;
62   process.AddArg("echo");
63   process.SetSearchPath(true);
64   EXPECT_EQ(EXIT_SUCCESS, process.Run());
65 }
66 
TEST(SimpleProcess,BindFd)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 class ProcessTest : public ::testing::Test {
83  public:
SetUp()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 
SetUpTestCase()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 
TEST_F(ProcessTest,Basic)107 TEST_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 
TEST_F(ProcessTest,AddStringOption)115 TEST_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 
TEST_F(ProcessTest,AddIntValue)122 TEST_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 
TEST_F(ProcessTest,NonZeroReturnValue)129 TEST_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 
TEST_F(ProcessTest,BadOutputFile)136 TEST_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 
TEST_F(ProcessTest,BadExecutable)142 TEST_F(ProcessTest, BadExecutable) {
143   process_.AddArg("false");
144   EXPECT_EQ(static_cast<pid_t>(Process::kErrorExitStatus), process_.Run());
145 }
146 
CheckStderrCaptured()147 void 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 
TEST_F(ProcessTest,StderrCaptured)158 TEST_F(ProcessTest, StderrCaptured) {
159   CheckStderrCaptured();
160 }
161 
TEST_F(ProcessTest,StderrCapturedWhenPreviouslyClosed)162 TEST_F(ProcessTest, StderrCapturedWhenPreviouslyClosed) {
163   int saved_stderr = dup(STDERR_FILENO);
164   close(STDERR_FILENO);
165   CheckStderrCaptured();
166   dup2(saved_stderr, STDERR_FILENO);
167 }
168 
GetFdPath(int fd)169 FilePath ProcessTest::GetFdPath(int fd) {
170   return FilePath(base::StringPrintf("/proc/self/fd/%d", fd));
171 }
172 
TEST_F(ProcessTest,RedirectStderrUsingPipe)173 TEST_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 
TEST_F(ProcessTest,RedirectStderrUsingPipeWhenPreviouslyClosed)191 TEST_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 
TEST_F(ProcessTest,RedirectStdoutUsingPipe)202 TEST_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 
TEST_F(ProcessTest,RedirectStdinUsingPipe)219 TEST_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 
TEST_F(ProcessTest,WithSameUid)234 TEST_F(ProcessTest, WithSameUid) {
235   gid_t uid = geteuid();
236   process_.AddArg(kBinEcho);
237   process_.SetUid(uid);
238   EXPECT_EQ(0, process_.Run());
239 }
240 
TEST_F(ProcessTest,WithSameGid)241 TEST_F(ProcessTest, WithSameGid) {
242   gid_t gid = getegid();
243   process_.AddArg(kBinEcho);
244   process_.SetGid(gid);
245   EXPECT_EQ(0, process_.Run());
246 }
247 
TEST_F(ProcessTest,WithIllegalUid)248 TEST_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 
TEST_F(ProcessTest,WithIllegalGid)258 TEST_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 
TEST_F(ProcessTest,NoParams)268 TEST_F(ProcessTest, NoParams) {
269   EXPECT_EQ(-1, process_.Run());
270 }
271 
272 #if !defined(__BIONIC__)  // Bionic intercepts the segfault on Android.
TEST_F(ProcessTest,SegFaultHandling)273 TEST_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 
TEST_F(ProcessTest,KillHandling)282 TEST_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 
TEST_F(ProcessTest,KillNoPid)291 TEST_F(ProcessTest, KillNoPid) {
292   process_.Kill(SIGTERM, 0);
293   EXPECT_TRUE(FindLog("Process not running"));
294 }
295 
TEST_F(ProcessTest,ProcessExists)296 TEST_F(ProcessTest, ProcessExists) {
297   EXPECT_FALSE(Process::ProcessExists(0));
298   EXPECT_TRUE(Process::ProcessExists(1));
299   EXPECT_TRUE(Process::ProcessExists(getpid()));
300 }
301 
TEST_F(ProcessTest,ResetPidByFile)302 TEST_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 
TEST_F(ProcessTest,KillSleeper)315 TEST_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 
TEST_F(ProcessTest,Reset)325 TEST_F(ProcessTest, Reset) {
326   process_.AddArg(kBinFalse);
327   process_.Reset(0);
328   process_.AddArg(kBinEcho);
329   EXPECT_EQ(0, process_.Run());
330 }
331 
ReturnFalse()332 bool ReturnFalse() { return false; }
333 
TEST_F(ProcessTest,PreExecCallback)334 TEST_F(ProcessTest, PreExecCallback) {
335   process_.AddArg(kBinTrue);
336   process_.SetPreExecCallback(base::Bind(&ReturnFalse));
337   ASSERT_NE(0, process_.Run());
338 }
339 
TEST_F(ProcessTest,LeakUnusedFileDescriptors)340 TEST_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 
TEST_F(ProcessTest,CloseUnusedFileDescriptors)349 TEST_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