blob: 83e26bd2e01c3e121729669e082396299f0d49be [file] [log] [blame]
Ben Chan6f391cb2012-03-21 17:38:21 -07001// 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 "cros-disks/process.h"
6
François Degrosc0b33b12019-09-12 14:50:43 +10007#include <csignal>
8#include <memory>
9#include <ostream>
10#include <utility>
11
12#include <fcntl.h>
13#include <sys/time.h>
14#include <unistd.h>
15
Sergei Datsenkocd676b72019-05-10 11:42:05 +100016#include <base/files/file_path.h>
17#include <base/files/file_util.h>
François Degrosc0b33b12019-09-12 14:50:43 +100018#include <base/files/scoped_file.h>
19#include <base/logging.h>
20#include <base/strings/string_piece.h>
21#include <base/strings/stringprintf.h>
22#include <chromeos/libminijail.h>
Sergei Datsenkocd676b72019-05-10 11:42:05 +100023
Ben Chan6f391cb2012-03-21 17:38:21 -070024#include <gmock/gmock.h>
25#include <gtest/gtest.h>
26
François Degros4a76d702019-09-26 14:54:35 +100027#include "cros-disks/sandboxed_init.h"
Sergei Datsenkocd676b72019-05-10 11:42:05 +100028#include "cros-disks/sandboxed_process.h"
29
Ben Chan6f391cb2012-03-21 17:38:21 -070030namespace cros_disks {
François Degrosc0b33b12019-09-12 14:50:43 +100031namespace {
Ben Chan6f391cb2012-03-21 17:38:21 -070032
Sergei Datsenkocd676b72019-05-10 11:42:05 +100033using testing::_;
34using testing::Contains;
Sergei Datsenko9246e9c2019-03-22 10:26:47 +110035using testing::ElementsAre;
François Degrosedaefc52019-10-03 12:00:20 +100036using testing::IsEmpty;
François Degrosc0b33b12019-09-12 14:50:43 +100037using testing::PrintToStringParamName;
Sergei Datsenko9246e9c2019-03-22 10:26:47 +110038using testing::Return;
François Degrosc0b33b12019-09-12 14:50:43 +100039using testing::SizeIs;
40using testing::StartsWith;
41using testing::UnorderedElementsAre;
42using testing::Values;
Sergei Datsenko9246e9c2019-03-22 10:26:47 +110043
François Degrosc0b33b12019-09-12 14:50:43 +100044// Sets a signal handler for SIGALRM and an interval timer signaling SIGALRM at
45// regular intervals.
46class AlarmGuard {
47 public:
48 explicit AlarmGuard(const int timer_interval_ms) {
49 CHECK(!old_handler_);
50 count_ = 0;
51 old_handler_ = signal(SIGALRM, &Handler);
52 CHECK_NE(old_handler_, SIG_ERR);
53 SetIntervalTimer(timer_interval_ms * 1000 /* microseconds */);
54 }
55
56 ~AlarmGuard() {
57 SetIntervalTimer(0);
58 CHECK_EQ(signal(SIGALRM, old_handler_), &Handler);
59 old_handler_ = nullptr;
60 }
61
62 // Number of times SIGALRM has been received.
63 static int count() { return count_; }
64
65 private:
66 static void Handler(int sig) {
67 CHECK_EQ(sig, SIGALRM);
68 ++count_;
69 }
70
71 static void SetIntervalTimer(const int usec) {
72 const itimerval tv = {{0, usec}, {0, usec}};
73 if (setitimer(ITIMER_REAL, &tv, nullptr) < 0) {
74 PLOG(FATAL) << "Cannot set timer";
75 }
76 }
77
78 // Number of times SIGALRM has been received.
79 static int count_;
80
81 using SigHandler = void (*)(int);
82 static SigHandler old_handler_;
83
84 DISALLOW_COPY_AND_ASSIGN(AlarmGuard);
85};
86
87int AlarmGuard::count_ = 0;
88AlarmGuard::SigHandler AlarmGuard::old_handler_ = nullptr;
89
François Degros56829142019-10-16 22:00:11 +110090std::string Read(const int fd) {
François Degrosc0b33b12019-09-12 14:50:43 +100091 char buffer[PIPE_BUF];
92
François Degros56829142019-10-16 22:00:11 +110093 LOG(INFO) << "Reading up to " << PIPE_BUF << " bytes from fd " << fd << "...";
94 const ssize_t bytes_read = HANDLE_EINTR(read(fd, buffer, PIPE_BUF));
95 PLOG_IF(FATAL, bytes_read < 0) << "Cannot read from fd " << fd;
François Degrosc0b33b12019-09-12 14:50:43 +100096
François Degros56829142019-10-16 22:00:11 +110097 LOG(INFO) << "Read " << bytes_read << " bytes from fd " << fd;
François Degrosc0b33b12019-09-12 14:50:43 +100098 return std::string(buffer, bytes_read);
99}
100
François Degros56829142019-10-16 22:00:11 +1100101void Write(const int fd, base::StringPiece s) {
François Degrosc0b33b12019-09-12 14:50:43 +1000102 while (!s.empty()) {
François Degros56829142019-10-16 22:00:11 +1100103 const ssize_t bytes_written = HANDLE_EINTR(write(fd, s.data(), s.size()));
104 PLOG_IF(FATAL, bytes_written < 0) << "Cannot write to fd " << fd;
François Degrosc0b33b12019-09-12 14:50:43 +1000105
106 s.remove_prefix(bytes_written);
107 }
108}
109
110// A mock Process class for testing the Process base class.
Ben Chan6f391cb2012-03-21 17:38:21 -0700111class ProcessUnderTest : public Process {
112 public:
Ben Chan21150af2019-09-11 17:04:07 -0700113 MOCK_METHOD(pid_t,
114 StartImpl,
François Degros1ef69942019-10-01 15:31:17 +1000115 (base::ScopedFD, base::ScopedFD, base::ScopedFD),
Ben Chan21150af2019-09-11 17:04:07 -0700116 (override));
117 MOCK_METHOD(int, WaitImpl, (), (override));
François Degros92bbea42019-09-13 10:42:52 +1000118 MOCK_METHOD(int, WaitNonBlockingImpl, (), (override));
Ben Chan6f391cb2012-03-21 17:38:21 -0700119};
120
François Degrosc0b33b12019-09-12 14:50:43 +1000121struct ProcessFactory {
122 base::StringPiece name;
123 std::unique_ptr<Process> (*make_process)();
124};
125
126std::ostream& operator<<(std::ostream& out, const ProcessFactory& x) {
127 return out << x.name;
128}
129
130} // namespace
131
Ben Chan6f391cb2012-03-21 17:38:21 -0700132class ProcessTest : public ::testing::Test {
133 protected:
134 ProcessUnderTest process_;
135};
136
137TEST_F(ProcessTest, GetArguments) {
François Degros5593b8c2019-07-25 12:27:42 +1000138 const char* const kTestArguments[] = {"/bin/ls", "-l", "", "."};
Ben Chan6057fe62016-12-02 10:08:59 -0800139 for (const char* test_argument : kTestArguments) {
140 process_.AddArgument(test_argument);
Ben Chan6f391cb2012-03-21 17:38:21 -0700141 }
142
Sergei Datsenkocd676b72019-05-10 11:42:05 +1000143 EXPECT_THAT(process_.arguments(), ElementsAre("/bin/ls", "-l", "", "."));
Sergei Datsenko9246e9c2019-03-22 10:26:47 +1100144
François Degros5593b8c2019-07-25 12:27:42 +1000145 char* const* arguments = process_.GetArguments();
Ben Chan44e7ea62014-08-29 18:13:37 -0700146 EXPECT_NE(nullptr, arguments);
Ben Chan6057fe62016-12-02 10:08:59 -0800147 for (const char* test_argument : kTestArguments) {
148 EXPECT_STREQ(test_argument, *arguments);
149 ++arguments;
Ben Chan6f391cb2012-03-21 17:38:21 -0700150 }
Ben Chan6057fe62016-12-02 10:08:59 -0800151 EXPECT_EQ(nullptr, *arguments);
Ben Chan6f391cb2012-03-21 17:38:21 -0700152}
153
154TEST_F(ProcessTest, GetArgumentsWithNoArgumentsAdded) {
François Degros2a4ec242019-10-15 16:28:54 +1100155 char* const* arguments = process_.GetArguments();
156 EXPECT_NE(nullptr, arguments);
157 EXPECT_EQ(nullptr, *arguments);
Ben Chan6f391cb2012-03-21 17:38:21 -0700158}
159
Sergei Datsenko9246e9c2019-03-22 10:26:47 +1100160TEST_F(ProcessTest, Run_Success) {
Sergei Datsenkocd676b72019-05-10 11:42:05 +1000161 process_.AddArgument("foo");
François Degros5593b8c2019-07-25 12:27:42 +1000162 EXPECT_CALL(process_, StartImpl(_, _, _)).WillOnce(Return(123));
François Degrosedaefc52019-10-03 12:00:20 +1000163 EXPECT_CALL(process_, WaitImpl()).Times(0);
164 EXPECT_CALL(process_, WaitNonBlockingImpl()).WillOnce(Return(42));
165 std::vector<std::string> output;
166 EXPECT_EQ(process_.Run(&output), 42);
167 EXPECT_THAT(output, IsEmpty());
Sergei Datsenko9246e9c2019-03-22 10:26:47 +1100168}
169
170TEST_F(ProcessTest, Run_Fail) {
Sergei Datsenkocd676b72019-05-10 11:42:05 +1000171 process_.AddArgument("foo");
François Degros5593b8c2019-07-25 12:27:42 +1000172 EXPECT_CALL(process_, StartImpl(_, _, _)).WillOnce(Return(-1));
Sergei Datsenkocd676b72019-05-10 11:42:05 +1000173 EXPECT_CALL(process_, WaitImpl()).Times(0);
François Degros92bbea42019-09-13 10:42:52 +1000174 EXPECT_CALL(process_, WaitNonBlockingImpl()).Times(0);
François Degrosedaefc52019-10-03 12:00:20 +1000175 std::vector<std::string> output;
176 EXPECT_EQ(process_.Run(&output), -1);
177 EXPECT_THAT(output, IsEmpty());
Sergei Datsenko9246e9c2019-03-22 10:26:47 +1100178}
179
François Degrosc0b33b12019-09-12 14:50:43 +1000180class ProcessRunTest : public ::testing::TestWithParam<ProcessFactory> {
181 public:
182 ProcessRunTest() {
183 // Ensure that we get an error message if Minijail crashes.
184 // TODO(crbug.com/1007098) Remove the following line or this comment
185 // depending on how this bug is resolved.
186 minijail_log_to_fd(STDERR_FILENO, 0);
187 }
Sergei Datsenkocd676b72019-05-10 11:42:05 +1000188
François Degrosc0b33b12019-09-12 14:50:43 +1000189 const std::unique_ptr<Process> process_ = GetParam().make_process();
190};
Sergei Datsenkocd676b72019-05-10 11:42:05 +1000191
François Degros56829142019-10-16 22:00:11 +1100192TEST_P(ProcessRunTest, RunReturnsZero) {
François Degrosc0b33b12019-09-12 14:50:43 +1000193 Process& process = *process_;
François Degros56829142019-10-16 22:00:11 +1100194 process.AddArgument("/bin/sh");
195 process.AddArgument("-c");
196 process.AddArgument("exit 0");
François Degrosedaefc52019-10-03 12:00:20 +1000197 std::vector<std::string> output;
198 EXPECT_EQ(process.Run(&output), 0);
199 EXPECT_THAT(output, IsEmpty());
Sergei Datsenkocd676b72019-05-10 11:42:05 +1000200}
201
François Degros56829142019-10-16 22:00:11 +1100202TEST_P(ProcessRunTest, WaitReturnsZero) {
François Degrosc0b33b12019-09-12 14:50:43 +1000203 Process& process = *process_;
François Degros56829142019-10-16 22:00:11 +1100204 process.AddArgument("/bin/sh");
205 process.AddArgument("-c");
206 process.AddArgument("exit 0");
207 EXPECT_TRUE(process.Start());
208 EXPECT_EQ(process.Wait(), 0);
209}
210
211TEST_P(ProcessRunTest, RunReturnsNonZero) {
212 Process& process = *process_;
213 process.AddArgument("/bin/sh");
214 process.AddArgument("-c");
215 process.AddArgument("exit 42");
François Degrosedaefc52019-10-03 12:00:20 +1000216 std::vector<std::string> output;
François Degros56829142019-10-16 22:00:11 +1100217 EXPECT_EQ(process.Run(&output), 42);
François Degrosedaefc52019-10-03 12:00:20 +1000218 EXPECT_THAT(output, IsEmpty());
François Degrosc0b33b12019-09-12 14:50:43 +1000219}
220
François Degros56829142019-10-16 22:00:11 +1100221TEST_P(ProcessRunTest, WaitReturnsNonZero) {
222 Process& process = *process_;
223 process.AddArgument("/bin/sh");
224 process.AddArgument("-c");
225 process.AddArgument("exit 42");
226 EXPECT_TRUE(process.Start());
227 EXPECT_EQ(process.Wait(), 42);
228}
229
230TEST_P(ProcessRunTest, RunKilledBySigKill) {
François Degrosc0b33b12019-09-12 14:50:43 +1000231 Process& process = *process_;
232 process.AddArgument("/bin/sh");
233 process.AddArgument("-c");
234 process.AddArgument("kill -KILL $$; sleep 1000");
François Degrosedaefc52019-10-03 12:00:20 +1000235 std::vector<std::string> output;
François Degros56829142019-10-16 22:00:11 +1100236 EXPECT_EQ(process.Run(&output), MINIJAIL_ERR_SIG_BASE + SIGKILL);
François Degrosedaefc52019-10-03 12:00:20 +1000237 EXPECT_THAT(output, IsEmpty());
François Degrosc0b33b12019-09-12 14:50:43 +1000238}
239
François Degros56829142019-10-16 22:00:11 +1100240TEST_P(ProcessRunTest, WaitKilledBySigKill) {
241 Process& process = *process_;
242 process.AddArgument("/bin/sh");
243 process.AddArgument("-c");
244 process.AddArgument("kill -KILL $$; sleep 1000");
245 EXPECT_TRUE(process.Start());
246 EXPECT_EQ(process.Wait(), MINIJAIL_ERR_SIG_BASE + SIGKILL);
247}
248
249TEST_P(ProcessRunTest, RunKilledBySigSys) {
François Degrosc0b33b12019-09-12 14:50:43 +1000250 Process& process = *process_;
251 process.AddArgument("/bin/sh");
252 process.AddArgument("-c");
253 process.AddArgument("kill -SYS $$; sleep 1000");
François Degrosedaefc52019-10-03 12:00:20 +1000254 std::vector<std::string> output;
255 EXPECT_EQ(process.Run(&output), MINIJAIL_ERR_JAIL);
256 EXPECT_THAT(output, IsEmpty());
François Degrosc0b33b12019-09-12 14:50:43 +1000257}
258
François Degros56829142019-10-16 22:00:11 +1100259TEST_P(ProcessRunTest, WaitKilledBySigSys) {
François Degrosc0b33b12019-09-12 14:50:43 +1000260 Process& process = *process_;
François Degros56829142019-10-16 22:00:11 +1100261 process.AddArgument("/bin/sh");
262 process.AddArgument("-c");
263 process.AddArgument("kill -SYS $$; sleep 1000");
264 EXPECT_TRUE(process.Start());
265 EXPECT_EQ(process.Wait(), MINIJAIL_ERR_JAIL);
266}
267
François Degros21bc9bb2020-04-18 00:14:43 +1000268TEST_P(ProcessRunTest, ExternallyKilledBySigKill) {
269 Process& process = *process_;
270 process.AddArgument("/bin/sh");
271 process.AddArgument("-c");
272
273 // Pipe to block the child process.
274 SubprocessPipe to_block(SubprocessPipe::kParentToChild);
275
276 // Pipe to monitor the child process.
277 SubprocessPipe to_wait(SubprocessPipe::kChildToParent);
278
279 process.AddArgument(base::StringPrintf(
280 R"(
281 printf 'Begin\n' >&%d;
282 read line <&%d;
283 printf '%%s and End\n' "$line" >&%d;
284 exit 42;
285 )",
286 to_wait.child_fd.get(), to_block.child_fd.get(), to_wait.child_fd.get()));
287
288 EXPECT_TRUE(process.Start());
289
290 // Close unused pipe ends.
291 to_block.child_fd.reset();
292 to_wait.child_fd.reset();
293
294 // Wait for child process to start.
295 EXPECT_EQ(Read(to_wait.parent_fd.get()), "Begin\n");
296
297 // Send SIGKILL to child process.
298 const pid_t pid = process.pid();
299 LOG(INFO) << "Sending signal to PID " << pid;
300 EXPECT_EQ(kill(pid, SIGKILL), 0);
301
302 // Wait for child process to finish.
303 EXPECT_EQ(Read(to_wait.parent_fd.get()), "");
304 EXPECT_EQ(process.Wait(), MINIJAIL_ERR_SIG_BASE + SIGKILL);
305}
306
307TEST_P(ProcessRunTest, ExternallyKilledBySigTerm) {
308 Process& process = *process_;
309 process.AddArgument("/bin/sh");
310 process.AddArgument("-c");
311
312 // Pipe to block the child process.
313 SubprocessPipe to_block(SubprocessPipe::kParentToChild);
314
315 // Pipe to monitor the child process.
316 SubprocessPipe to_wait(SubprocessPipe::kChildToParent);
317
318 process.AddArgument(base::StringPrintf(
319 R"(
320 printf 'Begin\n' >&%d;
321 read line <&%d;
322 printf '%%s and End\n' "$line" >&%d;
323 exit 42;
324 )",
325 to_wait.child_fd.get(), to_block.child_fd.get(), to_wait.child_fd.get()));
326
327 EXPECT_TRUE(process.Start());
328
329 // Close unused pipe ends.
330 to_block.child_fd.reset();
331 to_wait.child_fd.reset();
332
333 // Wait for child process to start.
334 EXPECT_EQ(Read(to_wait.parent_fd.get()), "Begin\n");
335
336 // Send SIGTERM to child process.
337 const pid_t pid = process.pid();
338 LOG(INFO) << "Sending signal to PID " << pid;
339 EXPECT_EQ(kill(pid, SIGTERM), 0);
340
341 // Wait for child process to finish.
342 EXPECT_EQ(Read(to_wait.parent_fd.get()), "");
343 EXPECT_EQ(process.Wait(), MINIJAIL_ERR_SIG_BASE + SIGTERM);
344}
345
François Degros56829142019-10-16 22:00:11 +1100346TEST_P(ProcessRunTest, RunCannotFindCommand) {
347 Process& process = *process_;
348 process.AddArgument("non existing command");
François Degrosedaefc52019-10-03 12:00:20 +1000349 std::vector<std::string> output;
François Degrosa97ad492019-10-04 12:12:12 +1000350 EXPECT_EQ(process.Run(&output), MINIJAIL_ERR_NO_COMMAND);
François Degrosc0b33b12019-09-12 14:50:43 +1000351}
352
François Degros56829142019-10-16 22:00:11 +1100353TEST_P(ProcessRunTest, WaitCannotFindCommand) {
354 Process& process = *process_;
355 process.AddArgument("non existing command");
356 EXPECT_TRUE(process.Start());
François Degrosa97ad492019-10-04 12:12:12 +1000357 EXPECT_EQ(process.Wait(), MINIJAIL_ERR_NO_COMMAND);
François Degros56829142019-10-16 22:00:11 +1100358}
359
360TEST_P(ProcessRunTest, RunCannotRunCommand) {
361 Process& process = *process_;
362 process.AddArgument("/dev/null");
363 std::vector<std::string> output;
François Degrosa97ad492019-10-04 12:12:12 +1000364 EXPECT_EQ(process.Run(&output), MINIJAIL_ERR_NO_ACCESS);
François Degros56829142019-10-16 22:00:11 +1100365}
366
367TEST_P(ProcessRunTest, WaitCannotRunCommand) {
368 Process& process = *process_;
369 process.AddArgument("/dev/null");
370 EXPECT_TRUE(process.Start());
François Degrosa97ad492019-10-04 12:12:12 +1000371 EXPECT_EQ(process.Wait(), MINIJAIL_ERR_NO_ACCESS);
François Degros56829142019-10-16 22:00:11 +1100372}
373
François Degrosc0b33b12019-09-12 14:50:43 +1000374TEST_P(ProcessRunTest, CapturesInterleavedOutputs) {
375 Process& process = *process_;
376 process.AddArgument("/bin/sh");
377 process.AddArgument("-c");
378 process.AddArgument(R"(
379 printf 'Line 1\nLine ' >&1;
380 printf 'Line 2\nLine' >&2;
381 printf '3\nLine 4\n' >&1;
382 printf ' 5\nLine 6' >&2;
383 )");
384
385 std::vector<std::string> output;
386 EXPECT_EQ(process.Run(&output), 0);
387 EXPECT_THAT(output, UnorderedElementsAre("OUT: Line 1", "OUT: Line 3",
388 "OUT: Line 4", "ERR: Line 2",
389 "ERR: Line 5", "ERR: Line 6"));
390}
391
François Degros56829142019-10-16 22:00:11 +1100392TEST_P(ProcessRunTest, CapturesLotsOfOutputData) {
François Degrosc0b33b12019-09-12 14:50:43 +1000393 Process& process = *process_;
394 process.AddArgument("/bin/sh");
395 process.AddArgument("-c");
396 process.AddArgument(R"(
397 for i in $(seq 1 1000); do
398 printf 'Message %i\n' $i >&1;
399 printf 'Error %i\n' $i >&2;
400 done;
401 )");
402
403 std::vector<std::string> output;
404 EXPECT_EQ(process.Run(&output), 0);
405 EXPECT_THAT(output, SizeIs(2000));
406}
407
François Degros1ef69942019-10-01 15:31:17 +1000408TEST_P(ProcessRunTest, DoesNotBlockWhenNotCapturingOutput) {
François Degros86fb1802019-09-12 14:50:43 +1000409 Process& process = *process_;
410 process.AddArgument("/bin/sh");
411 process.AddArgument("-c");
412
François Degros1ef69942019-10-01 15:31:17 +1000413 // Pipe to monitor the process and wait for it to finish without calling
414 // Process::Wait.
415 SubprocessPipe to_wait(SubprocessPipe::kChildToParent);
416
417 process.AddArgument(base::StringPrintf(R"(
418 printf '%%01000i\n' $(seq 1 100) >&1;
419 printf '%%01000i\n' $(seq 1 100) >&2;
420 printf 'End' >&%d;
François Degros86fb1802019-09-12 14:50:43 +1000421 exit 42;
François Degros1ef69942019-10-01 15:31:17 +1000422 )",
423 to_wait.child_fd.get()));
François Degros86fb1802019-09-12 14:50:43 +1000424
425 // This process generates lots of output on stdout and stderr, ie more than
426 // what a pipe can hold without blocking. If the pipes connected to stdout and
François Degrosedaefc52019-10-03 12:00:20 +1000427 // stderr were not drained, they would fill, the process would stall and
428 // process.Wait() would block forever. If the pipes were closed, the process
429 // would be killed by a SIGPIPE. With drained pipes, the process finishes
430 // normally and its return code should be visible.
431 EXPECT_TRUE(process.Start());
François Degros1ef69942019-10-01 15:31:17 +1000432
433 // The process should finish normally without the parent having to call
434 // Process::Wait() first.
435 to_wait.child_fd.reset();
436 EXPECT_EQ(Read(to_wait.parent_fd.get()), "End");
437 EXPECT_EQ(Read(to_wait.parent_fd.get()), "");
438
François Degrosedaefc52019-10-03 12:00:20 +1000439 EXPECT_EQ(process.Wait(), 42);
François Degros86fb1802019-09-12 14:50:43 +1000440}
441
François Degros56829142019-10-16 22:00:11 +1100442TEST_P(ProcessRunTest, RunDoesNotBlockWhenReadingFromStdIn) {
François Degrosc0b33b12019-09-12 14:50:43 +1000443 Process& process = *process_;
444 process.AddArgument("/bin/cat");
445
446 // By default, /bin/cat reads from stdin. If the pipe connected to stdin was
447 // left open, the process would block indefinitely while reading from it.
François Degrosedaefc52019-10-03 12:00:20 +1000448 std::vector<std::string> output;
449 EXPECT_EQ(process.Run(&output), 0);
450 EXPECT_THAT(output, IsEmpty());
François Degrosc0b33b12019-09-12 14:50:43 +1000451}
452
François Degros1ef69942019-10-01 15:31:17 +1000453TEST_P(ProcessRunTest, WaitDoesNotBlockWhenReadingFromStdIn) {
François Degros56829142019-10-16 22:00:11 +1100454 Process& process = *process_;
455 process.AddArgument("/bin/cat");
456
457 // By default, /bin/cat reads from stdin. If the pipe connected to stdin was
458 // left open, the process would block indefinitely while reading from it.
459 EXPECT_TRUE(process.Start());
460 EXPECT_EQ(process.Wait(), 0);
461}
462
463TEST_P(ProcessRunTest, RunDoesNotWaitForBackgroundProcessToFinish) {
François Degrosc0b33b12019-09-12 14:50:43 +1000464 Process& process = *process_;
465 process.AddArgument("/bin/sh");
466 process.AddArgument("-c");
467
468 // Pipe to unblock the background process and allow it to finish.
François Degrosc2bfe0e2019-10-14 13:08:49 +1100469 SubprocessPipe to_continue(SubprocessPipe::kParentToChild);
François Degros56829142019-10-16 22:00:11 +1100470
François Degrosc0b33b12019-09-12 14:50:43 +1000471 // Pipe to monitor the background process and wait for it to finish.
François Degrosc2bfe0e2019-10-14 13:08:49 +1100472 SubprocessPipe to_wait(SubprocessPipe::kChildToParent);
François Degrosc0b33b12019-09-12 14:50:43 +1000473
474 process.AddArgument(base::StringPrintf(R"(
François Degrosc0b33b12019-09-12 14:50:43 +1000475 (
476 exec 0<&-;
477 exec 1>&-;
478 exec 2>&-;
François Degros56829142019-10-16 22:00:11 +1100479 printf 'Begin\n' >&%d;
François Degrosc0b33b12019-09-12 14:50:43 +1000480 read line <&%d;
François Degros56829142019-10-16 22:00:11 +1100481 printf '%%s and End\n' "$line" >&%d;
François Degrosc0b33b12019-09-12 14:50:43 +1000482 exit 42;
483 )&
484 printf 'Started background process %%i\n' $!
485 exit 5;
486 )",
François Degrosc2bfe0e2019-10-14 13:08:49 +1100487 to_wait.child_fd.get(),
488 to_continue.child_fd.get(),
489 to_wait.child_fd.get()));
François Degrosc0b33b12019-09-12 14:50:43 +1000490
François Degros56829142019-10-16 22:00:11 +1100491 LOG(INFO) << "Running launcher process";
François Degrosc0b33b12019-09-12 14:50:43 +1000492 std::vector<std::string> output;
493 EXPECT_EQ(process.Run(&output), 5);
François Degros56829142019-10-16 22:00:11 +1100494 EXPECT_THAT(output,
495 ElementsAre(StartsWith("OUT: Started background process")));
François Degrosc0b33b12019-09-12 14:50:43 +1000496
François Degros56829142019-10-16 22:00:11 +1100497 LOG(INFO) << "Closing unused fds";
François Degrosc2bfe0e2019-10-14 13:08:49 +1100498 to_continue.child_fd.reset();
499 to_wait.child_fd.reset();
François Degros56829142019-10-16 22:00:11 +1100500
501 LOG(INFO) << "Waiting for background process to confirm starting";
François Degrosc2bfe0e2019-10-14 13:08:49 +1100502 EXPECT_EQ(Read(to_wait.parent_fd.get()), "Begin\n");
François Degros56829142019-10-16 22:00:11 +1100503
François Degrosc0b33b12019-09-12 14:50:43 +1000504 LOG(INFO) << "Unblocking background process";
François Degrosc2bfe0e2019-10-14 13:08:49 +1100505 Write(to_continue.parent_fd.get(), "Continue\n");
François Degrosc0b33b12019-09-12 14:50:43 +1000506
François Degrosc0b33b12019-09-12 14:50:43 +1000507 LOG(INFO) << "Waiting for background process to finish";
François Degrosc2bfe0e2019-10-14 13:08:49 +1100508 EXPECT_EQ(Read(to_wait.parent_fd.get()), "Continue and End\n");
509 EXPECT_EQ(Read(to_wait.parent_fd.get()), "");
François Degros56829142019-10-16 22:00:11 +1100510
511 LOG(INFO) << "Background process finished";
François Degrosc0b33b12019-09-12 14:50:43 +1000512}
513
François Degros56829142019-10-16 22:00:11 +1100514// TODO(crbug.com/1007613) Enable test once bug is fixed.
515TEST_P(ProcessRunTest, DISABLED_WaitDoesNotWaitForBackgroundProcessToFinish) {
516 Process& process = *process_;
517 process.AddArgument("/bin/sh");
518 process.AddArgument("-c");
519
520 // Pipe to unblock the background process and allow it to finish.
François Degrosc2bfe0e2019-10-14 13:08:49 +1100521 SubprocessPipe to_continue(SubprocessPipe::kParentToChild);
François Degros56829142019-10-16 22:00:11 +1100522
523 // Pipe to monitor the background process and wait for it to finish.
François Degrosc2bfe0e2019-10-14 13:08:49 +1100524 SubprocessPipe to_wait(SubprocessPipe::kChildToParent);
François Degros56829142019-10-16 22:00:11 +1100525
526 process.AddArgument(base::StringPrintf(R"(
527 (
528 exec 0<&-;
529 exec 1>&-;
530 exec 2>&-;
531 printf 'Begin\n' >&%d;
532 read line <&%d;
533 printf '%%s and End\n' "$line" >&%d;
534 exit 42;
535 )&
536 exit 5;
537 )",
François Degrosc2bfe0e2019-10-14 13:08:49 +1100538 to_wait.child_fd.get(),
539 to_continue.child_fd.get(),
540 to_wait.child_fd.get()));
François Degros56829142019-10-16 22:00:11 +1100541
542 LOG(INFO) << "Starting launcher process";
543 EXPECT_TRUE(process.Start());
544
545 LOG(INFO) << "Waiting for launcher process to finish";
546 EXPECT_EQ(process.Wait(), 5);
547
548 LOG(INFO) << "Closing unused fds";
François Degrosc2bfe0e2019-10-14 13:08:49 +1100549 to_continue.child_fd.reset();
550 to_wait.child_fd.reset();
François Degros56829142019-10-16 22:00:11 +1100551
552 LOG(INFO) << "Waiting for background process to confirm starting";
François Degrosc2bfe0e2019-10-14 13:08:49 +1100553 EXPECT_EQ(Read(to_wait.parent_fd.get()), "Begin\n");
François Degros56829142019-10-16 22:00:11 +1100554
555 LOG(INFO) << "Unblocking background process";
François Degrosc2bfe0e2019-10-14 13:08:49 +1100556 Write(to_continue.parent_fd.get(), "Continue\n");
François Degros56829142019-10-16 22:00:11 +1100557
558 LOG(INFO) << "Waiting for background process to finish";
François Degrosc2bfe0e2019-10-14 13:08:49 +1100559 EXPECT_EQ(Read(to_wait.parent_fd.get()), "Continue and End\n");
560 EXPECT_EQ(Read(to_wait.parent_fd.get()), "");
François Degros56829142019-10-16 22:00:11 +1100561
562 LOG(INFO) << "Background process finished";
563}
564
565TEST_P(ProcessRunTest, RunUndisturbedBySignals) {
François Degros8c14d382019-09-12 14:50:43 +1000566 Process& process = *process_;
567 process.AddArgument("/bin/sh");
568 process.AddArgument("-c");
569 process.AddArgument(R"(
570 for i in $(seq 1 100); do
571 printf 'Line %0100i\n' $i;
572 sleep 0.01;
573 done;
574 exit 42;
575 )");
576
577 std::vector<std::string> output;
578
579 // Activate an interval timer.
580 const AlarmGuard guard(13 /* milliseconds */);
581 EXPECT_EQ(process.Run(&output), 42);
582 EXPECT_GT(AlarmGuard::count(), 0);
583 // This checks that crbug.com/1005590 is fixed.
584 EXPECT_THAT(output, SizeIs(100));
585}
586
François Degros56829142019-10-16 22:00:11 +1100587TEST_P(ProcessRunTest, WaitUndisturbedBySignals) {
François Degrosc0b33b12019-09-12 14:50:43 +1000588 Process& process = *process_;
589 process.AddArgument("/bin/sh");
590 process.AddArgument("-c");
591 process.AddArgument(R"(
592 sleep 1;
593 exit 42;
594 )");
595
596 // Activate an interval timer.
597 const AlarmGuard guard(13 /* milliseconds */);
598 EXPECT_TRUE(process.Start());
599 EXPECT_EQ(process.Wait(), 42);
600 EXPECT_GT(AlarmGuard::count(), 0);
601}
602
603INSTANTIATE_TEST_SUITE_P(ProcessRun,
604 ProcessRunTest,
605 Values(ProcessFactory{
606 "SandboxedProcess",
607 []() -> std::unique_ptr<Process> {
608 return std::make_unique<SandboxedProcess>();
609 }}),
610 PrintToStringParamName());
611
François Degrosb497e422019-09-20 14:50:08 +1000612// TODO(crbug.com/1023727) Make it work on ARM and ARM64.
613#if defined(__x86_64__)
614INSTANTIATE_TEST_SUITE_P(ProcessRunAsRoot,
615 ProcessRunTest,
616 Values(ProcessFactory{
617 "WithPidNamespace",
618 []() -> std::unique_ptr<Process> {
619 auto process =
620 std::make_unique<SandboxedProcess>();
621 process->NewPidNamespace();
622 // TODO(crbug.com/1008262) Remove this line.
623 process->SkipRemountPrivate();
624 return process;
625 }}),
626 PrintToStringParamName());
627#endif
628
Ben Chan6f391cb2012-03-21 17:38:21 -0700629} // namespace cros_disks