-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This daemon handler class will manage the daemons we configure (start, stop, reload etc) using dbus (or any other message bus, such as the test one, to allow easy mocking) We also add a test message bus to test this daemon handler
- Loading branch information
Showing
4 changed files
with
246 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
#pragma once | ||
|
||
#include <memory> | ||
#include <string> | ||
|
||
#include <cloysterhpc/messagebus.h> | ||
|
||
class DaemonHandler { | ||
private: | ||
std::shared_ptr<MessageBus> m_bus; | ||
const std::string m_name; | ||
|
||
template <typename... Ts> | ||
sdbus::ObjectPath callObjectFunction( | ||
const std::string function, Ts... params) | ||
{ | ||
MessageReply reply | ||
= m_bus->method("org.freedesktop.systemd1.Manager", function) | ||
->call(m_name, params...); | ||
return reply.get<sdbus::ObjectPath>(); | ||
} | ||
|
||
static std::string fixServiceName(std::string name); | ||
|
||
public: | ||
DaemonHandler(std::shared_ptr<MessageBus> bus, const std::string name) | ||
: m_bus(bus) | ||
, m_name(DaemonHandler::fixServiceName(name)) | ||
{ | ||
} | ||
|
||
static void daemonReload(MessageBus& bus); | ||
|
||
bool exists(); | ||
|
||
void load(); | ||
void start(); | ||
void stop(); | ||
void restart(); | ||
void enable(); | ||
void disable(); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
#pragma once | ||
|
||
#include <cloysterhpc/messagebus.h> | ||
#include <any> | ||
#include <tuple> | ||
#include <vector> | ||
#include <string> | ||
|
||
class TestMessageMethod; | ||
|
||
using FunctionStore = std::tuple<std::string, std::string>; | ||
using FunctionParameters = std::vector<std::any>; | ||
|
||
class TestMessageBus : public MessageBus { | ||
friend class TestMessageMethod; | ||
|
||
private: | ||
std::unordered_map<std::string, std::vector<FunctionParameters>> m_functions; | ||
|
||
std::string makeStoreName(FunctionStore s) const { | ||
return std::get<0>(s) + "->" + std::get<1>(s); | ||
} | ||
|
||
void registerCall(FunctionStore s, FunctionParameters p) { | ||
auto count = this->callCount(s); | ||
m_functions[makeStoreName(s)].push_back(p); | ||
} | ||
|
||
public: | ||
std::unique_ptr<MessageBusMethod> method(std::string interface, | ||
std::string method); | ||
|
||
void dump() const; | ||
|
||
unsigned callCount(FunctionStore s) const; | ||
FunctionParameters calledWith(FunctionStore s, unsigned index) const; | ||
}; | ||
|
||
class TestMessageMethod : public MessageBusMethod { | ||
private: | ||
TestMessageBus *m_bus; | ||
FunctionStore m_store; | ||
FunctionParameters m_params = {}; | ||
|
||
protected: | ||
virtual void pushSingleParam(MethodParamVariant param) { | ||
std::visit([this](auto &&arg) { this->m_params.push_back(arg); }, param); | ||
} | ||
virtual MessageReply callMethod(); | ||
|
||
public: | ||
TestMessageMethod(TestMessageBus *bus, FunctionStore s) | ||
: m_bus(bus), m_store(s) {} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
#include <cloysterhpc/daemon_handler.h> | ||
|
||
std::string DaemonHandler::fixServiceName(std::string name) | ||
{ | ||
if (!name.ends_with(".service")) { | ||
return name + ".service"; | ||
} else { | ||
return name; | ||
} | ||
} | ||
|
||
bool DaemonHandler::exists() | ||
{ | ||
auto path = this->callObjectFunction("GetUnit"); | ||
return path.size() > 0; | ||
} | ||
|
||
void DaemonHandler::start() | ||
{ | ||
this->callObjectFunction("StartUnit", "replace"); | ||
} | ||
|
||
void DaemonHandler::stop() { this->callObjectFunction("StopUnit", "replace"); } | ||
|
||
void DaemonHandler::load() { this->callObjectFunction("LoadUnit"); } | ||
|
||
void DaemonHandler::restart() | ||
{ | ||
this->callObjectFunction("RestartUnit", "replace"); | ||
} | ||
|
||
void DaemonHandler::daemonReload(MessageBus& bus) | ||
{ | ||
bus.method("org.freedesktop.systemd1.Manager", "Reload")->call(); | ||
} | ||
|
||
#ifdef BUILD_TESTING | ||
#include <doctest/doctest.h> | ||
#else | ||
#define DOCTEST_CONFIG_DISABLE | ||
#include <doctest/doctest.h> | ||
#endif | ||
|
||
#include <testing/test_message_bus.h> | ||
|
||
TEST_SUITE("Test service handler connectivity") | ||
{ | ||
TEST_CASE("Service handler testing") | ||
{ | ||
auto testBus = std::make_shared<TestMessageBus>(); | ||
|
||
DaemonHandler sr { testBus, "generic-service" }; | ||
|
||
SUBCASE("it can start") | ||
{ | ||
auto function = std::make_tuple<std::string, std::string>( | ||
"org.freedesktop.systemd1.Manager", "StartUnit"); | ||
|
||
REQUIRE(testBus->callCount(function) == 0); | ||
sr.start(); | ||
|
||
REQUIRE(testBus->callCount(function) == 1); | ||
auto params = testBus->calledWith(function, 0); | ||
CHECK(std::any_cast<std::string>(params[0]) | ||
== "generic-service.service"); | ||
} | ||
|
||
SUBCASE("it can stop") | ||
{ | ||
auto function = std::make_tuple<std::string, std::string>( | ||
"org.freedesktop.systemd1.Manager", "StopUnit"); | ||
|
||
REQUIRE(testBus->callCount(function) == 0); | ||
sr.stop(); | ||
|
||
REQUIRE(testBus->callCount(function) == 1); | ||
auto params = testBus->calledWith(function, 0); | ||
CHECK(std::any_cast<std::string>(params[0]) | ||
== "generic-service.service"); | ||
} | ||
|
||
SUBCASE("it can restart") | ||
{ | ||
auto function = std::make_tuple<std::string, std::string>( | ||
"org.freedesktop.systemd1.Manager", "RestartUnit"); | ||
|
||
REQUIRE(testBus->callCount(function) == 0); | ||
sr.restart(); | ||
|
||
REQUIRE(testBus->callCount(function) == 1); | ||
auto params = testBus->calledWith(function, 0); | ||
CHECK(std::any_cast<std::string>(params[0]) | ||
== "generic-service.service"); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
#include <cstdio> | ||
#include <testing/test_message_bus.h> | ||
|
||
unsigned TestMessageBus::callCount(FunctionStore s) const | ||
{ | ||
auto sname = makeStoreName(s); | ||
if (!m_functions.contains(sname)) { | ||
return 0; | ||
} else { | ||
return m_functions.at(sname).size(); | ||
} | ||
} | ||
|
||
FunctionParameters TestMessageBus::calledWith( | ||
FunctionStore s, unsigned index) const | ||
{ | ||
if (this->callCount(s) == 0 || index >= this->callCount(s)) { | ||
return {}; | ||
} | ||
|
||
auto sname = makeStoreName(s); | ||
return m_functions.at(sname).at(index); | ||
} | ||
|
||
void TestMessageBus::dump() const | ||
{ | ||
fprintf(stderr, "???\n"); | ||
for (const auto& [k, paramslist] : m_functions) { | ||
fprintf(stderr, "\t%s: %ld calls\n", k.c_str(), paramslist.size()); | ||
int i = 0; | ||
for (const auto& params : paramslist) { | ||
fprintf(stderr, "\t\t%d: ", i++); | ||
for (const auto& p : params) { | ||
fprintf(stderr, "<%s> ", p.type().name()); | ||
} | ||
fprintf(stderr, "\n"); | ||
} | ||
} | ||
} | ||
|
||
std::unique_ptr<MessageBusMethod> TestMessageBus::method( | ||
std::string interface, std::string method) | ||
{ | ||
auto store = std::make_tuple(interface, method); | ||
return std::unique_ptr<MessageBusMethod>( | ||
new TestMessageMethod { this, store }); | ||
} | ||
|
||
MessageReply TestMessageMethod::callMethod() | ||
{ | ||
m_bus->registerCall(m_store, m_params); | ||
return MessageReply( | ||
std::make_any<sdbus::ObjectPath>(sdbus::ObjectPath("123"))); | ||
} |