From b0c98dacc34d599a42ddaccf2ad926b1cfde61ac Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Sat, 18 Apr 2020 11:23:27 +1000 Subject: [PATCH] Add unit test for bgprocess smooth recovery --- src/proc-service.cc | 8 +-- src/tests/proctests.cc | 118 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+), 4 deletions(-) diff --git a/src/proc-service.cc b/src/proc-service.cc index bca430e..c7970df 100644 --- a/src/proc-service.cc +++ b/src/proc-service.cc @@ -486,7 +486,7 @@ bgproc_service::pid_result_t bgproc_service::read_pid_file(bp_sys::exit_status *exit_status) noexcept { const char *pid_file_c = pid_file.c_str(); - int fd = open(pid_file_c, O_CLOEXEC); + int fd = bp_sys::open(pid_file_c, O_CLOEXEC); if (fd == -1) { log(loglevel_t::ERROR, get_name(), ": read pid file: ", strerror(errno)); return pid_result_t::FAILED; @@ -497,11 +497,11 @@ bgproc_service::read_pid_file(bp_sys::exit_status *exit_status) noexcept if (r < 0) { // Could not read from PID file log(loglevel_t::ERROR, get_name(), ": could not read from pidfile; ", strerror(errno)); - close(fd); + bp_sys::close(fd); return pid_result_t::FAILED; } - close(fd); + bp_sys::close(fd); pidbuf[r] = 0; // store nul terminator bool valid_pid = false; @@ -523,7 +523,7 @@ bgproc_service::read_pid_file(bp_sys::exit_status *exit_status) noexcept pid_t wait_r = waitpid(pid, exit_status, WNOHANG); if (wait_r == -1 && errno == ECHILD) { // We can't track this child - check process exists: - if (kill(pid, 0) == 0 || errno != ESRCH) { + if (bp_sys::kill(pid, 0) == 0 || errno != ESRCH) { tracking_child = false; return pid_result_t::OK; } diff --git a/src/tests/proctests.cc b/src/tests/proctests.cc index b75eea3..7cba9a2 100644 --- a/src/tests/proctests.cc +++ b/src/tests/proctests.cc @@ -3,6 +3,7 @@ #include #include #include +#include #include "service.h" #include "proc-service.h" @@ -680,6 +681,122 @@ void test_proc_smooth_recovery2() sset.remove_service(&p); } +void test_bgproc_smooth_recover() +{ + using namespace std; + + service_set sset; + + string command = "test-command"; + list> command_offsets; + command_offsets.emplace_back(0, command.length()); + std::list depends; + + bgproc_service p {&sset, "testproc", std::move(command), command_offsets, depends}; + init_service_defaults(p); + p.set_smooth_recovery(true); + p.set_restart_delay(time_val {0, 1000}); + p.set_pid_file("/run/daemon.pid"); + sset.add_service(&p); + + p.start(true); + sset.process_queues(); + + base_process_service_test::exec_succeeded(&p); + sset.process_queues(); + + // pid_t first_instance = bp_sys::last_forked_pid; + pid_t daemon_instance = ++bp_sys::last_forked_pid; + + // Set up the pid file content with the pid of the daemon + stringstream str; + str << daemon_instance << std::flush; + string pid_file_content = str.str(); + vector pid_file_content_v(pid_file_content.begin(), pid_file_content.end()); + bp_sys::supply_file_content("/run/daemon.pid", std::move(pid_file_content_v)); + + assert(p.get_state() == service_state_t::STARTING); + + base_process_service_test::handle_exit(&p, 0); // exit the launch process + sset.process_queues(); + + // daemon process has been started now, state should be STARTED + assert(p.get_state() == service_state_t::STARTED); + assert(daemon_instance == bp_sys::last_forked_pid); + + base_process_service_test::handle_exit(&p, 0); // exit the daemon process + + // since time hasn't been changed, we expect that the process has not yet been re-launched: + assert(p.get_state() == service_state_t::STARTED); + assert(daemon_instance == bp_sys::last_forked_pid); + + event_loop.advance_time(time_val {0, 1000}); + sset.process_queues(); + + // Now a new process should've been launched: + assert(event_loop.active_timers.size() == 0); + assert(daemon_instance + 1 == bp_sys::last_forked_pid); + assert(p.get_state() == service_state_t::STARTED); + assert(event_loop.active_timers.size() == 0); + + base_process_service_test::exec_succeeded(&p); + sset.process_queues(); + + assert(event_loop.active_timers.size() == 0); + + daemon_instance = ++bp_sys::last_forked_pid; + str.str(""); + str << daemon_instance << std::flush; + pid_file_content = str.str(); + pid_file_content_v = std::vector(pid_file_content.begin(), pid_file_content.end()); + bp_sys::supply_file_content("/run/daemon.pid", std::move(pid_file_content_v)); + + base_process_service_test::handle_exit(&p, 0); + sset.process_queues(); + + assert(p.get_state() == service_state_t::STARTED); + + assert(event_loop.active_timers.size() == 0); + + // Now run through it again + + base_process_service_test::handle_exit(&p, 0); // exit the daemon process + + // since time hasn't been changed, we expect that the process has not yet been re-launched: + assert(p.get_state() == service_state_t::STARTED); + assert(daemon_instance == bp_sys::last_forked_pid); + + event_loop.advance_time(time_val {0, 1000}); + sset.process_queues(); + + // Now a new process should've been launched: + assert(event_loop.active_timers.size() == 0); + assert(daemon_instance + 1 == bp_sys::last_forked_pid); + assert(p.get_state() == service_state_t::STARTED); + assert(event_loop.active_timers.size() == 0); + + base_process_service_test::exec_succeeded(&p); + sset.process_queues(); + + assert(event_loop.active_timers.size() == 0); + + daemon_instance = ++bp_sys::last_forked_pid; + str.str(""); + str << daemon_instance << std::flush; + pid_file_content = str.str(); + pid_file_content_v = std::vector(pid_file_content.begin(), pid_file_content.end()); + bp_sys::supply_file_content("/run/daemon.pid", std::move(pid_file_content_v)); + + base_process_service_test::handle_exit(&p, 0); + sset.process_queues(); + + assert(p.get_state() == service_state_t::STARTED); + + assert(event_loop.active_timers.size() == 0); + + sset.remove_service(&p); +} + // Test stop timeout void test_scripted_stop_timeout() { @@ -1035,6 +1152,7 @@ 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_bgproc_smooth_recover, ""); RUN_TEST(test_scripted_stop_timeout, ""); RUN_TEST(test_scripted_start_fail, " "); RUN_TEST(test_scripted_stop_fail, " "); -- 2.25.1