Tests: don't call timer_expiry directly.
[oweals/dinit.git] / src / tests / proctests.cc
index c7168339c44dce7c74304a70a799ed79603899e4..c00b65af42f3b05d5edcbaa825e68847011a3542 100644 (file)
@@ -16,7 +16,6 @@ extern eventloop_t event_loop;
 
 constexpr static auto REG = dependency_type::REGULAR;
 constexpr static auto WAITS = dependency_type::WAITS_FOR;
-constexpr static auto MS = dependency_type::MILESTONE;
 
 // Friend interface to access base_process_service private/protected members.
 class base_process_service_test
@@ -28,6 +27,12 @@ class base_process_service_test
         bsp->exec_succeeded();
     }
 
+    static void exec_failed(base_process_service *bsp, int errcode)
+    {
+       bsp->waiting_for_execstat = false;
+       bsp->exec_failed(errcode);
+    }
+
     static void handle_exit(base_process_service *bsp, int exit_status)
     {
         bsp->pid = -1;
@@ -39,6 +44,11 @@ class base_process_service_test
         bsp->pid = -1;
         bsp->handle_exit_status(bp_sys::exit_status(false, true, signo));
     }
+
+    static int get_notification_fd(base_process_service *bsp)
+    {
+        return bsp->notification_fd;
+    }
 };
 
 namespace bp_sys {
@@ -52,7 +62,6 @@ 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_interruptible(false);
 }
 
 // Regular service start
@@ -67,7 +76,7 @@ void test_proc_service_start()
     command_offsets.emplace_back(0, command.length());
     std::list<prelim_dep> depends;
 
-    process_service p = process_service(&sset, "testproc", std::move(command), command_offsets, depends);
+    process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
     init_service_defaults(p);
     sset.add_service(&p);
 
@@ -85,6 +94,49 @@ void test_proc_service_start()
     sset.remove_service(&p);
 }
 
+// Test start with readiness notification
+void test_proc_notify_start()
+{
+    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_notification_fd(3);
+    sset.add_service(&p);
+
+    p.start(true);
+    sset.process_queues();
+
+    assert(p.get_state() == service_state_t::STARTING);
+
+    base_process_service_test::exec_succeeded(&p);
+    sset.process_queues();
+
+    assert(p.get_state() == service_state_t::STARTING);
+
+    int nfd = base_process_service_test::get_notification_fd(&p);
+    assert(nfd > 0);
+
+    char notifystr[] = "ok started\n";
+    std::vector<char> rnotifystr;
+    rnotifystr.insert(rnotifystr.end(), notifystr, notifystr + sizeof(notifystr));
+    bp_sys::supply_read_data(nfd, std::move(rnotifystr));
+
+    event_loop.regd_fd_watchers[nfd]->fd_event(event_loop, nfd, dasynq::IN_EVENTS);
+
+    assert(p.get_state() == service_state_t::STARTED);
+    assert(event_loop.active_timers.size() == 0);
+
+    sset.remove_service(&p);
+}
+
 // Unexpected termination
 void test_proc_unexpected_term()
 {
@@ -97,7 +149,7 @@ void test_proc_unexpected_term()
     command_offsets.emplace_back(0, command.length());
     std::list<prelim_dep> depends;
 
-    process_service p = process_service(&sset, "testproc", std::move(command), command_offsets, depends);
+    process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
     init_service_defaults(p);
     sset.add_service(&p);
 
@@ -113,6 +165,53 @@ void test_proc_unexpected_term()
     sset.process_queues();
 
     assert(p.get_state() == service_state_t::STOPPED);
+    assert(p.get_stop_reason() == stopped_reason_t::TERMINATED);
+    assert(event_loop.active_timers.size() == 0);
+
+    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);
@@ -130,7 +229,7 @@ void test_term_via_stop()
     command_offsets.emplace_back(0, command.length());
     std::list<prelim_dep> depends;
 
-    process_service p = process_service(&sset, "testproc", std::move(command), command_offsets, depends);
+    process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
     init_service_defaults(p);
     sset.add_service(&p);
 
