From d1a31f23e0d5c57ba98beb6b94feb4052286b51f Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Thu, 25 Jan 2018 23:14:17 +0000 Subject: [PATCH] Process tests: check timer status in various tests. Make sure that timers have been stopped appropriately after state transitions. --- src/tests/proctests.cc | 73 ++++++++++++++++++++++++++++++++- src/tests/test-includes/dinit.h | 8 +++- 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/src/tests/proctests.cc b/src/tests/proctests.cc index d1eae39..45b56de 100644 --- a/src/tests/proctests.cc +++ b/src/tests/proctests.cc @@ -12,6 +12,8 @@ // These tests work mostly by completely mocking out the base_process_service class. The mock // implementations can be found in test-baseproc.cc. +extern eventloop_t event_loop; + // Friend interface to access base_process_service private/protected members. class base_process_service_test { @@ -35,12 +37,11 @@ namespace bp_sys { extern pid_t last_forked_pid; } -static void init_service_defaults(process_service &ps) +static void init_service_defaults(base_process_service &ps) { ps.set_restart_interval(time_val(10,0), 3); ps.set_restart_delay(time_val(0, 200000000)); // 200 milliseconds ps.set_stop_timeout(time_val(10,0)); - ps.set_start_timeout(time_val(10,0)); ps.set_start_interruptible(false); } @@ -68,6 +69,7 @@ void test_proc_service_start() sset.process_queues(); assert(p.get_state() == service_state_t::STARTED); + assert(event_loop.active_timers.size() == 0); } // Unexpected termination @@ -95,6 +97,7 @@ void test_proc_unexpected_term() sset.process_queues(); assert(p.get_state() == service_state_t::STOPPED); + assert(event_loop.active_timers.size() == 0); } // Termination via stop request @@ -119,16 +122,19 @@ void test_term_via_stop() sset.process_queues(); assert(p.get_state() == service_state_t::STARTED); + assert(event_loop.active_timers.size() == 0); p.stop(true); sset.process_queues(); assert(p.get_state() == service_state_t::STOPPING); + assert(event_loop.active_timers.size() == 1); base_process_service_test::handle_exit(&p, 0); sset.process_queues(); assert(p.get_state() == service_state_t::STOPPED); + assert(event_loop.active_timers.size() == 0); } // Time-out during start @@ -160,6 +166,7 @@ void test_proc_start_timeout() sset.process_queues(); assert(p.get_state() == service_state_t::STOPPED); + assert(event_loop.active_timers.size() == 0); } // Test stop timeout @@ -204,6 +211,9 @@ void test_proc_stop_timeout() sset.process_queues(); assert(p.get_state() == service_state_t::STOPPED); + // Note that timer is still active as we faked its expiry above + //assert(event_loop.active_timers.size() == 0); + event_loop.active_timers.clear(); } // Smooth recovery @@ -245,6 +255,7 @@ void test_proc_smooth_recovery1() // Now a new process should've been launched: assert(first_instance + 1 == bp_sys::last_forked_pid); assert(p.get_state() == service_state_t::STARTED); + event_loop.active_timers.clear(); } // Smooth recovery without restart delay @@ -273,6 +284,7 @@ void test_proc_smooth_recovery2() pid_t first_instance = bp_sys::last_forked_pid; assert(p.get_state() == service_state_t::STARTED); + assert(event_loop.active_timers.size() == 0); base_process_service_test::handle_exit(&p, 0); sset.process_queues(); @@ -280,8 +292,64 @@ void test_proc_smooth_recovery2() // no restart delay, process should restart immediately: assert(first_instance + 1 == bp_sys::last_forked_pid); assert(p.get_state() == service_state_t::STARTED); + assert(event_loop.active_timers.size() == 0); } +// Test stop timeout +void test_scripted_stop_timeout() +{ + using namespace std; + + service_set sset; + + string command = "test-command"; + string stopcommand = "stop-command"; + list> command_offsets; + command_offsets.emplace_back(0, command.length()); + std::list depends; + + scripted_service p = scripted_service(&sset, "testscripted", std::move(command), command_offsets, depends); + init_service_defaults(p); + p.set_stop_command(stopcommand, command_offsets); + + p.start(true); + sset.process_queues(); + + assert(p.get_state() == service_state_t::STARTING); + + base_process_service_test::exec_succeeded(&p); + sset.process_queues(); + base_process_service_test::handle_exit(&p, 0); + sset.process_queues(); + + assert(p.get_state() == service_state_t::STARTED); + + p.stop(true); + sset.process_queues(); + + assert(p.get_state() == service_state_t::STOPPING); + + base_process_service_test::exec_succeeded(&p); + sset.process_queues(); + + // should still be stopping: + assert(p.get_state() == service_state_t::STOPPING); + + p.timer_expired(); + sset.process_queues(); + + // kill signal (SIGKILL) should have been sent; process not dead until it's dead, however + assert(p.get_state() == service_state_t::STOPPING); + assert(bp_sys::last_sig_sent == SIGKILL); + + base_process_service_test::handle_exit(&p, SIGKILL); + sset.process_queues(); + + assert(p.get_state() == service_state_t::STOPPED); + event_loop.active_timers.clear(); +} + + #define RUN_TEST(name, spacing) \ std::cout << #name "..." spacing; \ name(); \ @@ -296,4 +364,5 @@ int main(int argc, char **argv) RUN_TEST(test_proc_stop_timeout, " "); RUN_TEST(test_proc_smooth_recovery1, ""); RUN_TEST(test_proc_smooth_recovery2, ""); + RUN_TEST(test_scripted_stop_timeout, ""); } diff --git a/src/tests/test-includes/dinit.h b/src/tests/test-includes/dinit.h index ef945ca..f43eab4 100644 --- a/src/tests/test-includes/dinit.h +++ b/src/tests/test-includes/dinit.h @@ -3,6 +3,8 @@ // dummy dinit.h +#include + #include "dasynq.h" using clock_type = dasynq::clock_type; @@ -92,12 +94,12 @@ class eventloop_t void arm_timer_rel(eventloop_t &loop, time_val timeout) noexcept { - + loop.active_timers.insert(this); } void stop_timer(eventloop_t &loop) noexcept { - + loop.active_timers.erase(this); } }; @@ -105,6 +107,8 @@ class eventloop_t { }; + + std::unordered_set active_timers; }; inline void open_control_socket(bool report_ro_failure = true) noexcept -- 2.25.1