Tests: add test for readiness notification via pipe.
authorDavin McCall <davmac@davmac.org>
Fri, 16 Nov 2018 18:30:41 +0000 (18:30 +0000)
committerDavin McCall <davmac@davmac.org>
Fri, 16 Nov 2018 19:54:23 +0000 (19:54 +0000)
src/tests/proctests.cc
src/tests/test-includes/dinit.h

index 1f61cf280fd997019299d4d30468fea6d6450da3..c3d245c884a6d6cbf82b80c4fdebc95821864c9c 100644 (file)
@@ -44,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 {
@@ -89,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()
 {
@@ -267,7 +315,8 @@ void test_proc_start_timeout2()
     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();
@@ -322,7 +371,6 @@ void test_proc_start_execfail()
     sset.remove_service(&p);
 }
 
-
 // Test stop timeout
 void test_proc_stop_timeout()
 {
@@ -535,7 +583,8 @@ void test_scripted_start_fail()
     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);
 
@@ -581,8 +630,10 @@ void test_scripted_stop_fail()
     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);
@@ -795,6 +846,7 @@ void test_waitsfor_restart()
 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_term_via_stop, "        ");
     RUN_TEST(test_term_via_stop2, "       ");
index 55bda59cdf0be4ba002f13ef01c6e61bc7b3b487..14c1ee932c9437e553a72dbe8f55d0bb2b525725 100644 (file)
@@ -67,7 +67,12 @@ class eventloop_t
         public:
         void add_watch(eventloop_t &loop, int fd, int events, bool enable = true)
         {
+            if (loop.regd_fd_watchers.find(fd) != loop.regd_fd_watchers.end()
+                    || loop.regd_bidi_watchers.find(fd) != loop.regd_bidi_watchers.end()) {
+                throw std::string("must not add_watch when already active");
+            }
             watched_fd = fd;
+            loop.regd_fd_watchers[fd] = this;
         }
 
         int get_watched_fd() noexcept
@@ -82,8 +87,11 @@ class eventloop_t
 
         void deregister(eventloop_t &loop) noexcept
         {
-
+            loop.regd_fd_watchers.erase(watched_fd);
+            watched_fd = -1;
         }
+
+        virtual rearm fd_event(eventloop_t & loop, int fd, int flags) = 0;
     };
 
     template <typename Derived> class fd_watcher_impl : public fd_watcher
@@ -163,6 +171,7 @@ class eventloop_t
 
     std::unordered_set<timer *> active_timers;
        std::map<int, bidi_fd_watcher *> regd_bidi_watchers;
+       std::map<int, fd_watcher *> regd_fd_watchers;
 };
 
 inline void open_control_socket(bool report_ro_failure = true) noexcept