blob: 4aa371b9fdd8ffc542df590cd17e079fdf59f3a7 [file] [log] [blame]
#include "aos/starter/subprocess.h"
#include "gtest/gtest.h"
#include "aos/events/shm_event_loop.h"
#include "aos/testing/path.h"
#include "aos/testing/tmpdir.h"
#include "aos/util/file.h"
namespace aos::starter::testing {
class SubprocessTest : public ::testing::Test {
protected:
SubprocessTest() : shm_dir_(aos::testing::TestTmpDir() + "/aos") {
FLAGS_shm_base = shm_dir_;
// Nuke the shm dir:
aos::util::UnlinkRecursive(shm_dir_);
}
gflags::FlagSaver flag_saver_;
std::string shm_dir_;
};
TEST_F(SubprocessTest, CaptureOutputs) {
const std::string config_file =
::aos::testing::ArtifactPath("aos/events/pingpong_config.json");
aos::FlatbufferDetachedBuffer<aos::Configuration> config =
aos::configuration::ReadConfig(config_file);
aos::ShmEventLoop event_loop(&config.message());
bool observed_stopped = false;
Application echo_stdout(
"echo", "echo", &event_loop, [&observed_stopped, &echo_stdout]() {
if (echo_stdout.status() == aos::starter::State::STOPPED) {
observed_stopped = true;
}
});
ASSERT_FALSE(echo_stdout.autorestart());
echo_stdout.set_args({"abcdef"});
echo_stdout.set_capture_stdout(true);
echo_stdout.set_capture_stderr(true);
echo_stdout.Start();
aos::TimerHandler *exit_timer =
event_loop.AddTimer([&event_loop]() { event_loop.Exit(); });
event_loop.OnRun([&event_loop, exit_timer]() {
// Note: we are using the backup poll in this test to capture SIGCHLD. This
// runs at 1 hz, so make sure we let it run at least once.
exit_timer->Schedule(event_loop.monotonic_now() +
std::chrono::milliseconds(1500));
});
event_loop.Run();
ASSERT_EQ("abcdef\n", echo_stdout.GetStdout());
ASSERT_TRUE(echo_stdout.GetStderr().empty());
EXPECT_TRUE(observed_stopped);
EXPECT_EQ(aos::starter::State::STOPPED, echo_stdout.status());
observed_stopped = false;
// Run again, the output should've been cleared.
echo_stdout.set_args({"ghijkl"});
echo_stdout.Start();
event_loop.Run();
ASSERT_EQ("ghijkl\n", echo_stdout.GetStdout());
EXPECT_TRUE(observed_stopped);
}
TEST_F(SubprocessTest, CaptureStderr) {
const std::string config_file =
::aos::testing::ArtifactPath("aos/events/pingpong_config.json");
aos::FlatbufferDetachedBuffer<aos::Configuration> config =
aos::configuration::ReadConfig(config_file);
aos::ShmEventLoop event_loop(&config.message());
bool observed_stopped = false;
Application echo_stderr(
"echo", "sh", &event_loop, [&observed_stopped, &echo_stderr]() {
if (echo_stderr.status() == aos::starter::State::STOPPED) {
observed_stopped = true;
}
});
echo_stderr.set_args({"-c", "echo abcdef >&2"});
echo_stderr.set_capture_stdout(true);
echo_stderr.set_capture_stderr(true);
echo_stderr.Start();
// Note: we are using the backup poll in this test to capture SIGCHLD. This
// runs at 1 hz, so make sure we let it run at least once.
event_loop.AddTimer([&event_loop]() { event_loop.Exit(); })
->Schedule(event_loop.monotonic_now() + std::chrono::milliseconds(1500));
event_loop.Run();
ASSERT_EQ("abcdef\n", echo_stderr.GetStderr());
ASSERT_TRUE(echo_stderr.GetStdout().empty());
ASSERT_TRUE(observed_stopped);
ASSERT_EQ(aos::starter::State::STOPPED, echo_stderr.status());
}
TEST_F(SubprocessTest, UnactiveQuietFlag) {
const std::string config_file =
::aos::testing::ArtifactPath("aos/events/pingpong_config.json");
::testing::internal::CaptureStderr();
// Set up application without quiet flag active
aos::FlatbufferDetachedBuffer<aos::Configuration> config =
aos::configuration::ReadConfig(config_file);
aos::ShmEventLoop event_loop(&config.message());
bool observed_stopped = false;
Application error_out(
"false", "false", &event_loop,
[&observed_stopped, &error_out]() {
if (error_out.status() == aos::starter::State::STOPPED) {
observed_stopped = true;
}
},
Application::QuietLogging::kNo);
ASSERT_FALSE(error_out.autorestart());
error_out.Start();
aos::TimerHandler *exit_timer =
event_loop.AddTimer([&event_loop]() { event_loop.Exit(); });
event_loop.OnRun([&event_loop, exit_timer]() {
exit_timer->Schedule(event_loop.monotonic_now() +
std::chrono::milliseconds(1500));
});
event_loop.Run();
// Ensure presence of logs without quiet flag
std::string output = ::testing::internal::GetCapturedStderr();
std::string expectedStart = "Failed to start 'false'";
std::string expectedRun = "exited unexpectedly with status";
ASSERT_TRUE(output.find(expectedStart) != std::string::npos ||
output.find(expectedRun) != std::string::npos);
EXPECT_TRUE(observed_stopped);
EXPECT_EQ(aos::starter::State::STOPPED, error_out.status());
}
TEST_F(SubprocessTest, ActiveQuietFlag) {
const std::string config_file =
::aos::testing::ArtifactPath("aos/events/pingpong_config.json");
::testing::internal::CaptureStderr();
// Set up application with quiet flag active
aos::FlatbufferDetachedBuffer<aos::Configuration> config =
aos::configuration::ReadConfig(config_file);
aos::ShmEventLoop event_loop(&config.message());
bool observed_stopped = false;
Application error_out(
"false", "false", &event_loop,
[&observed_stopped, &error_out]() {
if (error_out.status() == aos::starter::State::STOPPED) {
observed_stopped = true;
}
},
Application::QuietLogging::kYes);
ASSERT_FALSE(error_out.autorestart());
error_out.Start();
aos::TimerHandler *exit_timer =
event_loop.AddTimer([&event_loop]() { event_loop.Exit(); });
event_loop.OnRun([&event_loop, exit_timer]() {
exit_timer->Schedule(event_loop.monotonic_now() +
std::chrono::milliseconds(1500));
});
event_loop.Run();
// Ensure lack of logs with quiet flag
ASSERT_TRUE(::testing::internal::GetCapturedStderr().empty());
EXPECT_TRUE(observed_stopped);
EXPECT_EQ(aos::starter::State::STOPPED, error_out.status());
}
} // namespace aos::starter::testing