From f70495a48646e54272783b4b709aca0396cb85f8 Mon Sep 17 00:00:00 2001 From: Joel Klinghed Date: Fri, 26 Nov 2021 08:19:58 +0100 Subject: Create daemon module and use it from server Need to run setup() after forking, otherwise each TaskRunner created in setup() will dead-lock at exit as there are now two copies of each of them but not of the threads causing the destructors to lock. This made setup a little bit more complicated as it has to forward the log and status to parent process but I turned out quite nice. --- test/test_daemon.cc | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 test/test_daemon.cc (limited to 'test/test_daemon.cc') diff --git a/test/test_daemon.cc b/test/test_daemon.cc new file mode 100644 index 0000000..04ba105 --- /dev/null +++ b/test/test_daemon.cc @@ -0,0 +1,146 @@ +#include "common.hh" + +#include "daemon.hh" +#include "logger.hh" + +#include +#include +#include + +namespace { + +class MockDaemon : public Daemon { +public: + MOCK_METHOD(bool, setup, (Logger*), (override)); + MOCK_METHOD(bool, run, (), (override)); +}; + +class MockLogger : public Logger { +public: + void err(char const* format, ...) override { + va_list args; + va_start(args, format); + vlog("err", format, args); + va_end(args); + } + + void warn(char const* format, ...) override { + va_list args; + va_start(args, format); + vlog("warn", format, args); + va_end(args); + } + + void info(char const* format, ...) override { + va_list args; + va_start(args, format); + vlog("info", format, args); + va_end(args); + } + + void dbg(char const* format, ...) override { + va_list args; + va_start(args, format); + vlog("dbg", format, args); + va_end(args); + } + + void vlog(std::string level, char const* format, va_list args) { + if (strcmp(format, "%s") == 0) { + log(level, va_arg(args, char const*)); + } else if (strcmp(format, "%.*s") == 0) { + auto len = va_arg(args, int); + auto ptr = va_arg(args, char const*); + log(level, std::string(ptr, len)); + } else { + log(level, format); + } + } + + MOCK_METHOD(void, log, (std::string, std::string)); +}; + +class TestDaemon : public Daemon { +public: + bool setup(Logger*) override { + return false; + } + + bool run() override { + return false; + } +}; + +class FailSetupDaemon : public TestDaemon { +public: + explicit FailSetupDaemon(std::string error) + : error_(std::move(error)) {} + + bool setup(Logger* logger) override { + logger->err("%s", error_.c_str()); + return false; + } + +private: + std::string error_; +}; + +class SuccessSetupDaemon : public TestDaemon { +public: + explicit SuccessSetupDaemon(std::string success) + : success_(std::move(success)) {} + + bool setup(Logger* logger) override { + logger->info("%s", success_.c_str()); + return true; + } + +private: + std::string success_; +}; + +} // namespace + +TEST(daemon, run_in_foreground_setup_fail) { + auto daemon = std::make_unique(); + auto logger = Logger::create_null(); + EXPECT_CALL(*daemon, setup(logger.get())) + .WillOnce(testing::Return(false)); + EXPECT_FALSE(Daemon::run_in_foreground(logger.get(), std::move(daemon))); +} + +TEST(daemon, run_in_foreground_run_fail) { + auto daemon = std::make_unique(); + auto logger = Logger::create_null(); + EXPECT_CALL(*daemon, setup(logger.get())) + .WillOnce(testing::Return(true)); + EXPECT_CALL(*daemon, run()) + .WillOnce(testing::Return(false)); + EXPECT_FALSE(Daemon::run_in_foreground(logger.get(), std::move(daemon))); +} + +TEST(daemon, run_in_foreground_run_success) { + auto daemon = std::make_unique(); + auto logger = Logger::create_null(); + EXPECT_CALL(*daemon, setup(logger.get())) + .WillOnce(testing::Return(true)); + EXPECT_CALL(*daemon, run()) + .WillOnce(testing::Return(true)); + EXPECT_TRUE(Daemon::run_in_foreground(logger.get(), std::move(daemon))); +} + +TEST(daemon, fork_in_background_setup_fail) { + auto daemon = std::make_unique("Something failed"); + MockLogger logger; + testing::Mock::AllowLeak(&logger); // Forking copies the mock. + EXPECT_CALL(logger, log("err", "Something failed")); + EXPECT_FALSE(Daemon::fork_in_background(&logger, std::move(daemon))); +} + +TEST(daemon, fork_in_background_run_fail) { + auto daemon = std::make_unique("All good"); + MockLogger logger; + testing::Mock::AllowLeak(&logger); // Forking copies the mock. + EXPECT_CALL(logger, log("info", "All good")); + EXPECT_TRUE(Daemon::fork_in_background(&logger, std::move(daemon))); +} -- cgit v1.2.3-70-g09d2