From 41cefb9ccfeab5f506b0c21074a6850a77b70efb Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Fri, 16 Jun 2017 20:48:35 +0100 Subject: [PATCH] Beginnings of automated test suite. --- src/Makefile | 4 +-- src/dinit-main.cc | 24 ++++++++++++++ src/dinit.cc | 21 +------------ src/service.h | 9 +++++- src/tests/Makefile | 20 ++++++++++++ src/tests/tests.cc | 78 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 133 insertions(+), 23 deletions(-) create mode 100644 src/dinit-main.cc create mode 100644 src/tests/Makefile create mode 100644 src/tests/tests.cc diff --git a/src/Makefile b/src/Makefile index a30e3a8..338deb2 100644 --- a/src/Makefile +++ b/src/Makefile @@ -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 index 0000000..4e67a1a --- /dev/null +++ b/src/dinit-main.cc @@ -0,0 +1,24 @@ +#include + +// 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; + } +} diff --git a/src/dinit.cc b/src/dinit.cc index d7221ea..7d3c2fd 100644 --- a/src/dinit.cc +++ b/src/dinit.cc @@ -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 diff --git a/src/service.h b/src/service.h index 0ee545d..ee6a304 100644 --- a/src/service.h +++ b/src/service.h @@ -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 index 0000000..5e12ac0 --- /dev/null +++ b/src/tests/Makefile @@ -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 index 0000000..93e701b --- /dev/null +++ b/src/tests/tests.cc @@ -0,0 +1,78 @@ +#include +#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(); +} -- 2.25.1