1*1a96fba6SXin Li // Copyright 2015 The Chromium OS Authors. All rights reserved.
2*1a96fba6SXin Li // Use of this source code is governed by a BSD-style license that can be
3*1a96fba6SXin Li // found in the LICENSE file.
4*1a96fba6SXin Li
5*1a96fba6SXin Li #include <brillo/process_reaper.h>
6*1a96fba6SXin Li
7*1a96fba6SXin Li #include <signal.h>
8*1a96fba6SXin Li #include <sys/wait.h>
9*1a96fba6SXin Li #include <unistd.h>
10*1a96fba6SXin Li
11*1a96fba6SXin Li #include <base/bind.h>
12*1a96fba6SXin Li #include <base/location.h>
13*1a96fba6SXin Li #include <base/message_loop/message_loop.h>
14*1a96fba6SXin Li #include <brillo/asynchronous_signal_handler.h>
15*1a96fba6SXin Li #include <brillo/message_loops/base_message_loop.h>
16*1a96fba6SXin Li #include <gtest/gtest.h>
17*1a96fba6SXin Li
18*1a96fba6SXin Li namespace {
19*1a96fba6SXin Li
ForkChildAndExit(int exit_code)20*1a96fba6SXin Li pid_t ForkChildAndExit(int exit_code) {
21*1a96fba6SXin Li pid_t pid = fork();
22*1a96fba6SXin Li PCHECK(pid != -1);
23*1a96fba6SXin Li if (pid == 0) {
24*1a96fba6SXin Li _exit(exit_code);
25*1a96fba6SXin Li }
26*1a96fba6SXin Li return pid;
27*1a96fba6SXin Li }
28*1a96fba6SXin Li
ForkChildAndKill(int sig)29*1a96fba6SXin Li pid_t ForkChildAndKill(int sig) {
30*1a96fba6SXin Li pid_t pid = fork();
31*1a96fba6SXin Li PCHECK(pid != -1);
32*1a96fba6SXin Li if (pid == 0) {
33*1a96fba6SXin Li if (raise(sig) != 0) {
34*1a96fba6SXin Li PLOG(ERROR) << "raise(" << sig << ")";
35*1a96fba6SXin Li }
36*1a96fba6SXin Li _exit(0); // Not reached. This value will cause the test to fail.
37*1a96fba6SXin Li }
38*1a96fba6SXin Li return pid;
39*1a96fba6SXin Li }
40*1a96fba6SXin Li
41*1a96fba6SXin Li } // namespace
42*1a96fba6SXin Li
43*1a96fba6SXin Li namespace brillo {
44*1a96fba6SXin Li
45*1a96fba6SXin Li class ProcessReaperTest : public ::testing::Test {
46*1a96fba6SXin Li public:
SetUp()47*1a96fba6SXin Li void SetUp() override {
48*1a96fba6SXin Li brillo_loop_.SetAsCurrent();
49*1a96fba6SXin Li async_signal_handler_.Init();
50*1a96fba6SXin Li process_reaper_.Register(&async_signal_handler_);
51*1a96fba6SXin Li }
52*1a96fba6SXin Li
53*1a96fba6SXin Li protected:
54*1a96fba6SXin Li base::MessageLoopForIO base_loop_;
55*1a96fba6SXin Li brillo::BaseMessageLoop brillo_loop_{&base_loop_};
56*1a96fba6SXin Li brillo::AsynchronousSignalHandler async_signal_handler_;
57*1a96fba6SXin Li
58*1a96fba6SXin Li // ProcessReaper under test.
59*1a96fba6SXin Li ProcessReaper process_reaper_;
60*1a96fba6SXin Li };
61*1a96fba6SXin Li
TEST_F(ProcessReaperTest,UnregisterWhenNotRegistered)62*1a96fba6SXin Li TEST_F(ProcessReaperTest, UnregisterWhenNotRegistered) {
63*1a96fba6SXin Li ProcessReaper another_process_reaper_;
64*1a96fba6SXin Li another_process_reaper_.Unregister();
65*1a96fba6SXin Li }
66*1a96fba6SXin Li
TEST_F(ProcessReaperTest,UnregisterAndReregister)67*1a96fba6SXin Li TEST_F(ProcessReaperTest, UnregisterAndReregister) {
68*1a96fba6SXin Li process_reaper_.Unregister();
69*1a96fba6SXin Li process_reaper_.Register(&async_signal_handler_);
70*1a96fba6SXin Li // This checks that we can unregister the ProcessReaper and then destroy it.
71*1a96fba6SXin Li process_reaper_.Unregister();
72*1a96fba6SXin Li }
73*1a96fba6SXin Li
TEST_F(ProcessReaperTest,ReapExitedChild)74*1a96fba6SXin Li TEST_F(ProcessReaperTest, ReapExitedChild) {
75*1a96fba6SXin Li pid_t pid = ForkChildAndExit(123);
76*1a96fba6SXin Li EXPECT_TRUE(process_reaper_.WatchForChild(FROM_HERE, pid, base::BindOnce(
77*1a96fba6SXin Li [](MessageLoop* loop, const siginfo_t& info) {
78*1a96fba6SXin Li EXPECT_EQ(CLD_EXITED, info.si_code);
79*1a96fba6SXin Li EXPECT_EQ(123, info.si_status);
80*1a96fba6SXin Li loop->BreakLoop();
81*1a96fba6SXin Li }, &brillo_loop_)));
82*1a96fba6SXin Li brillo_loop_.Run();
83*1a96fba6SXin Li }
84*1a96fba6SXin Li
85*1a96fba6SXin Li // Test that simultaneous child processes fire their respective callbacks when
86*1a96fba6SXin Li // exiting.
TEST_F(ProcessReaperTest,ReapedChildrenMatchCallbacks)87*1a96fba6SXin Li TEST_F(ProcessReaperTest, ReapedChildrenMatchCallbacks) {
88*1a96fba6SXin Li int running_children = 10;
89*1a96fba6SXin Li for (int i = 0; i < running_children; ++i) {
90*1a96fba6SXin Li // Different processes will have different exit values.
91*1a96fba6SXin Li int exit_value = 1 + i;
92*1a96fba6SXin Li pid_t pid = ForkChildAndExit(exit_value);
93*1a96fba6SXin Li EXPECT_TRUE(process_reaper_.WatchForChild(FROM_HERE, pid, base::BindOnce(
94*1a96fba6SXin Li [](MessageLoop* loop, int exit_value, int* running_children,
95*1a96fba6SXin Li const siginfo_t& info) {
96*1a96fba6SXin Li EXPECT_EQ(CLD_EXITED, info.si_code);
97*1a96fba6SXin Li EXPECT_EQ(exit_value, info.si_status);
98*1a96fba6SXin Li (*running_children)--;
99*1a96fba6SXin Li if (*running_children == 0)
100*1a96fba6SXin Li loop->BreakLoop();
101*1a96fba6SXin Li }, &brillo_loop_, exit_value, &running_children)));
102*1a96fba6SXin Li }
103*1a96fba6SXin Li // This sleep is optional. It helps to have more processes exit before we
104*1a96fba6SXin Li // start watching for them in the message loop.
105*1a96fba6SXin Li usleep(10 * 1000);
106*1a96fba6SXin Li brillo_loop_.Run();
107*1a96fba6SXin Li EXPECT_EQ(0, running_children);
108*1a96fba6SXin Li }
109*1a96fba6SXin Li
TEST_F(ProcessReaperTest,ReapKilledChild)110*1a96fba6SXin Li TEST_F(ProcessReaperTest, ReapKilledChild) {
111*1a96fba6SXin Li pid_t pid = ForkChildAndKill(SIGKILL);
112*1a96fba6SXin Li EXPECT_TRUE(process_reaper_.WatchForChild(FROM_HERE, pid, base::BindOnce(
113*1a96fba6SXin Li [](MessageLoop* loop, const siginfo_t& info) {
114*1a96fba6SXin Li EXPECT_EQ(CLD_KILLED, info.si_code);
115*1a96fba6SXin Li EXPECT_EQ(SIGKILL, info.si_status);
116*1a96fba6SXin Li loop->BreakLoop();
117*1a96fba6SXin Li }, &brillo_loop_)));
118*1a96fba6SXin Li brillo_loop_.Run();
119*1a96fba6SXin Li }
120*1a96fba6SXin Li
TEST_F(ProcessReaperTest,ReapKilledAndForgottenChild)121*1a96fba6SXin Li TEST_F(ProcessReaperTest, ReapKilledAndForgottenChild) {
122*1a96fba6SXin Li pid_t pid = ForkChildAndExit(0);
123*1a96fba6SXin Li EXPECT_TRUE(process_reaper_.WatchForChild(FROM_HERE, pid, base::BindOnce(
124*1a96fba6SXin Li [](MessageLoop* loop, const siginfo_t& /* info */) {
125*1a96fba6SXin Li ADD_FAILURE() << "Child process was still tracked.";
126*1a96fba6SXin Li loop->BreakLoop();
127*1a96fba6SXin Li }, &brillo_loop_)));
128*1a96fba6SXin Li EXPECT_TRUE(process_reaper_.ForgetChild(pid));
129*1a96fba6SXin Li
130*1a96fba6SXin Li // A second call should return failure.
131*1a96fba6SXin Li EXPECT_FALSE(process_reaper_.ForgetChild(pid));
132*1a96fba6SXin Li
133*1a96fba6SXin Li // Run the loop with a timeout, as the BreakLoop() above is not expected.
134*1a96fba6SXin Li brillo_loop_.PostDelayedTask(FROM_HERE,
135*1a96fba6SXin Li base::Bind(&MessageLoop::BreakLoop,
136*1a96fba6SXin Li base::Unretained(&brillo_loop_)),
137*1a96fba6SXin Li base::TimeDelta::FromMilliseconds(100));
138*1a96fba6SXin Li brillo_loop_.Run();
139*1a96fba6SXin Li }
140*1a96fba6SXin Li
141*1a96fba6SXin Li } // namespace brillo
142