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