@@ -153,6 +252,58 @@ void test_term_via_stop()
     sset.process_queues();
 
     assert(p.get_state() == service_state_t::STOPPED);
+    assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
+    assert(event_loop.active_timers.size() == 0);
+
+    sset.remove_service(&p);
+}
+
+// Termination via stop request, ensure reason is reset:
+void test_term_via_stop2()
+{
+    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);
+    sset.add_service(&p);
+
+    p.start(true);
+    sset.process_queues();
+
+    // first set it up with failure reason:
+
+    base_process_service_test::exec_failed(&p, ENOENT);
+    sset.process_queues();
+
+    assert(p.get_state() == service_state_t::STOPPED);
+    assert(p.get_stop_reason() == stopped_reason_t::EXECFAILED);
+
+    // now restart clean:
+
+    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);
+
+    p.stop(true);
+    sset.process_queues();
+    assert(p.get_state() == service_state_t::STOPPING);
+
+    base_process_service_test::handle_exit(&p, 0);
+    sset.process_queues();
+    assert(p.get_state() == service_state_t::STOPPED);
+    assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
     assert(event_loop.active_timers.size() == 0);
 
     sset.remove_service(&p);
@@ -170,8 +321,9 @@ void test_proc_start_timeout()
     command_offsets.emplace_back(0, command.length());
     std::list<prelim_dep> depends;
 
-    process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
+    scripted_service p {&sset, "testproc", std::move(command), command_offsets, depends};
     init_service_defaults(p);
+    p.set_start_timeout(time_val(10,0));
     sset.add_service(&p);
 
     p.start(true);
@@ -179,15 +331,17 @@ void test_proc_start_timeout()
 
     assert(p.get_state() == service_state_t::STARTING);
 
-    p.timer_expired();
+    event_loop.advance_time(time_val(10,0));
     sset.process_queues();
 
     assert(p.get_state() == service_state_t::STOPPING);
 
-    base_process_service_test::handle_exit(&p, 0);
+    base_process_service_test::handle_signal_exit(&p, SIGTERM);
     sset.process_queues();
 
+    // We set no stop script, so state should now be STOPPED with no timer set
     assert(p.get_state() == service_state_t::STOPPED);
+    assert(p.get_stop_reason() == stopped_reason_t::TIMEDOUT);
     assert(event_loop.active_timers.size() == 0);
 
     sset.remove_service(&p);
@@ -205,11 +359,13 @@ void test_proc_start_timeout2()
     command_offsets.emplace_back(0, command.length());
     std::list<prelim_dep> depends;
 
-    process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
+    scripted_service p {&sset, "testproc", std::move(command), command_offsets, depends};
+    p.set_start_timeout(time_val {1,0});
     init_service_defaults(p);
     sset.add_service(&p);
 
-    service_record ts {&sset, "test-service-1", service_type_t::INTERNAL, {{&p, dependency_type::WAITS_FOR}} };
+    service_record ts {&sset, "test-service-1", service_type_t::INTERNAL,
+        {{&p, dependency_type::WAITS_FOR}} };
 
     ts.start(true);
     sset.process_queues();
@@ -217,7 +373,7 @@ void test_proc_start_timeout2()
     assert(p.get_state() == service_state_t::STARTING);
     assert(ts.get_state() == service_state_t::STARTING);
 
-    p.timer_expired();
+    event_loop.advance_time(time_val {1,0}); // start timer should expire
     sset.process_queues();
 
     assert(p.get_state() == service_state_t::STOPPING);
@@ -226,12 +382,88 @@ void test_proc_start_timeout2()
     sset.process_queues();
 
     assert(p.get_state() == service_state_t::STOPPED);
+    assert(p.get_stop_reason() == stopped_reason_t::TIMEDOUT);
     assert(ts.get_state() == service_state_t::STARTED);
     assert(event_loop.active_timers.size() == 0);
 
     sset.remove_service(&p);
 }
 
