Beginnings of automated test suite.
authorDavin McCall <davmac@davmac.org>
Fri, 16 Jun 2017 19:48:35 +0000 (20:48 +0100)
committerDavin McCall <davmac@davmac.org>
Fri, 16 Jun 2017 19:48:35 +0000 (20:48 +0100)
src/Makefile
src/dinit-main.cc [new file with mode: 0644]
src/dinit.cc
src/service.h
src/tests/Makefile [new file with mode: 0644]
src/tests/tests.cc [new file with mode: 0644]

index a30e3a848f8023b7da574e613e7a4ba1d5c18369..338deb29882d7600f06863e6f1b57b30de8fec6b 100644 (file)
@@ -4,9 +4,9 @@ ifeq ($(BUILD_SHUTDOWN),yes)
   SHUTDOWN=shutdown
 endif
 
-objects = dinit.o load_service.o service.o control.o dinit-log.o dinitctl.o shutdown.o
+objects = dinit.o load_service.o service.o control.o dinit-log.o dinit-main.o dinitctl.o shutdown.o
 
-dinit_objects = dinit.o load_service.o service.o control.o dinit-log.o
+dinit_objects = dinit.o load_service.o service.o control.o dinit-log.o dinit-main.o
 
 all: dinit dinitctl $(SHUTDOWN)
 
diff --git a/src/dinit-main.cc b/src/dinit-main.cc
new file mode 100644 (file)
index 0000000..4e67a1a
--- /dev/null
@@ -0,0 +1,24 @@
+#include <iostream>
+
+// Entry point for Dinit.
+
+int dinit_main(int argc, char **argv);
+
+int main(int argc, char **argv)
+{
+    try {
+        return dinit_main(argc, argv);
+    }
+    catch (std::bad_alloc &badalloc) {
+        std::cout << "dinit: Out-of-memory during initialisation" << std::endl;
+        return 1;
+    }
+    catch (std::system_error &syserr) {
+        std::cout << "dinit: unexpected system error during initialisation: " << syserr.what() << std::endl;
+        return 1;
+    }
+    catch (...) {
+        std::cout << "dinit: unexpected error during initialisation" << std::endl;
+        return 1;
+    }
+}
index d7221ea1cef32b0a4b119a8d58bec5510238d5d7..7d3c2fd0a38fb19c00d0df481d3153fb7101a95e 100644 (file)
@@ -130,7 +130,7 @@ namespace {
     control_socket_watcher control_socket_io;
 }
 
-static int dinit_main(int argc, char **argv)
+int dinit_main(int argc, char **argv)
 {
     using namespace std;
     
@@ -407,25 +407,6 @@ static int dinit_main(int argc, char **argv)
     return 0;
 }
 
-int main(int argc, char **argv)
-{
-    try {
-        return dinit_main(argc, argv);
-    }
-    catch (std::bad_alloc &badalloc) {
-        std::cout << "dinit: Out-of-memory during initialisation" << std::endl;
-        return 1;
-    }
-    catch (std::system_error &syserr) {
-        std::cout << "dinit: unexpected system error during initialisation: " << syserr.what() << std::endl;
-        return 1;
-    }
-    catch (...) {
-        std::cout << "dinit: unexpected error during initialisation" << std::endl;
-        return 1;
-    }
-}
-
 // In exception situations we want user confirmation before proceeding (eg on critical boot failure
 // we wait before rebooting to avoid a reboot loop).
 static void wait_for_user_input() noexcept
index 0ee545dc584b460bd18f23679c0f0006b4057840..ee6a304576c4af19bb389480513b872e1b3c5d4b 100644 (file)
@@ -783,13 +783,20 @@ class service_set
         restart_enabled = true;
     }
     
-    // Start the specified service
+    // Start the specified service. The service will be marked active.
     void start_service(service_record *svc)
     {
         svc->start();
         processQueues();
     }
 
+    // Stop the specified service. Its active mark will be cleared.
+    void stop_service(service_record *svc)
+    {
+        svc->stop();
+        processQueues();
+    }
+
     // Locate an existing service record.
     service_record *find_service(const std::string &name) noexcept;
 
