blob: 4aa371b9fdd8ffc542df590cd17e079fdf59f3a7 [file] [log] [blame]
James Kuszmauld42edb42022-01-07 18:00:16 -08001#include "aos/starter/subprocess.h"
2
Philipp Schrader790cb542023-07-05 21:06:52 -07003#include "gtest/gtest.h"
4
James Kuszmauld42edb42022-01-07 18:00:16 -08005#include "aos/events/shm_event_loop.h"
6#include "aos/testing/path.h"
7#include "aos/testing/tmpdir.h"
8#include "aos/util/file.h"
James Kuszmauld42edb42022-01-07 18:00:16 -08009
10namespace aos::starter::testing {
11
12class SubprocessTest : public ::testing::Test {
13 protected:
14 SubprocessTest() : shm_dir_(aos::testing::TestTmpDir() + "/aos") {
15 FLAGS_shm_base = shm_dir_;
16
17 // Nuke the shm dir:
18 aos::util::UnlinkRecursive(shm_dir_);
19 }
20
21 gflags::FlagSaver flag_saver_;
22 std::string shm_dir_;
23};
24
25TEST_F(SubprocessTest, CaptureOutputs) {
26 const std::string config_file =
27 ::aos::testing::ArtifactPath("aos/events/pingpong_config.json");
28
29 aos::FlatbufferDetachedBuffer<aos::Configuration> config =
30 aos::configuration::ReadConfig(config_file);
31 aos::ShmEventLoop event_loop(&config.message());
32 bool observed_stopped = false;
33 Application echo_stdout(
34 "echo", "echo", &event_loop, [&observed_stopped, &echo_stdout]() {
35 if (echo_stdout.status() == aos::starter::State::STOPPED) {
36 observed_stopped = true;
37 }
38 });
39 ASSERT_FALSE(echo_stdout.autorestart());
40 echo_stdout.set_args({"abcdef"});
41 echo_stdout.set_capture_stdout(true);
42 echo_stdout.set_capture_stderr(true);
43
44 echo_stdout.Start();
45 aos::TimerHandler *exit_timer =
46 event_loop.AddTimer([&event_loop]() { event_loop.Exit(); });
47 event_loop.OnRun([&event_loop, exit_timer]() {
Austin Schuh63851a42022-05-16 13:31:37 -070048 // Note: we are using the backup poll in this test to capture SIGCHLD. This
49 // runs at 1 hz, so make sure we let it run at least once.
Philipp Schradera6712522023-07-05 20:25:11 -070050 exit_timer->Schedule(event_loop.monotonic_now() +
51 std::chrono::milliseconds(1500));
James Kuszmauld42edb42022-01-07 18:00:16 -080052 });
53
54 event_loop.Run();
55
James Kuszmauld42edb42022-01-07 18:00:16 -080056 ASSERT_EQ("abcdef\n", echo_stdout.GetStdout());
57 ASSERT_TRUE(echo_stdout.GetStderr().empty());
58 EXPECT_TRUE(observed_stopped);
59 EXPECT_EQ(aos::starter::State::STOPPED, echo_stdout.status());
60
61 observed_stopped = false;
62
63 // Run again, the output should've been cleared.
64 echo_stdout.set_args({"ghijkl"});
65 echo_stdout.Start();
66 event_loop.Run();
67 ASSERT_EQ("ghijkl\n", echo_stdout.GetStdout());
68 EXPECT_TRUE(observed_stopped);
69}
70
71TEST_F(SubprocessTest, CaptureStderr) {
72 const std::string config_file =
73 ::aos::testing::ArtifactPath("aos/events/pingpong_config.json");
74
75 aos::FlatbufferDetachedBuffer<aos::Configuration> config =
76 aos::configuration::ReadConfig(config_file);
77 aos::ShmEventLoop event_loop(&config.message());
78 bool observed_stopped = false;
79 Application echo_stderr(
80 "echo", "sh", &event_loop, [&observed_stopped, &echo_stderr]() {
81 if (echo_stderr.status() == aos::starter::State::STOPPED) {
82 observed_stopped = true;
83 }
84 });
85 echo_stderr.set_args({"-c", "echo abcdef >&2"});
86 echo_stderr.set_capture_stdout(true);
87 echo_stderr.set_capture_stderr(true);
88
89 echo_stderr.Start();
Austin Schuh63851a42022-05-16 13:31:37 -070090 // Note: we are using the backup poll in this test to capture SIGCHLD. This
91 // runs at 1 hz, so make sure we let it run at least once.
James Kuszmauld42edb42022-01-07 18:00:16 -080092 event_loop.AddTimer([&event_loop]() { event_loop.Exit(); })
Philipp Schradera6712522023-07-05 20:25:11 -070093 ->Schedule(event_loop.monotonic_now() + std::chrono::milliseconds(1500));
James Kuszmauld42edb42022-01-07 18:00:16 -080094
95 event_loop.Run();
96
97 ASSERT_EQ("abcdef\n", echo_stderr.GetStderr());
98 ASSERT_TRUE(echo_stderr.GetStdout().empty());
99 ASSERT_TRUE(observed_stopped);
100 ASSERT_EQ(aos::starter::State::STOPPED, echo_stderr.status());
101}
102
payton.rehl2841b1c2023-05-25 17:23:55 -0700103TEST_F(SubprocessTest, UnactiveQuietFlag) {
104 const std::string config_file =
105 ::aos::testing::ArtifactPath("aos/events/pingpong_config.json");
106
107 ::testing::internal::CaptureStderr();
108
109 // Set up application without quiet flag active
110 aos::FlatbufferDetachedBuffer<aos::Configuration> config =
111 aos::configuration::ReadConfig(config_file);
112 aos::ShmEventLoop event_loop(&config.message());
113 bool observed_stopped = false;
114 Application error_out(
115 "false", "false", &event_loop,
116 [&observed_stopped, &error_out]() {
117 if (error_out.status() == aos::starter::State::STOPPED) {
118 observed_stopped = true;
119 }
120 },
121 Application::QuietLogging::kNo);
122 ASSERT_FALSE(error_out.autorestart());
123
124 error_out.Start();
125 aos::TimerHandler *exit_timer =
126 event_loop.AddTimer([&event_loop]() { event_loop.Exit(); });
127 event_loop.OnRun([&event_loop, exit_timer]() {
128 exit_timer->Schedule(event_loop.monotonic_now() +
129 std::chrono::milliseconds(1500));
130 });
131
132 event_loop.Run();
133
134 // Ensure presence of logs without quiet flag
135 std::string output = ::testing::internal::GetCapturedStderr();
136 std::string expectedStart = "Failed to start 'false'";
137 std::string expectedRun = "exited unexpectedly with status";
138
139 ASSERT_TRUE(output.find(expectedStart) != std::string::npos ||
140 output.find(expectedRun) != std::string::npos);
141 EXPECT_TRUE(observed_stopped);
142 EXPECT_EQ(aos::starter::State::STOPPED, error_out.status());
143}
144
145TEST_F(SubprocessTest, ActiveQuietFlag) {
146 const std::string config_file =
147 ::aos::testing::ArtifactPath("aos/events/pingpong_config.json");
148
149 ::testing::internal::CaptureStderr();
150
151 // Set up application with quiet flag active
152 aos::FlatbufferDetachedBuffer<aos::Configuration> config =
153 aos::configuration::ReadConfig(config_file);
154 aos::ShmEventLoop event_loop(&config.message());
155 bool observed_stopped = false;
156 Application error_out(
157 "false", "false", &event_loop,
158 [&observed_stopped, &error_out]() {
159 if (error_out.status() == aos::starter::State::STOPPED) {
160 observed_stopped = true;
161 }
162 },
163 Application::QuietLogging::kYes);
164 ASSERT_FALSE(error_out.autorestart());
165
166 error_out.Start();
167 aos::TimerHandler *exit_timer =
168 event_loop.AddTimer([&event_loop]() { event_loop.Exit(); });
169 event_loop.OnRun([&event_loop, exit_timer]() {
170 exit_timer->Schedule(event_loop.monotonic_now() +
171 std::chrono::milliseconds(1500));
172 });
173
174 event_loop.Run();
175
176 // Ensure lack of logs with quiet flag
177 ASSERT_TRUE(::testing::internal::GetCapturedStderr().empty());
178 EXPECT_TRUE(observed_stopped);
179 EXPECT_EQ(aos::starter::State::STOPPED, error_out.status());
180}
181
James Kuszmauld42edb42022-01-07 18:00:16 -0800182} // namespace aos::starter::testing