+// Test exec() failure for process service start.
+void test_proc_start_execfail()
+{
+    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);
+    sset.add_service(&p);
+
+    p.start(true);
+    sset.process_queues();
+
+    assert(p.get_state() == service_state_t::STARTING);
+
+    base_process_service_test::exec_failed(&p, ENOENT);
+    sset.process_queues();
+
+    assert(p.get_state() == service_state_t::STOPPED);
+    assert(p.get_stop_reason() == stopped_reason_t::EXECFAILED);
+    assert(event_loop.active_timers.size() == 0);
+
+    sset.remove_service(&p);
+}
+
+// Test no ready notification before process terminates
+void test_proc_notify_fail()
+{
+    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_notification_fd(3);
+    sset.add_service(&p);
+
+    p.start(true);
+    sset.process_queues();
+
+    assert(p.get_state() == service_state_t::STARTING);
+
+    base_process_service_test::exec_succeeded(&p);
+    sset.process_queues();
+
+    assert(p.get_state() == service_state_t::STARTING);
+
+    int nfd = base_process_service_test::get_notification_fd(&p);
+    assert(nfd > 0);
+
+    // Signal EOF on notify fd:
+    event_loop.regd_fd_watchers[nfd]->fd_event(event_loop, nfd, dasynq::IN_EVENTS);
+
+    assert(p.get_state() == service_state_t::STOPPING);
+
+    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);
+
+    sset.remove_service(&p);
+}
+
 // Test stop timeout
 void test_proc_stop_timeout()
 {
@@ -244,8 +476,9 @@ void test_proc_stop_timeout()
     command_offsets.emplace_back(0, command.length());
     std::list<prelim_dep> depends;
 
-    process_service p = process_service(&sset, "testproc", std::move(command), command_offsets, depends);
+    process_service p {&sset, "testproc", std::move(command), command_offsets, depends};
     init_service_defaults(p);
+    p.set_stop_timeout(time_val {10, 0});
     sset.add_service(&p);
 
     p.start(true);
@@ -264,7 +497,7 @@ void test_proc_stop_timeout()
     assert(p.get_state() == service_state_t::STOPPING);
     assert(bp_sys::last_sig_sent == SIGTERM);
 
-    p.timer_expired();
+    event_loop.advance_time(time_val {10, 0}); // expire stop timer
     sset.process_queues();
 
     // kill signal (SIGKILL) should have been sent; process not dead until it's dead, however
@@ -275,10 +508,10 @@ void test_proc_stop_timeout()
     sset.process_queues();
 
     assert(p.get_state() == service_state_t::STOPPED);
+    assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
+
+    assert(event_loop.active_timers.size() == 0);
 
-    // Note that timer is still active as we faked its expiry above
-    //assert(event_loop.active_timers.size() == 0);
-    event_loop.active_timers.clear();
     sset.remove_service(&p);
 }
 
@@ -294,9 +527,10 @@ void test_proc_smooth_recovery1()
     command_offsets.emplace_back(0, command.length());
     std::list<prelim_dep> depends;
 
-    process_service p = process_service(&sset, "testproc", std::move(command), command_offsets, depends);
+    process_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});
     sset.add_service(&p);
 
     p.start(true);
@@ -316,13 +550,14 @@ void test_proc_smooth_recovery1()
     assert(first_instance == bp_sys::last_forked_pid);
     assert(p.get_state() == service_state_t::STARTED);
 
-    p.timer_expired();
+    event_loop.advance_time(time_val {0, 1000});
     sset.process_queues();
 
     // 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();
+
+    assert(event_loop.active_timers.size() == 0);
 
     sset.remove_service(&p);
 }
@@ -339,7 +574,7 @@ void test_proc_smooth_recovery2()
     command_offsets.emplace_back(0, command.length());
     std::list<prelim_dep> depends;
 
-    process_service p = process_service(&sset, "testproc", std::move(command), command_offsets, depends);
+    process_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, 0));
@@ -380,9 +615,10 @@ void test_scripted_stop_timeout()
     command_offsets.emplace_back(0, command.length());
     std::list<prelim_dep> depends;
 
-    scripted_service p = scripted_service(&sset, "testscripted", std::move(command), command_offsets, depends);
+    scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
     init_service_defaults(p);
     p.set_stop_command(stopcommand, command_offsets);