diff --git a/src/tests/Makefile b/src/tests/Makefile
new file mode 100644 (file)
index 0000000..5e12ac0
--- /dev/null
@@ -0,0 +1,20 @@
+-include ../../mconfig
+
+objects = tests.o
+parent_objs = ../service.o ../control.o ../dinit-log.o ../load_service.o ../dinit.o
+
+build-tests: tests
+
+tests: $(objects)
+       $(CXX) -o tests tests.o $(parent_objs) $(EXTRA_LIBS)
+
+$(objects): %.o: %.cc
+       $(CXX) $(CXXOPTS) -I.. -I../dasynq -c $< -o $@
+
+clean:
+       rm -f *.o
+
+$(objects:.o=.d): %.d: %.cc
+       $(CXX) $(CXXOPTS) -I.. -I../dasynq -MM -MG -MF $@ $<
+
+include $(objects:.o=.d)
diff --git a/src/tests/tests.cc b/src/tests/tests.cc
new file mode 100644 (file)
index 0000000..93e701b
--- /dev/null
@@ -0,0 +1,78 @@
+#include <cassert>
+#include "service.h"
+
+void test1()
+{
+    service_set sset;
+
+    service_record *s1 = new service_record(&sset, "test-service-1", service_type::INTERNAL, {}, {});
+    service_record *s2 = new service_record(&sset, "test-service-2", service_type::INTERNAL, {s1}, {});
+    service_record *s3 = new service_record(&sset, "test-service-3", service_type::INTERNAL, {s2}, {});
+    sset.add_service(s1);
+    sset.add_service(s2);
+    sset.add_service(s3);
+
+    assert(sset.find_service("test-service-1") == s1);
+    assert(sset.find_service("test-service-2") == s2);
+    assert(sset.find_service("test-service-3") == s3);
+
+    // s3 depends on s2, which depends on s1. So starting s3 should start all three services:
+    sset.start_service(s3);
+
+    assert(s1->getState() == service_state_t::STARTED);
+    assert(s2->getState() == service_state_t::STARTED);
+    assert(s3->getState() == service_state_t::STARTED);
+
+    // stopping s3 should release the other two services:
+    sset.stop_service(s3);
+
+    assert(s3->getState() == service_state_t::STOPPED);
+    assert(s2->getState() == service_state_t::STOPPED);
+    assert(s1->getState() == service_state_t::STOPPED);
+}
+
+void test2()
+{
+    service_set sset;
+
+    service_record *s1 = new service_record(&sset, "test-service-1", service_type::INTERNAL, {}, {});
+    service_record *s2 = new service_record(&sset, "test-service-2", service_type::INTERNAL, {s1}, {});
+    service_record *s3 = new service_record(&sset, "test-service-3", service_type::INTERNAL, {s2}, {});
+    service_record *s4 = new service_record(&sset, "test-service-4", service_type::INTERNAL, {s2}, {});
+    sset.add_service(s1);
+    sset.add_service(s2);
+    sset.add_service(s3);
+    sset.add_service(s4);
+
+    // s3 depends on s2, which depends on s1. Similarly with s4. After starting both, all services
+    // should be started:
+    sset.start_service(s3);
+    sset.start_service(s4);
+
+    assert(s1->getState() == service_state_t::STARTED);
+    assert(s2->getState() == service_state_t::STARTED);
+    assert(s3->getState() == service_state_t::STARTED);
+    assert(s4->getState() == service_state_t::STARTED);
+
+    // after stopping s3, s4 should hold the other two services:
+    sset.stop_service(s3);
+
+    assert(s4->getState() == service_state_t::STARTED);
+    assert(s3->getState() == service_state_t::STOPPED);
+    assert(s2->getState() == service_state_t::STARTED);
+    assert(s1->getState() == service_state_t::STARTED);
+
+    // Now if we stop s4, s2 and s1 should also be released:
+    sset.stop_service(s4);
+
+    assert(s4->getState() == service_state_t::STOPPED);
+    assert(s3->getState() == service_state_t::STOPPED);
+    assert(s2->getState() == service_state_t::STOPPED);
+    assert(s1->getState() == service_state_t::STOPPED);
+}
+
+int main(int argc, char **argv)
+{
+    test1();
+    test2();
+}