blob: 23e0426b3903d11ff396c8e89b6caed04faa6264 [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
Qijiang Fan713061e2021-03-08 15:45:12 +090016#include <base/check.h>
17#include <base/check_op.h>
Sergei Datsenkocd676b72019-05-10 11:42:05 +100018#include <base/files/file_path.h>
19#include <base/files/file_util.h>
François Degrosc0b33b12019-09-12 14:50:43 +100020#include <base/files/scoped_file.h>
21#include <base/logging.h>
22#include <base/strings/string_piece.h>
23#include <base/strings/stringprintf.h>
24#include <chromeos/libminijail.h>
Sergei Datsenkocd676b72019-05-10 11:42:05 +100025
Ben Chan6f391cb2012-03-21 17:38:21 -070026#include <gmock/gmock.h>
27#include <gtest/gtest.h>
28
François Degros4a76d702019-09-26 14:54:35 +100029#include "cros-disks/sandboxed_init.h"
Sergei Datsenkocd676b72019-05-10 11:42:05 +100030#include "cros-disks/sandboxed_process.h"
31
Ben Chan6f391cb2012-03-21 17:38:21 -070032namespace cros_disks {
François Degrosc0b33b12019-09-12 14:50:43 +100033namespace {
Ben Chan6f391cb2012-03-21 17:38:21 -070034
Sergei Datsenkocd676b72019-05-10 11:42:05 +100035using testing::_;
36using testing::Contains;
Sergei Datsenko9246e9c2019-03-22 10:26:47 +110037using testing::ElementsAre;
François Degrosedaefc52019-10-03 12:00:20 +100038using testing::IsEmpty;
François Degros597bcf42020-08-28 19:34:19 +100039using testing::Not;
François Degrosc0b33b12019-09-12 14:50:43 +100040using testing::PrintToStringParamName;
Sergei Datsenko9246e9c2019-03-22 10:26:47 +110041using testing::Return;
François Degrosc0b33b12019-09-12 14:50:43 +100042using testing::SizeIs;
43using testing::StartsWith;
44using testing::UnorderedElementsAre;
45using testing::Values;
Sergei Datsenko9246e9c2019-03-22 10:26:47 +110046
François Degrosc0b33b12019-09-12 14:50:43 +100047// Sets a signal handler for SIGALRM and an interval timer signaling SIGALRM at
48// regular intervals.
49class AlarmGuard {
50 public:
51 explicit AlarmGuard(const int timer_interval_ms) {
52 CHECK(!old_handler_);
53 count_ = 0;
54 old_handler_ = signal(SIGALRM, &Handler);
55 CHECK_NE(old_handler_, SIG_ERR);
56 SetIntervalTimer(timer_interval_ms * 1000 /* microseconds */);
57 }
Qijiang Fan6bc59e12020-11-11 02:51:06 +090058 AlarmGuard(const AlarmGuard&) = delete;
59 AlarmGuard& operator=(const AlarmGuard&) = delete;
François Degrosc0b33b12019-09-12 14:50:43 +100060
61 ~AlarmGuard() {
62 SetIntervalTimer(0);
63 CHECK_EQ(signal(SIGALRM, old_handler_), &Handler);
64 old_handler_ = nullptr;
65 }
66
67 // Number of times SIGALRM has been received.
68 static int count() { return count_; }
69
70 private:
71 static void Handler(int sig) {
72 CHECK_EQ(sig, SIGALRM);
73 ++count_;
74 }
75
76 static void SetIntervalTimer(const int usec) {
77 const itimerval tv = {{0, usec}, {0, usec}};
78 if (setitimer(ITIMER_REAL, &tv, nullptr) < 0) {
79 PLOG(FATAL) << "Cannot set timer";
80 }
81 }
82
83 // Number of times SIGALRM has been received.
84 static int count_;
85
86 using SigHandler = void (*)(int);
87 static SigHandler old_handler_;
François Degrosc0b33b12019-09-12 14:50:43 +100088};
89
90int AlarmGuard::count_ = 0;
91AlarmGuard::SigHandler AlarmGuard::old_handler_ = nullptr;
92
François Degros56829142019-10-16 22:00:11 +110093std::string Read(const int fd) {
François Degrosc0b33b12019-09-12 14:50:43 +100094 char buffer[PIPE_BUF];
95
François Degros56829142019-10-16 22:00:11 +110096 LOG(INFO) << "Reading up to " << PIPE_BUF << " bytes from fd " << fd << "...";
97 const ssize_t bytes_read = HANDLE_EINTR(read(fd, buffer, PIPE_BUF));
98 PLOG_IF(FATAL, bytes_read < 0) << "Cannot read from fd " << fd;
François Degrosc0b33b12019-09-12 14:50:43 +100099
François Degros56829142019-10-16 22:00:11 +1100100 LOG(INFO) << "Read " << bytes_read << " bytes from fd " << fd;
François Degrosc0b33b12019-09-12 14:50:43 +1000101 return std::string(buffer, bytes_read);
102}
103
François Degros56829142019-10-16 22:00:11 +1100104void Write(const int fd, base::StringPiece s) {
François Degrosc0b33b12019-09-12 14:50:43 +1000105 while (!s.empty()) {
François Degros56829142019-10-16 22:00:11 +1100106 const ssize_t bytes_written = HANDLE_EINTR(write(fd, s.data(), s.size()));
107 PLOG_IF(FATAL, bytes_written < 0) << "Cannot write to fd " << fd;
François Degrosc0b33b12019-09-12 14:50:43 +1000108
109 s.remove_prefix(bytes_written);
110 }
111}
112
113// A mock Process class for testing the Process base class.
Ben Chan6f391cb2012-03-21 17:38:21 -0700114class ProcessUnderTest : public Process {
115 public:
Ben Chan21150af2019-09-11 17:04:07 -0700116 MOCK_METHOD(pid_t,
117 StartImpl,
François Degros1ef69942019-10-01 15:31:17 +1000118 (base::ScopedFD, base::ScopedFD, base::ScopedFD),
Ben Chan21150af2019-09-11 17:04:07 -0700119 (override));
120 MOCK_METHOD(int, WaitImpl, (), (override));
François Degros92bbea42019-09-13 10:42:52 +1000121 MOCK_METHOD(int, WaitNonBlockingImpl, (), (override));
Ben Chan6f391cb2012-03-21 17:38:21 -0700122};
123
François Degrosc0b33b12019-09-12 14:50:43 +1000124struct ProcessFactory {
125 base::StringPiece name;
126 std::unique_ptr<Process> (*make_process)();
127};
128
129std::ostream& operator<<(std::ostream& out, const ProcessFactory& x) {
130 return out << x.name;
131}
132
133} // namespace
134
Ben Chan6f391cb2012-03-21 17:38:21 -0700135class ProcessTest : public ::testing::Test {
136 protected:
137 ProcessUnderTest process_;
138};
139
140TEST_F(ProcessTest, GetArguments) {
François Degros5593b8c2019-07-25 12:27:42 +1000141 const char* const kTestArguments[] = {"/bin/ls", "-l", "", "."};
Ben Chan6057fe62016-12-02 10:08:59 -0800142 for (const char* test_argument : kTestArguments) {
143 process_.AddArgument(test_argument);
Ben Chan6f391cb2012-03-21 17:38:21 -0700144 }
145
Sergei Datsenkocd676b72019-05-10 11:42:05 +1000146 EXPECT_THAT(process_.arguments(), ElementsAre("/bin/ls", "-l", "", "."));
Sergei Datsenko9246e9c2019-03-22 10:26:47 +1100147
François Degros5593b8c2019-07-25 12:27:42 +1000148 char* const* arguments = process_.GetArguments();
Ben Chan44e7ea62014-08-29 18:13:37 -0700149 EXPECT_NE(nullptr, arguments);
Ben Chan6057fe62016-12-02 10:08:59 -0800150 for (const char* test_argument : kTestArguments) {
151 EXPECT_STREQ(test_argument, *arguments);
152 ++arguments;
Ben Chan6f391cb2012-03-21 17:38:21 -0700153 }
Ben Chan6057fe62016-12-02 10:08:59 -0800154 EXPECT_EQ(nullptr, *arguments);
Ben Chan6f391cb2012-03-21 17:38:21 -0700155}
156
157TEST_F(ProcessTest, GetArgumentsWithNoArgumentsAdded) {
François Degros2a4ec242019-10-15 16:28:54 +1100158 char* const* arguments = process_.GetArguments();
159 EXPECT_NE(nullptr, arguments);
160 EXPECT_EQ(nullptr, *arguments);
Ben Chan6f391cb2012-03-21 17:38:21 -0700161}
162
Sergei Datsenko9246e9c2019-03-22 10:26:47 +1100163TEST_F(ProcessTest, Run_Success) {
Sergei Datsenkocd676b72019-05-10 11:42:05 +1000164 process_.AddArgument("foo");
François Degros5593b8c2019-07-25 12:27:42 +1000165 EXPECT_CALL(process_, StartImpl(_, _, _)).WillOnce(Return(123));
François Degrosedaefc52019-10-03 12:00:20 +1000166 EXPECT_CALL(process_, WaitImpl()).Times(0);
167 EXPECT_CALL(process_, WaitNonBlockingImpl()).WillOnce(Return(42));
168 std::vector<std::string> output;
169 EXPECT_EQ(process_.Run(&output), 42);
170 EXPECT_THAT(output, IsEmpty());
Sergei Datsenko9246e9c2019-03-22 10:26:47 +1100171}
172
173TEST_F(ProcessTest, Run_Fail) {
Sergei Datsenkocd676b72019-05-10 11:42:05 +1000174 process_.AddArgument("foo");
François Degros5593b8c2019-07-25 12:27:42 +1000175 EXPECT_CALL(process_, StartImpl(_, _, _)).WillOnce(Return(-1));
Sergei Datsenkocd676b72019-05-10 11:42:05 +1000176 EXPECT_CALL(process_, WaitImpl()).Times(0);
François Degros92bbea42019-09-13 10:42:52 +1000177 EXPECT_CALL(process_, WaitNonBlockingImpl()).Times(0);
François Degrosedaefc52019-10-03 12:00:20 +1000178 std::vector<std::string> output;
179 EXPECT_EQ(process_.Run(&output), -1);
180 EXPECT_THAT(output, IsEmpty());
Sergei Datsenko9246e9c2019-03-22 10:26:47 +1100181}
182
François Degrosc0b33b12019-09-12 14:50:43 +1000183class ProcessRunTest : public ::testing::TestWithParam<ProcessFactory> {
184 public:
185 ProcessRunTest() {
186 // Ensure that we get an error message if Minijail crashes.
187 // TODO(crbug.com/1007098) Remove the following line or this comment
188 // depending on how this bug is resolved.
189 minijail_log_to_fd(STDERR_FILENO, 0);
190 }
Sergei Datsenkocd676b72019-05-10 11:42:05 +1000191
François Degrosc0b33b12019-09-12 14:50:43 +1000192 const std::unique_ptr<Process> process_ = GetParam().make_process();
193};
Sergei Datsenkocd676b72019-05-10 11:42:05 +1000194
François Degros56829142019-10-16 22:00:11 +1100195TEST_P(ProcessRunTest, RunReturnsZero) {
François Degrosc0b33b12019-09-12 14:50:43 +1000196 Process& process = *process_;
François Degros56829142019-10-16 22:00:11 +1100197 process.AddArgument("/bin/sh");
198 process.AddArgument("-c");
199 process.AddArgument("exit 0");
François Degrosedaefc52019-10-03 12:00:20 +1000200 std::vector<std::string> output;
201 EXPECT_EQ(process.Run(&output), 0);
202 EXPECT_THAT(output, IsEmpty());
Sergei Datsenkocd676b72019-05-10 11:42:05 +1000203}
204
François Degros56829142019-10-16 22:00:11 +1100205TEST_P(ProcessRunTest, WaitReturnsZero) {
François Degrosc0b33b12019-09-12 14:50:43 +1000206 Process& process = *process_;
François Degros56829142019-10-16 22:00:11 +1100207 process.AddArgument("/bin/sh");
208 process.AddArgument("-c");
209 process.AddArgument("exit 0");
210 EXPECT_TRUE(process.Start());
211 EXPECT_EQ(process.Wait(), 0);
212}
213
214TEST_P(ProcessRunTest, RunReturnsNonZero) {
215 Process& process = *process_;
216 process.AddArgument("/bin/sh");
217 process.AddArgument("-c");
218 process.AddArgument("exit 42");
François Degrosedaefc52019-10-03 12:00:20 +1000219 std::vector<std::string> output;
François Degros56829142019-10-16 22:00:11 +1100220 EXPECT_EQ(process.Run(&output), 42);
François Degrosedaefc52019-10-03 12:00:20 +1000221 EXPECT_THAT(output, IsEmpty());
François Degrosc0b33b12019-09-12 14:50:43 +1000222}
223
François Degros56829142019-10-16 22:00:11 +1100224TEST_P(ProcessRunTest, WaitReturnsNonZero) {
225 Process& process = *process_;
226 process.AddArgument("/bin/sh");
227 process.AddArgument("-c");
228 process.AddArgument("exit 42");
229 EXPECT_TRUE(process.Start());
230 EXPECT_EQ(process.Wait(), 42);
231}
232
233TEST_P(ProcessRunTest, RunKilledBySigKill) {
François Degrosc0b33b12019-09-12 14:50:43 +1000234 Process& process = *process_;
235 process.AddArgument("/bin/sh");
236 process.AddArgument("-c");
237 process.AddArgument("kill -KILL $$; sleep 1000");
François Degrosedaefc52019-10-03 12:00:20 +1000238 std::vector<std::string> output;
François Degros56829142019-10-16 22:00:11 +1100239 EXPECT_EQ(process.Run(&output), MINIJAIL_ERR_SIG_BASE + SIGKILL);
François Degrosedaefc52019-10-03 12:00:20 +1000240 EXPECT_THAT(output, IsEmpty());
François Degrosc0b33b12019-09-12 14:50:43 +1000241}
242
François Degros56829142019-10-16 22:00:11 +1100243TEST_P(ProcessRunTest, WaitKilledBySigKill) {
244 Process& process = *process_;
245 process.AddArgument("/bin/sh");
246 process.AddArgument("-c");
247 process.AddArgument("kill -KILL $$; sleep 1000");
248 EXPECT_TRUE(process.Start());
249 EXPECT_EQ(process.Wait(), MINIJAIL_ERR_SIG_BASE + SIGKILL);
250}
251
252TEST_P(ProcessRunTest, RunKilledBySigSys) {
François Degrosc0b33b12019-09-12 14:50:43 +1000253 Process& process = *process_;
254 process.AddArgument("/bin/sh");
255 process.AddArgument("-c");
256 process.AddArgument("kill -SYS $$; sleep 1000");
François Degrosedaefc52019-10-03 12:00:20 +1000257 std::vector<std::string> output;
258 EXPECT_EQ(process.Run(&output), MINIJAIL_ERR_JAIL);
259 EXPECT_THAT(output, IsEmpty());
François Degrosc0b33b12019-09-12 14:50:43 +1000260}
261
François Degros56829142019-10-16 22:00:11 +1100262TEST_P(ProcessRunTest, WaitKilledBySigSys) {
François Degrosc0b33b12019-09-12 14:50:43 +1000263 Process& process = *process_;
François Degros56829142019-10-16 22:00:11 +1100264 process.AddArgument("/bin/sh");
265 process.AddArgument("-c");
266 process.AddArgument("kill -SYS $$; sleep 1000");
267 EXPECT_TRUE(process.Start());
268 EXPECT_EQ(process.Wait(), MINIJAIL_ERR_JAIL);
269}
270
François Degros21bc9bb2020-04-18 00:14:43 +1000271TEST_P(ProcessRunTest, ExternallyKilledBySigKill) {
272 Process& process = *process_;
273 process.AddArgument("/bin/sh");
274 process.AddArgument("-c");
275
276 // Pipe to block the child process.
277 SubprocessPipe to_block(SubprocessPipe::kParentToChild);
278
279 // Pipe to monitor the child process.
280 SubprocessPipe to_wait(SubprocessPipe::kChildToParent);
281
282 process.AddArgument(base::StringPrintf(
283 R"(
284 printf 'Begin\n' >&%d;
285 read line <&%d;
286 printf '%%s and End\n' "$line" >&%d;
287 exit 42;
288 )",
289 to_wait.child_fd.get(), to_block.child_fd.get(), to_wait.child_fd.get()));
290
291 EXPECT_TRUE(process.Start());
292
293 // Close unused pipe ends.
294 to_block.child_fd.reset();
295 to_wait.child_fd.reset();
296
297 // Wait for child process to start.
298 EXPECT_EQ(Read(to_wait.parent_fd.get()), "Begin\n");
299
300 // Send SIGKILL to child process.
301 const pid_t pid = process.pid();
302 LOG(INFO) << "Sending signal to PID " << pid;
303 EXPECT_EQ(kill(pid, SIGKILL), 0);
304
305 // Wait for child process to finish.
306 EXPECT_EQ(Read(to_wait.parent_fd.get()), "");
307 EXPECT_EQ(process.Wait(), MINIJAIL_ERR_SIG_BASE + SIGKILL);
308}
309
310TEST_P(ProcessRunTest, ExternallyKilledBySigTerm) {
311 Process& process = *process_;
312 process.AddArgument("/bin/sh");
313 process.AddArgument("-c");
314
315 // Pipe to block the child process.
316 SubprocessPipe to_block(SubprocessPipe::kParentToChild);
317
318 // Pipe to monitor the child process.
319 SubprocessPipe to_wait(SubprocessPipe::kChildToParent);
320
321 process.AddArgument(base::StringPrintf(
322 R"(
323 printf 'Begin\n' >&%d;
324 read line <&%d;
325 printf '%%s and End\n' "$line" >&%d;
326 exit 42;
327 )",
328 to_wait.child_fd.get(), to_block.child_fd.get(), to_wait.child_fd.get()));
329
330 EXPECT_TRUE(process.Start());
331
332 // Close unused pipe ends.
333 to_block.child_fd.reset();
334 to_wait.child_fd.reset();
335
336 // Wait for child process to start.
337 EXPECT_EQ(Read(to_wait.parent_fd.get()), "Begin\n");
338
339 // Send SIGTERM to child process.
340 const pid_t pid = process.pid();
341 LOG(INFO) << "Sending signal to PID " << pid;
342 EXPECT_EQ(kill(pid, SIGTERM), 0);
343
344 // Wait for child process to finish.
345 EXPECT_EQ(Read(to_wait.parent_fd.get()), "");
346 EXPECT_EQ(process.Wait(), MINIJAIL_ERR_SIG_BASE + SIGTERM);
347}
348
François Degros56829142019-10-16 22:00:11 +1100349TEST_P(ProcessRunTest, RunCannotFindCommand) {
350 Process& process = *process_;
351 process.AddArgument("non existing command");
François Degrosedaefc52019-10-03 12:00:20 +1000352 std::vector<std::string> output;
François Degrosa97ad492019-10-04 12:12:12 +1000353 EXPECT_EQ(process.Run(&output), MINIJAIL_ERR_NO_COMMAND);
François Degrosc0b33b12019-09-12 14:50:43 +1000354}
355
François Degros56829142019-10-16 22:00:11 +1100356TEST_P(ProcessRunTest, WaitCannotFindCommand) {
357 Process& process = *process_;
358 process.AddArgument("non existing command");
359 EXPECT_TRUE(process.Start());
François Degrosa97ad492019-10-04 12:12:12 +1000360 EXPECT_EQ(process.Wait(), MINIJAIL_ERR_NO_COMMAND);
François Degros56829142019-10-16 22:00:11 +1100361}
362
363TEST_P(ProcessRunTest, RunCannotRunCommand) {
364 Process& process = *process_;
365 process.AddArgument("/dev/null");
366 std::vector<std::string> output;
François Degrosa97ad492019-10-04 12:12:12 +1000367 EXPECT_EQ(process.Run(&output), MINIJAIL_ERR_NO_ACCESS);
François Degros56829142019-10-16 22:00:11 +1100368}
369
370TEST_P(ProcessRunTest, WaitCannotRunCommand) {
371 Process& process = *process_;
372 process.AddArgument("/dev/null");
373 EXPECT_TRUE(process.Start());
François Degrosa97ad492019-10-04 12:12:12 +1000374 EXPECT_EQ(process.Wait(), MINIJAIL_ERR_NO_ACCESS);
François Degros56829142019-10-16 22:00:11 +1100375}
376
François Degrosc0b33b12019-09-12 14:50:43 +1000377TEST_P(ProcessRunTest, CapturesInterleavedOutputs) {
378 Process& process = *process_;
379 process.AddArgument("/bin/sh");
380 process.AddArgument("-c");
381 process.AddArgument(R"(
382 printf 'Line 1\nLine ' >&1;
383 printf 'Line 2\nLine' >&2;
384 printf '3\nLine 4\n' >&1;
385 printf ' 5\nLine 6' >&2;
386 )");
387
388 std::vector<std::string> output;
389 EXPECT_EQ(process.Run(&output), 0);
390 EXPECT_THAT(output, UnorderedElementsAre("OUT: Line 1", "OUT: Line 3",
391 "OUT: Line 4", "ERR: Line 2",
392 "ERR: Line 5", "ERR: Line 6"));
393}
394
François Degros56829142019-10-16 22:00:11 +1100395TEST_P(ProcessRunTest, CapturesLotsOfOutputData) {
François Degrosc0b33b12019-09-12 14:50:43 +1000396 Process& process = *process_;
397 process.AddArgument("/bin/sh");
398 process.AddArgument("-c");
399 process.AddArgument(R"(
400 for i in $(seq 1 1000); do
401 printf 'Message %i\n' $i >&1;
402 printf 'Error %i\n' $i >&2;
403 done;
404 )");
405
406 std::vector<std::string> output;
407 EXPECT_EQ(process.Run(&output), 0);
408 EXPECT_THAT(output, SizeIs(2000));
409}
410
François Degros1ef69942019-10-01 15:31:17 +1000411TEST_P(ProcessRunTest, DoesNotBlockWhenNotCapturingOutput) {
François Degros86fb1802019-09-12 14:50:43 +1000412 Process& process = *process_;
413 process.AddArgument("/bin/sh");
414 process.AddArgument("-c");
415
François Degros1ef69942019-10-01 15:31:17 +1000416 // Pipe to monitor the process and wait for it to finish without calling
417 // Process::Wait.
418 SubprocessPipe to_wait(SubprocessPipe::kChildToParent);
419
420 process.AddArgument(base::StringPrintf(R"(
421 printf '%%01000i\n' $(seq 1 100) >&1;
422 printf '%%01000i\n' $(seq 1 100) >&2;
423 printf 'End' >&%d;
François Degros86fb1802019-09-12 14:50:43 +1000424 exit 42;
François Degros1ef69942019-10-01 15:31:17 +1000425 )",
426 to_wait.child_fd.get()));
François Degros86fb1802019-09-12 14:50:43 +1000427
428 // This process generates lots of output on stdout and stderr, ie more than
429 // what a pipe can hold without blocking. If the pipes connected to stdout and
François Degrosedaefc52019-10-03 12:00:20 +1000430 // stderr were not drained, they would fill, the process would stall and
431 // process.Wait() would block forever. If the pipes were closed, the process
432 // would be killed by a SIGPIPE. With drained pipes, the process finishes
433 // normally and its return code should be visible.
434 EXPECT_TRUE(process.Start());
François Degros1ef69942019-10-01 15:31:17 +1000435
436 // The process should finish normally without the parent having to call
437 // Process::Wait() first.
438 to_wait.child_fd.reset();
439 EXPECT_EQ(Read(to_wait.parent_fd.get()), "End");
440 EXPECT_EQ(Read(to_wait.parent_fd.get()), "");
441
François Degrosedaefc52019-10-03 12:00:20 +1000442 EXPECT_EQ(process.Wait(), 42);
François Degros86fb1802019-09-12 14:50:43 +1000443}
444
François Degros56829142019-10-16 22:00:11 +1100445TEST_P(ProcessRunTest, RunDoesNotBlockWhenReadingFromStdIn) {
François Degrosc0b33b12019-09-12 14:50:43 +1000446 Process& process = *process_;
447 process.AddArgument("/bin/cat");
448
François Degrosedaefc52019-10-03 12:00:20 +1000449 std::vector<std::string> output;
450 EXPECT_EQ(process.Run(&output), 0);
451 EXPECT_THAT(output, IsEmpty());
François Degrosc0b33b12019-09-12 14:50:43 +1000452}
453
François Degros597bcf42020-08-28 19:34:19 +1000454TEST_P(ProcessRunTest, ReadsFromStdIn) {
455 Process& process = *process_;
456 process.AddArgument("/bin/cat");
457
458 EXPECT_EQ(process.input(), "");
459 const std::string input = "Line 1\nLine 2\nLine 3";
460 process.SetStdIn(input);
461 EXPECT_EQ(process.input(), input);
462
463 std::vector<std::string> output;
464 EXPECT_EQ(process.Run(&output), 0);
465 EXPECT_THAT(output, ElementsAre("OUT: Line 1", "OUT: Line 2", "OUT: Line 3"));
466}
467
468TEST_P(ProcessRunTest, ReadsLotsFromStdIn) {
469 Process& process = *process_;
470 process.AddArgument("/bin/wc");
471 process.AddArgument("-c");
472
473 // 4KB of data should be passed without error nor truncation.
474 process.SetStdIn(std::string(4096, 'x'));
475 EXPECT_THAT(process.input(), SizeIs(4096));
476
477 std::vector<std::string> output;
478 EXPECT_EQ(process.Run(&output), 0);
479 EXPECT_THAT(output, ElementsAre("OUT: 4096"));
480}
481
482TEST_P(ProcessRunTest, TruncatesDataFromStdIn) {
483 Process& process = *process_;
484 process.AddArgument("/bin/wc");
485 process.AddArgument("-c");
486
487 // 100KB of data should be truncated.
488 process.SetStdIn(std::string(100'000, 'x'));
489
490 std::vector<std::string> output;
491 EXPECT_EQ(process.Run(&output), 0);
492 EXPECT_THAT(output, ElementsAre(Not("OUT: 100000")));
493}
494
François Degros1ef69942019-10-01 15:31:17 +1000495TEST_P(ProcessRunTest, WaitDoesNotBlockWhenReadingFromStdIn) {
François Degros56829142019-10-16 22:00:11 +1100496 Process& process = *process_;
497 process.AddArgument("/bin/cat");
François Degros597bcf42020-08-28 19:34:19 +1000498 process.SetStdIn(std::string(100'000, 'x'));
François Degros56829142019-10-16 22:00:11 +1100499
500 // By default, /bin/cat reads from stdin. If the pipe connected to stdin was
501 // left open, the process would block indefinitely while reading from it.
502 EXPECT_TRUE(process.Start());
503 EXPECT_EQ(process.Wait(), 0);
504}
505
506TEST_P(ProcessRunTest, RunDoesNotWaitForBackgroundProcessToFinish) {
François Degrosc0b33b12019-09-12 14:50:43 +1000507 Process& process = *process_;
508 process.AddArgument("/bin/sh");
509 process.AddArgument("-c");
510
511 // Pipe to unblock the background process and allow it to finish.
François Degrosc2bfe0e2019-10-14 13:08:49 +1100512 SubprocessPipe to_continue(SubprocessPipe::kParentToChild);
François Degros56829142019-10-16 22:00:11 +1100513
François Degrosc0b33b12019-09-12 14:50:43 +1000514 // Pipe to monitor the background process and wait for it to finish.
François Degrosc2bfe0e2019-10-14 13:08:49 +1100515 SubprocessPipe to_wait(SubprocessPipe::kChildToParent);
François Degrosc0b33b12019-09-12 14:50:43 +1000516
517 process.AddArgument(base::StringPrintf(R"(
François Degrosc0b33b12019-09-12 14:50:43 +1000518 (
519 exec 0<&-;
520 exec 1>&-;
521 exec 2>&-;
François Degros56829142019-10-16 22:00:11 +1100522 printf 'Begin\n' >&%d;
François Degrosc0b33b12019-09-12 14:50:43 +1000523 read line <&%d;
François Degros56829142019-10-16 22:00:11 +1100524 printf '%%s and End\n' "$line" >&%d;
François Degrosc0b33b12019-09-12 14:50:43 +1000525 exit 42;
526 )&
527 printf 'Started background process %%i\n' $!
528 exit 5;
529 )",
François Degrosc2bfe0e2019-10-14 13:08:49 +1100530 to_wait.child_fd.get(),
531 to_continue.child_fd.get(),
532 to_wait.child_fd.get()));
François Degrosc0b33b12019-09-12 14:50:43 +1000533
François Degros56829142019-10-16 22:00:11 +1100534 LOG(INFO) << "Running launcher process";
François Degrosc0b33b12019-09-12 14:50:43 +1000535 std::vector<std::string> output;
536 EXPECT_EQ(process.Run(&output), 5);
François Degros56829142019-10-16 22:00:11 +1100537 EXPECT_THAT(output,
538 ElementsAre(StartsWith("OUT: Started background process")));
François Degrosc0b33b12019-09-12 14:50:43 +1000539
François Degros56829142019-10-16 22:00:11 +1100540 LOG(INFO) << "Closing unused fds";
François Degrosc2bfe0e2019-10-14 13:08:49 +1100541 to_continue.child_fd.reset();
542 to_wait.child_fd.reset();
François Degros56829142019-10-16 22:00:11 +1100543
544 LOG(INFO) << "Waiting for background process to confirm starting";
François Degrosc2bfe0e2019-10-14 13:08:49 +1100545 EXPECT_EQ(Read(to_wait.parent_fd.get()), "Begin\n");
François Degros56829142019-10-16 22:00:11 +1100546
François Degrosc0b33b12019-09-12 14:50:43 +1000547 LOG(INFO) << "Unblocking background process";
François Degrosc2bfe0e2019-10-14 13:08:49 +1100548 Write(to_continue.parent_fd.get(), "Continue\n");
François Degrosc0b33b12019-09-12 14:50:43 +1000549
François Degrosc0b33b12019-09-12 14:50:43 +1000550 LOG(INFO) << "Waiting for background process to finish";
François Degrosc2bfe0e2019-10-14 13:08:49 +1100551 EXPECT_EQ(Read(to_wait.parent_fd.get()), "Continue and End\n");
552 EXPECT_EQ(Read(to_wait.parent_fd.get()), "");
François Degros56829142019-10-16 22:00:11 +1100553
554 LOG(INFO) << "Background process finished";
François Degrosc0b33b12019-09-12 14:50:43 +1000555}
556
François Degros56829142019-10-16 22:00:11 +1100557// TODO(crbug.com/1007613) Enable test once bug is fixed.
558TEST_P(ProcessRunTest, DISABLED_WaitDoesNotWaitForBackgroundProcessToFinish) {
559 Process& process = *process_;
560 process.AddArgument("/bin/sh");
561 process.AddArgument("-c");
562
563 // Pipe to unblock the background process and allow it to finish.
François Degrosc2bfe0e2019-10-14 13:08:49 +1100564 SubprocessPipe to_continue(SubprocessPipe::kParentToChild);
François Degros56829142019-10-16 22:00:11 +1100565
566 // Pipe to monitor the background process and wait for it to finish.
François Degrosc2bfe0e2019-10-14 13:08:49 +1100567 SubprocessPipe to_wait(SubprocessPipe::kChildToParent);
François Degros56829142019-10-16 22:00:11 +1100568
569 process.AddArgument(base::StringPrintf(R"(
570 (
571 exec 0<&-;
572 exec 1>&-;
573 exec 2>&-;
574 printf 'Begin\n' >&%d;
575 read line <&%d;
576 printf '%%s and End\n' "$line" >&%d;
577 exit 42;
578 )&
579 exit 5;
580 )",
François Degrosc2bfe0e2019-10-14 13:08:49 +1100581 to_wait.child_fd.get(),
582 to_continue.child_fd.get(),
583 to_wait.child_fd.get()));
François Degros56829142019-10-16 22:00:11 +1100584
585 LOG(INFO) << "Starting launcher process";
586 EXPECT_TRUE(process.Start());
587
588 LOG(INFO) << "Waiting for launcher process to finish";
589 EXPECT_EQ(process.Wait(), 5);
590
591 LOG(INFO) << "Closing unused fds";
François Degrosc2bfe0e2019-10-14 13:08:49 +1100592 to_continue.child_fd.reset();
593 to_wait.child_fd.reset();
François Degros56829142019-10-16 22:00:11 +1100594
595 LOG(INFO) << "Waiting for background process to confirm starting";
François Degrosc2bfe0e2019-10-14 13:08:49 +1100596 EXPECT_EQ(Read(to_wait.parent_fd.get()), "Begin\n");
François Degros56829142019-10-16 22:00:11 +1100597
598 LOG(INFO) << "Unblocking background process";
François Degrosc2bfe0e2019-10-14 13:08:49 +1100599 Write(to_continue.parent_fd.get(), "Continue\n");
François Degros56829142019-10-16 22:00:11 +1100600
601 LOG(INFO) << "Waiting for background process to finish";
François Degrosc2bfe0e2019-10-14 13:08:49 +1100602 EXPECT_EQ(Read(to_wait.parent_fd.get()), "Continue and End\n");
603 EXPECT_EQ(Read(to_wait.parent_fd.get()), "");
François Degros56829142019-10-16 22:00:11 +1100604
605 LOG(INFO) << "Background process finished";
606}
607
608TEST_P(ProcessRunTest, RunUndisturbedBySignals) {
François Degros8c14d382019-09-12 14:50:43 +1000609 Process& process = *process_;
610 process.AddArgument("/bin/sh");
611 process.AddArgument("-c");
612 process.AddArgument(R"(
613 for i in $(seq 1 100); do
614 printf 'Line %0100i\n' $i;
615 sleep 0.01;
616 done;
617 exit 42;
618 )");
619
620 std::vector<std::string> output;
621
622 // Activate an interval timer.
623 const AlarmGuard guard(13 /* milliseconds */);
624 EXPECT_EQ(process.Run(&output), 42);
625 EXPECT_GT(AlarmGuard::count(), 0);
626 // This checks that crbug.com/1005590 is fixed.
627 EXPECT_THAT(output, SizeIs(100));
628}
629
François Degros56829142019-10-16 22:00:11 +1100630TEST_P(ProcessRunTest, WaitUndisturbedBySignals) {
François Degrosc0b33b12019-09-12 14:50:43 +1000631 Process& process = *process_;
632 process.AddArgument("/bin/sh");
633 process.AddArgument("-c");
634 process.AddArgument(R"(
635 sleep 1;
636 exit 42;
637 )");
638
639 // Activate an interval timer.
640 const AlarmGuard guard(13 /* milliseconds */);
641 EXPECT_TRUE(process.Start());
642 EXPECT_EQ(process.Wait(), 42);
643 EXPECT_GT(AlarmGuard::count(), 0);
644}
645
François Degrosee318212020-07-14 14:11:42 +1000646TEST_P(ProcessRunTest, PassCurrentEnvironment) {
647 EXPECT_EQ(setenv("OLD_VAR_1", "Old 1", 0), 0);
648 EXPECT_EQ(setenv("OLD_VAR_2", "Old 2", 0), 0);
649 Process& process = *process_;
650 process.AddArgument("/bin/sh");
651 process.AddArgument("-c");
652 process.AddArgument("set");
653
654 std::vector<std::string> output;
655 EXPECT_EQ(process.Run(&output), 0);
656 EXPECT_THAT(output, Contains("OUT: OLD_VAR_1='Old 1'"));
657 EXPECT_THAT(output, Contains("OUT: OLD_VAR_2='Old 2'"));
658 EXPECT_EQ(unsetenv("OLD_VAR_1"), 0);
659 EXPECT_EQ(unsetenv("OLD_VAR_2"), 0);
660}
661
662TEST_P(ProcessRunTest, AppendExtraEnvironment) {
663 EXPECT_EQ(setenv("OLD_VAR_1", "Old 1", 0), 0);
664 EXPECT_EQ(setenv("OLD_VAR_2", "Old 2", 0), 0);
665 Process& process = *process_;
666 EXPECT_THAT(process.environment(), IsEmpty());
667 process.AddEnvironmentVariable("MY_VAR_1", "");
668 process.AddEnvironmentVariable("MY_VAR_2", " ");
669 process.AddEnvironmentVariable("MY_VAR_3", "=");
670 process.AddEnvironmentVariable("MY_VAR_4",
671 R"(abc 123 ~`!@#$%^&*()_-+={[}]|\:;"'<,>.?/)");
672 EXPECT_THAT(
673 process.environment(),
674 ElementsAre("MY_VAR_1=", "MY_VAR_2= ", "MY_VAR_3==",
675 R"(MY_VAR_4=abc 123 ~`!@#$%^&*()_-+={[}]|\:;"'<,>.?/)"));
676 process.AddArgument("/bin/sh");
677 process.AddArgument("-c");
678 process.AddArgument("set");
679
680 std::vector<std::string> output;
681 EXPECT_EQ(process.Run(&output), 0);
682 EXPECT_THAT(output, Contains("OUT: OLD_VAR_1='Old 1'"));
683 EXPECT_THAT(output, Contains("OUT: OLD_VAR_2='Old 2'"));
684 EXPECT_THAT(output, Contains("OUT: MY_VAR_1=''"));
685 EXPECT_THAT(output, Contains("OUT: MY_VAR_2=' '"));
686 EXPECT_THAT(output, Contains("OUT: MY_VAR_3='='"));
687 EXPECT_THAT(
688 output,
689 Contains(
690 R"(OUT: MY_VAR_4='abc 123 ~`!@#$%^&*()_-+={[}]|\:;"'"'"'<,>.?/')"));
691 EXPECT_EQ(unsetenv("OLD_VAR_1"), 0);
692 EXPECT_EQ(unsetenv("OLD_VAR_2"), 0);
693}
694
François Degrosc0b33b12019-09-12 14:50:43 +1000695INSTANTIATE_TEST_SUITE_P(ProcessRun,
696 ProcessRunTest,
697 Values(ProcessFactory{
698 "SandboxedProcess",
699 []() -> std::unique_ptr<Process> {
700 return std::make_unique<SandboxedProcess>();
701 }}),
702 PrintToStringParamName());
703
François Degrosb497e422019-09-20 14:50:08 +1000704// TODO(crbug.com/1023727) Make it work on ARM and ARM64.
705#if defined(__x86_64__)
706INSTANTIATE_TEST_SUITE_P(ProcessRunAsRoot,
707 ProcessRunTest,
708 Values(ProcessFactory{
709 "WithPidNamespace",
710 []() -> std::unique_ptr<Process> {
711 auto process =
712 std::make_unique<SandboxedProcess>();
713 process->NewPidNamespace();
714 // TODO(crbug.com/1008262) Remove this line.
715 process->SkipRemountPrivate();
716 return process;
717 }}),
718 PrintToStringParamName());
719#endif
720
Ben Chan6f391cb2012-03-21 17:38:21 -0700721} // namespace cros_disks