+    p.set_stop_timeout(time_val {10, 0});
     sset.add_service(&p);
 
     p.start(true);
@@ -408,7 +644,7 @@ void test_scripted_stop_timeout()
     // should still be stopping:
     assert(p.get_state() == service_state_t::STOPPING);
 
-    p.timer_expired();
+    event_loop.advance_time(time_val {10, 0}); // expire stop timer
     sset.process_queues();
 
     // kill signal (SIGKILL) should have been sent; process not dead until it's dead, however
@@ -419,8 +655,10 @@ void test_scripted_stop_timeout()
     sset.process_queues();
 
     assert(p.get_state() == service_state_t::STOPPED);
+    assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
+
+    assert(event_loop.active_timers.size() == 0);
 
-    event_loop.active_timers.clear();
     sset.remove_service(&p);
 }
 
@@ -436,13 +674,14 @@ void test_scripted_start_fail()
     command_offsets.emplace_back(0, command.length());
     std::list<prelim_dep> depends;
 
-    scripted_service p = scripted_service(&sset, "testscripted", std::move(command), command_offsets, depends);
+    scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
     init_service_defaults(p);
     p.set_stop_command(stopcommand, command_offsets);
     sset.add_service(&p);
 
     service_record *s2 = new service_record(&sset, "test-service-2", service_type_t::INTERNAL, {{&p, REG}});
-    service_record *s3 = new service_record(&sset, "test-service-3", service_type_t::INTERNAL, {{&p, REG}, {s2, REG}});
+    service_record *s3 = new service_record(&sset, "test-service-3",
+            service_type_t::INTERNAL, {{&p, REG}, {s2, REG}});
     sset.add_service(s2);
     sset.add_service(s3);
 
@@ -460,6 +699,9 @@ void test_scripted_start_fail()
     assert(p.get_state() == service_state_t::STOPPED);
     assert(s2->get_state() == service_state_t::STOPPED);
     assert(s3->get_state() == service_state_t::STOPPED);
+    assert(p.get_stop_reason() == stopped_reason_t::FAILED);
+    assert(s2->get_stop_reason() == stopped_reason_t::DEPFAILED);
+    assert(s3->get_stop_reason() == stopped_reason_t::DEPFAILED);
 
     event_loop.active_timers.clear();
     sset.remove_service(&p);
@@ -479,14 +721,16 @@ void test_scripted_stop_fail()
     command_offsets.emplace_back(0, command.length());
     std::list<prelim_dep> depends;
 
-    scripted_service p = scripted_service(&sset, "testscripted", std::move(command), command_offsets, depends);
+    scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
     init_service_defaults(p);
     p.set_stop_command(stopcommand, command_offsets);
     sset.add_service(&p);
 
     service_record *s2 = new service_record(&sset, "test-service-2", service_type_t::INTERNAL, {});
-    service_record *s3 = new service_record(&sset, "test-service-3", service_type_t::INTERNAL, {{s2, REG}, {&p, REG}});
-    service_record *s4 = new service_record(&sset, "test-service-4", service_type_t::INTERNAL, {{&p, REG}, {s3, REG}});
+    service_record *s3 = new service_record(&sset, "test-service-3", service_type_t::INTERNAL,
+            {{s2, REG}, {&p, REG}});
+    service_record *s4 = new service_record(&sset, "test-service-4", service_type_t::INTERNAL,
+            {{&p, REG}, {s3, REG}});
     sset.add_service(s2);
     sset.add_service(s3);
     sset.add_service(s4);
@@ -537,9 +781,9 @@ void test_scripted_start_skip()
     command_offsets.emplace_back(0, command.length());
     std::list<prelim_dep> depends;
 
-    scripted_service p = scripted_service(&sset, "testscripted", std::move(command), command_offsets, depends);
+    scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
     init_service_defaults(p);
-    onstart_flags_t sflags;
+    service_flags_t sflags;
     sflags.skippable = true;
     p.set_flags(sflags);
     sset.add_service(&p);
