| #include <csignal> |
| #include <future> |
| #include <thread> |
| |
| #include "aos/events/ping_generated.h" |
| #include "aos/events/pong_generated.h" |
| #include "aos/testing/path.h" |
| #include "aos/testing/tmpdir.h" |
| #include "gtest/gtest.h" |
| #include "starter_rpc_lib.h" |
| #include "starterd_lib.h" |
| |
| using aos::testing::ArtifactPath; |
| |
| TEST(StarterdTest, StartStopTest) { |
| const std::string config_file = |
| ArtifactPath("aos/events/pingpong_config.json"); |
| |
| aos::FlatbufferDetachedBuffer<aos::Configuration> config = |
| aos::configuration::ReadConfig(config_file); |
| |
| const std::string test_dir = aos::testing::TestTmpDir(); |
| |
| auto new_config = aos::configuration::MergeWithConfig( |
| &config.message(), absl::StrFormat( |
| R"({"applications": [ |
| { |
| "name": "ping", |
| "executable_name": "%s", |
| "args": ["--shm_base", "%s/aos"] |
| }, |
| { |
| "name": "pong", |
| "executable_name": "%s", |
| "args": ["--shm_base", "%s/aos"] |
| } |
| ]})", |
| ArtifactPath("aos/events/ping"), test_dir, |
| ArtifactPath("aos/events/pong"), test_dir)); |
| |
| const aos::Configuration *config_msg = &new_config.message(); |
| |
| // Set up starter with config file |
| aos::starter::Starter starter(config_msg); |
| |
| // Create an event loop to watch for ping messages, verifying it actually |
| // started. |
| aos::ShmEventLoop watcher_loop(config_msg); |
| watcher_loop.SkipAosLog(); |
| |
| watcher_loop |
| .AddTimer([&watcher_loop] { |
| watcher_loop.Exit(); |
| FAIL(); |
| }) |
| ->Setup(watcher_loop.monotonic_now() + std::chrono::seconds(7)); |
| |
| int test_stage = 0; |
| watcher_loop.MakeWatcher( |
| "/test", [&test_stage, config_msg](const aos::examples::Ping &) { |
| switch (test_stage) { |
| case 1: { |
| test_stage = 2; |
| break; |
| } |
| case 2: { |
| std::thread([config_msg] { |
| LOG(INFO) << "Send command"; |
| ASSERT_TRUE(aos::starter::SendCommandBlocking( |
| aos::starter::Command::STOP, "ping", config_msg, |
| std::chrono::seconds(3))); |
| }).detach(); |
| test_stage = 3; |
| break; |
| } |
| } |
| }); |
| |
| watcher_loop.MakeWatcher( |
| "/aos", [&test_stage, &watcher_loop](const aos::starter::Status &status) { |
| const aos::starter::ApplicationStatus *app_status = |
| FindApplicationStatus(status, "ping"); |
| if (app_status == nullptr) { |
| return; |
| } |
| |
| switch (test_stage) { |
| case 0: { |
| if (app_status->has_state() && |
| app_status->state() == aos::starter::State::RUNNING) { |
| test_stage = 1; |
| } |
| break; |
| } |
| |
| case 3: { |
| if (app_status->has_state() && |
| app_status->state() == aos::starter::State::STOPPED) { |
| watcher_loop.Exit(); |
| SUCCEED(); |
| } |
| break; |
| } |
| } |
| }); |
| |
| std::thread starterd_thread([&starter] { starter.Run(); }); |
| watcher_loop.Run(); |
| |
| starter.Cleanup(); |
| starterd_thread.join(); |
| } |
| |
| TEST(StarterdTest, DeathTest) { |
| const std::string config_file = |
| ArtifactPath("aos/events/pingpong_config.json"); |
| |
| aos::FlatbufferDetachedBuffer<aos::Configuration> config = |
| aos::configuration::ReadConfig(config_file); |
| |
| const std::string test_dir = aos::testing::TestTmpDir(); |
| |
| auto new_config = aos::configuration::MergeWithConfig( |
| &config.message(), absl::StrFormat( |
| R"({"applications": [ |
| { |
| "name": "ping", |
| "executable_name": "%s", |
| "args": ["--shm_base", "%s/aos"] |
| }, |
| { |
| "name": "pong", |
| "executable_name": "%s", |
| "args": ["--shm_base", "%s/aos"] |
| } |
| ]})", |
| ArtifactPath("aos/events/ping"), test_dir, |
| ArtifactPath("aos/events/pong"), test_dir)); |
| |
| const aos::Configuration *config_msg = &new_config.message(); |
| |
| // Set up starter with config file |
| aos::starter::Starter starter(config_msg); |
| |
| // Create an event loop to watch for ping messages, verifying it actually |
| // started. |
| aos::ShmEventLoop watcher_loop(config_msg); |
| watcher_loop.SkipAosLog(); |
| |
| watcher_loop |
| .AddTimer([&watcher_loop] { |
| watcher_loop.Exit(); |
| FAIL(); |
| }) |
| ->Setup(watcher_loop.monotonic_now() + std::chrono::seconds(7)); |
| |
| int test_stage = 0; |
| uint64_t id; |
| |
| watcher_loop.MakeWatcher("/aos", [&test_stage, &watcher_loop, |
| &id](const aos::starter::Status &status) { |
| const aos::starter::ApplicationStatus *app_status = |
| FindApplicationStatus(status, "ping"); |
| if (app_status == nullptr) { |
| return; |
| } |
| |
| switch (test_stage) { |
| case 0: { |
| if (app_status->has_state() && |
| app_status->state() == aos::starter::State::RUNNING) { |
| test_stage = 1; |
| ASSERT_TRUE(app_status->has_pid()); |
| ASSERT_TRUE(kill(app_status->pid(), SIGINT) != -1); |
| ASSERT_TRUE(app_status->has_id()); |
| id = app_status->id(); |
| } |
| break; |
| } |
| |
| case 1: { |
| if (app_status->has_state() && |
| app_status->state() == aos::starter::State::RUNNING && |
| app_status->has_id() && app_status->id() != id) { |
| watcher_loop.Exit(); |
| SUCCEED(); |
| } |
| break; |
| } |
| } |
| }); |
| |
| std::thread starterd_thread([&starter] { starter.Run(); }); |
| watcher_loop.Run(); |
| |
| starter.Cleanup(); |
| starterd_thread.join(); |
| } |