xref: /aosp_15_r20/external/libbrillo/brillo/process_reaper_test.cc (revision 1a96fba65179ea7d3f56207137718607415c5953)
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