Browse Source

Igr: convert restart test to run via igr-runner

Davin McCall 1 month ago
parent
commit
0a44d89ee1
2 changed files with 62 additions and 2 deletions
  1. 33 1
      src/igr-tests/igr-runner.cc
  2. 29 1
      src/igr-tests/igr.h

+ 33 - 1
src/igr-tests/igr-runner.cc

@@ -23,11 +23,12 @@ void environ2_test();
 void ps_environ_test();
 void chain_to_test();
 void force_stop_test();
+void restart_test();
 
 int main(int argc, char **argv)
 {
     void (*test_funcs[])() = { basic_test, environ_test, environ2_test, ps_environ_test, chain_to_test,
-            force_stop_test };
+            force_stop_test, restart_test };
     const char * const test_dirs[] = { "basic", "environ", "environ2", "ps-environ", "chain-to", "force-stop",
             "restart", "check-basic", "check-cycle", "check-cycle2", "check-lint", "reload1", "reload2",
             "no-command-error", "add-rm-dep", "var-subst", "svc-start-fail", "dep-not-found", "pseudo-cycle",
@@ -331,3 +332,34 @@ void force_stop_test()
     // dinit should stop since all services are now stopped
     dinit_p.wait_for_term({1, 0});
 }
+
+void restart_test()
+{
+    igr_test_setup setup("restart");
+    std::string output_file = setup.prep_output_file("basic-ran");
+
+    dinit_proc dinit_p;
+    dinit_p.start("restart", {"-u", "-d", "sd", "-p", igr_dinit_socket_path, "-q"}, true);
+
+    // "dinitctl start boot" - wait until "boot" has fully started:
+    dinitctl_proc dinitctl_p;
+    dinitctl_p.start("restart", {"-p", igr_dinit_socket_path, "start", "boot"});
+    dinitctl_p.wait_for_term({1, 0}  /* max 1 second */);
+
+    // "basic" is a process service. It has started, but we need to give it a little time to
+    // write its output:
+    nanosleepx(0, 1000000000u / 10u);
+
+    igr_assert_eq("ran\n", read_file_contents(output_file));
+    if (unlink(output_file.c_str()) == -1) {
+        throw std::system_error(errno, std::generic_category(), "unlink");
+    }
+
+    // "dinitctl restart basic"
+    dinitctl_p.start("restart", {"-p", igr_dinit_socket_path, "restart", "basic"});
+    dinitctl_p.wait_for_term({1, 0}  /* max 1 second */);
+
+    nanosleepx(0, 1000000000u / 10u);
+
+    igr_assert_eq("ran\n", read_file_contents(output_file));
+}

+ 29 - 1
src/igr-tests/igr.h

@@ -233,6 +233,11 @@ public:
     {
         return err.get_output();
     }
+
+    void signal(int signo)
+    {
+        pwatch.send_signal(event_loop, signo);
+    }
 };
 
 // dinit process
@@ -242,7 +247,19 @@ class dinit_proc : public igr_proc
 
 public:
     dinit_proc() {}
-    ~dinit_proc() {}
+
+    ~dinit_proc() {
+        // Signal (if not yet terminated) and allow a second for termination
+        igr_proc::signal(SIGTERM);
+        try {
+            wait_for_term({1, 0});
+        }
+        catch (igr_failure_exc &exc) {
+            // timeout, but
+            // a) we are in destructor and shouldn't throw
+            // b) this isn't critical, the process will be KILL'd anyway
+        }
+    }
 
     void start(const char *wdir, std::vector<std::string> args = {}, bool with_ready_wait = false)
     {
@@ -407,3 +424,14 @@ inline void igr_assert_eq(const std::string &expected, const std::string &actual
         throw igr_failure_exc(std::string("Test assertion failed:\n") + "Expected: " + expected + "\nActual: " + actual);
     }
 }
+
+inline void nanosleepx(decltype(std::declval<timespec>().tv_sec) seconds,
+        decltype(std::declval<timespec>().tv_nsec) nanoseconds)
+{
+    timespec sleep_time;
+    sleep_time.tv_sec = 0;
+    sleep_time.tv_nsec = 1000000000 / 10;  // .1 seconds
+    if (nanosleep(&sleep_time, nullptr) == -1) {
+        throw std::system_error(errno, std::generic_category(), "nanosleep");
+    }
+}