@@ -569,6 +813,8 @@ void test_scripted_start_skip()
 
     assert(p.get_state() == service_state_t::STOPPED);
     assert(s2->get_state() == service_state_t::STOPPED);
+    assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
+    assert(s2->get_stop_reason() == stopped_reason_t::NORMAL);
     assert(sset.count_active_services() == 0);
 
     event_loop.active_timers.clear();
@@ -587,12 +833,12 @@ void test_scripted_start_skip2()
     command_offsets.emplace_back(0, command.length());
     std::list<prelim_dep> depends;
 
-    scripted_service p = scripted_service(&sset, "testscripted", std::move(command), command_offsets, depends);
+    scripted_service p {&sset, "testscripted", std::move(command), command_offsets, depends};
     init_service_defaults(p);
-    onstart_flags_t sflags;
+    service_flags_t sflags;
     sflags.skippable = true;
+    sflags.start_interruptible = true;
     p.set_flags(sflags);
-    p.set_start_interruptible(true);
     sset.add_service(&p);
 
     service_record *s2 = new service_record(&sset, "test-service-2", service_type_t::INTERNAL, {{&p, REG}});
@@ -616,24 +862,96 @@ void test_scripted_start_skip2()
 
     assert(p.get_state() == service_state_t::STOPPED);
     assert(s2->get_state() == service_state_t::STOPPED);
+    assert(p.get_stop_reason() == stopped_reason_t::NORMAL);
+    assert(s2->get_stop_reason() == stopped_reason_t::NORMAL);
     assert(sset.count_active_services() == 0);
 
     event_loop.active_timers.clear();
     sset.remove_service(&p);
 }
 
+// Test that starting a service with a waits-for dependency on another - currently stopping - service,
+// causes that service to re-start.
+void test_waitsfor_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);
+    sset.add_service(&p);
+
+    service_record tp {&sset, "test-service", service_type_t::INTERNAL, {{&p, WAITS}}};
+    sset.add_service(&tp);
+
+    // start p:
+
+    p.start(true);
+    sset.process_queues();
+
+    assert(p.get_state() == service_state_t::STARTING);
+
+    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);
+
+    // begin stopping p:
+
+    p.stop(true);
+    sset.process_queues();
+
+    assert(p.get_state() == service_state_t::STOPPING);
+
+    // start tp (which waits-for p):
+
+    tp.start(true);
+    sset.process_queues();
+
+    assert(tp.get_state() == service_state_t::STARTING);
+    assert(p.get_state() == service_state_t::STOPPING);
+
+    base_process_service_test::handle_signal_exit(&p, SIGTERM);
+    sset.process_queues();
+
+    assert(tp.get_state() == service_state_t::STARTING);
+    assert(p.get_state() == service_state_t::STARTING);
+
+    base_process_service_test::exec_succeeded(&p);
+    sset.process_queues();
+
+    assert(tp.get_state() == service_state_t::STARTED);
+    assert(p.get_state() == service_state_t::STARTED);
+
+    sset.remove_service(&tp);
+    sset.remove_service(&p);
+}
+
+
 #define RUN_TEST(name, spacing) \
-    std::cout << #name "..." spacing; \
+    std::cout << #name "..." spacing << std::flush; \
     name(); \
     std::cout << "PASSED" << std::endl;
 
 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, "   ");
     RUN_TEST(test_proc_start_timeout2, "  ");
+    RUN_TEST(test_proc_start_execfail, "  ");
+    RUN_TEST(test_proc_notify_fail, "     ");
     RUN_TEST(test_proc_stop_timeout, "    ");
     RUN_TEST(test_proc_smooth_recovery1, "");
     RUN_TEST(test_proc_smooth_recovery2, "");
@@ -642,4 +960,5 @@ int main(int argc, char **argv)
     RUN_TEST(test_scripted_stop_fail, "   ");
     RUN_TEST(test_scripted_start_skip, "  ");
     RUN_TEST(test_scripted_start_skip2, " ");
+    RUN_TEST(test_waitsfor_restart, "     ");
 }