Add test for restart after unexpected termination.
authorDavin McCall <davmac@davmac.org>
Sat, 25 May 2019 14:55:51 +0000 (00:55 +1000)
committerDavin McCall <davmac@davmac.org>
Sun, 26 May 2019 04:48:25 +0000 (14:48 +1000)
src/tests/proctests.cc
src/tests/test-includes/dinit.h

index a4484d95573d1805fb3058ed596ee6e23a6853d3..026ca8f9a924a45094ff4add193cea65a0cdc73d 100644 (file)
@@ -171,6 +171,52 @@ void test_proc_unexpected_term()
     sset.remove_service(&p);
 }
 
+// Unexpected termination
+void test_proc_term_restart()
+{
+    using namespace std;
+
+    service_set sset;
+
+    string command = "test-command";
+    list<pair<unsigned,unsigned>> command_offsets;
+    command_offsets.emplace_back(0, command.length());
+    std::list<prelim_dep> depends;
+
+    process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
+    init_service_defaults(p);
+    p.set_auto_restart(true);
+    sset.add_service(&p);
+
+    p.start(true);
+    sset.process_queues();
+
+    base_process_service_test::exec_succeeded(&p);
+    sset.process_queues();
+
+    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();
+
+    // Starting, restart timer should be armed:
+    assert(p.get_state() == service_state_t::STARTING);
+    assert(event_loop.active_timers.size() == 1);
+
+    event_loop.advance_time(time_val(0, 200000000));
+    assert(event_loop.active_timers.size() == 0);
+
+    sset.process_queues();
+    base_process_service_test::exec_succeeded(&p);
+    sset.process_queues();
+
+    assert(p.get_state() == service_state_t::STARTED);
+    assert(event_loop.active_timers.size() == 0);
+
+    sset.remove_service(&p);
+}
+
 // Termination via stop request
 void test_term_via_stop()
 {
@@ -892,6 +938,7 @@ int main(int argc, char **argv)
     RUN_TEST(test_proc_service_start, "   ");
     RUN_TEST(test_proc_notify_start, "    ");
     RUN_TEST(test_proc_unexpected_term, " ");
+    RUN_TEST(test_proc_term_restart, "    ");
     RUN_TEST(test_term_via_stop, "        ");
     RUN_TEST(test_term_via_stop2, "       ");
     RUN_TEST(test_proc_start_timeout, "   ");
index e2a043992e639c6215500dabd05c77e5f1256fc5..d97493d8f13a5cdf2a04438d4231dd54cec296bb 100644 (file)
@@ -6,6 +6,7 @@
 #include <unordered_set>
 #include <map>
 #include <string>
+#include <cassert>
 
 #include "dasynq.h"
 
@@ -19,10 +20,24 @@ namespace bp_sys {
 
 class eventloop_t
 {
+    time_val current_time {0, 0};
+
     public:
     void get_time(time_val &tv, dasynq::clock_type clock) noexcept
     {
-        tv = {0, 0};
+        tv = current_time;
+    }
+
+    void advance_time(time_val amount)
+    {
+        current_time += amount;
+        for (timer * t : active_timers) {
+            if (t->expiry_time >= current_time) {
+                t->stop_timer(*this);
+                rearm r = t->expired(*this, 1);
+                assert(r == rearm::NOOP); // others not handled
+            }
+        }
     }
 
     class child_proc_watcher
@@ -142,6 +157,17 @@ class eventloop_t
 
     class timer
     {
+        friend class eventloop_t;
+
+        private:
+        time_val expiry_time;
+
+        protected:
+        virtual rearm expired(eventloop_t &loop, int expiry_count)
+        {
+            return rearm::NOOP;
+        }
+
         public:
         void add_timer(eventloop_t &loop)
         {
@@ -150,6 +176,7 @@ class eventloop_t
 
         void arm_timer_rel(eventloop_t &loop, time_val timeout) noexcept
         {
+            expiry_time = loop.current_time + timeout;
             loop.active_timers.insert(this);
         }
 
@@ -166,7 +193,11 @@ class eventloop_t
 
     template <typename Derived> class timer_impl : public timer
     {
-
+        protected:
+        virtual rearm expired(eventloop_t &loop, int expiry_count) override
+        {
+            return static_cast<Derived *>(this)->timer_expiry(loop, expiry_count);
+        }
     };
 
     std::unordered_set<timer *> active_timers;