tests: encapsulate RPC watcher into a class
Change-Id: I62e09cd4333717ce8941a2bcbe17298cc007f315
diff --git a/tests/health_systemd-units.cpp b/tests/health_systemd-units.cpp
index 8378550..1b18dba 100644
--- a/tests/health_systemd-units.cpp
+++ b/tests/health_systemd-units.cpp
@@ -15,55 +15,28 @@
#include "pretty_printers.h"
#include "test_log_setup.h"
#include "tests/sysrepo-helpers/common.h"
+#include "tests/sysrepo-helpers/rpc.h"
#include "utils/log-init.h"
#include "utils/log.h"
using namespace std::chrono_literals;
// clang-format off
-#define EXPECT_ALARM_RPC(RESOURCE, SEVERITY, TEXT) REQUIRE_CALL(fakeAlarmServer, rpcCalled(alarmRPC, std::map<std::string, std::string>{ \
- {"/sysrepo-ietf-alarms:create-or-update-alarm/alarm-text", TEXT}, \
- {"/sysrepo-ietf-alarms:create-or-update-alarm/alarm-type-id", "velia-alarms:systemd-unit-failure"}, \
- {"/sysrepo-ietf-alarms:create-or-update-alarm/alarm-type-qualifier", ""}, \
- {"/sysrepo-ietf-alarms:create-or-update-alarm/resource", RESOURCE}, \
- {"/sysrepo-ietf-alarms:create-or-update-alarm/severity", SEVERITY} \
+#define REQUIRE_ALARM_RPC(RESOURCE, SEVERITY, TEXT) REQUIRE_RPC_CALL(alarmRPC, (Values{ \
+ {"/sysrepo-ietf-alarms:create-or-update-alarm", "(unprintable)"}, \
+ {"/sysrepo-ietf-alarms:create-or-update-alarm/alarm-text", TEXT}, \
+ {"/sysrepo-ietf-alarms:create-or-update-alarm/alarm-type-id", "velia-alarms:systemd-unit-failure"}, \
+ {"/sysrepo-ietf-alarms:create-or-update-alarm/alarm-type-qualifier", ""}, \
+ {"/sysrepo-ietf-alarms:create-or-update-alarm/resource", RESOURCE}, \
+ {"/sysrepo-ietf-alarms:create-or-update-alarm/severity", SEVERITY} \
})).IN_SEQUENCE(seq1);
// clang-format on
-const auto alarmRPC = "/sysrepo-ietf-alarms:create-or-update-alarm";
-
-class FakeAlarmServerSysrepo {
-public:
- FakeAlarmServerSysrepo();
- MAKE_CONST_MOCK2(rpcCalled, void(std::string_view, const std::map<std::string, std::string>&));
-
-private:
- sysrepo::Session m_srSess;
- std::optional<sysrepo::Subscription> m_srSub;
-};
-
-
-FakeAlarmServerSysrepo::FakeAlarmServerSysrepo()
- : m_srSess(sysrepo::Connection{}.sessionStart())
-{
- m_srSub = m_srSess.onRPCAction(alarmRPC, [&](auto, auto, std::string_view path, const libyang::DataNode input, auto, auto, auto) {
- std::map<std::string, std::string> in;
-
- for (auto n : input.childrenDfs()) {
- if (n.isTerm()) {
- in[n.path()] = n.asTerm().valueStr();
- }
- }
-
- rpcCalled(path, in);
- return sysrepo::ErrorCode::Ok;
- });
-}
-
TEST_CASE("systemd unit state monitoring (alarms)")
{
TEST_INIT_LOGS;
TEST_SYSREPO_INIT;
+ TEST_SYSREPO_INIT_CLIENT;
trompeloeil::sequence seq1;
// Create and setup separate connections for both client and server to simulate real-world server-client architecture.
@@ -74,19 +47,17 @@
serverConnection->enterEventLoopAsync();
auto server = DbusSystemdServer(*serverConnection);
- FakeAlarmServerSysrepo fakeAlarmServer;
+ RPCWatcher alarmRPC(client, "/sysrepo-ietf-alarms:create-or-update-alarm");
- EXPECT_ALARM_RPC("unit1.service", "cleared", "systemd unit state: (active, running)");
+ REQUIRE_ALARM_RPC("unit1.service", "cleared", "systemd unit state: (active, running)");
server.createUnit(*serverConnection, "unit1.service", "/org/freedesktop/systemd1/unit/unit1", "active", "running");
- EXPECT_ALARM_RPC("unit2.service", "critical", "systemd unit state: (activating, auto-restart)");
+ REQUIRE_ALARM_RPC("unit2.service", "critical", "systemd unit state: (activating, auto-restart)");
server.createUnit(*serverConnection, "unit2.service", "/org/freedesktop/systemd1/unit/unit2", "activating", "auto-restart");
- EXPECT_ALARM_RPC("unit3.service", "critical", "systemd unit state: (failed, failed)");
+ REQUIRE_ALARM_RPC("unit3.service", "critical", "systemd unit state: (failed, failed)");
server.createUnit(*serverConnection, "unit3.service", "/org/freedesktop/systemd1/unit/unit3", "failed", "failed");
auto systemdAlarms = std::make_shared<velia::health::SystemdUnits>(srSess, *clientConnection, serverConnection->getUniqueName(), "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "org.freedesktop.systemd1.Unit");
- waitForCompletionAndBitMore(seq1);
- // clang-format off
REQUIRE(dataFromSysrepo(srSess, "/ietf-alarms:alarms/alarm-inventory", sysrepo::Datastore::Operational) == std::map<std::string, std::string>{
{"/alarm-type[alarm-type-id='velia-alarms:systemd-unit-failure'][alarm-type-qualifier='']", ""},
{"/alarm-type[alarm-type-id='velia-alarms:systemd-unit-failure'][alarm-type-qualifier='']/alarm-type-id", "velia-alarms:systemd-unit-failure"},
@@ -100,15 +71,15 @@
});
// clang-format on
- EXPECT_ALARM_RPC("unit2.service", "cleared", "systemd unit state: (active, running)");
- EXPECT_ALARM_RPC("unit3.service", "cleared", "systemd unit state: (active, running)");
- EXPECT_ALARM_RPC("unit4.service", "critical", "systemd unit state: (failed, failed)");
- EXPECT_ALARM_RPC("unit3.service", "critical", "systemd unit state: (activating, auto-restart)");
- EXPECT_ALARM_RPC("unit3.service", "cleared", "systemd unit state: (active, running)");
- EXPECT_ALARM_RPC("unit3.service", "critical", "systemd unit state: (failed, failed)");
- EXPECT_ALARM_RPC("unit3.service", "critical", "systemd unit state: (activating, auto-restart)");
- EXPECT_ALARM_RPC("unit3.service", "cleared", "systemd unit state: (active, running)");
- EXPECT_ALARM_RPC("unit4.service", "cleared", "systemd unit state: (active, running)");
+ REQUIRE_ALARM_RPC("unit2.service", "cleared", "systemd unit state: (active, running)");
+ REQUIRE_ALARM_RPC("unit3.service", "cleared", "systemd unit state: (active, running)");
+ REQUIRE_ALARM_RPC("unit4.service", "critical", "systemd unit state: (failed, failed)");
+ REQUIRE_ALARM_RPC("unit3.service", "critical", "systemd unit state: (activating, auto-restart)");
+ REQUIRE_ALARM_RPC("unit3.service", "cleared", "systemd unit state: (active, running)");
+ REQUIRE_ALARM_RPC("unit3.service", "critical", "systemd unit state: (failed, failed)");
+ REQUIRE_ALARM_RPC("unit3.service", "critical", "systemd unit state: (activating, auto-restart)");
+ REQUIRE_ALARM_RPC("unit3.service", "cleared", "systemd unit state: (active, running)");
+ REQUIRE_ALARM_RPC("unit4.service", "cleared", "systemd unit state: (active, running)");
std::thread systemdSimulator([&] {
server.changeUnitState("/org/freedesktop/systemd1/unit/unit2", "active", "running");
diff --git a/tests/sysrepo-helpers/rpc.cpp b/tests/sysrepo-helpers/rpc.cpp
new file mode 100644
index 0000000..eb32038
--- /dev/null
+++ b/tests/sysrepo-helpers/rpc.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2024 CESNET, https://photonics.cesnet.cz/
+ *
+ * Written by Tomáš Pecka <tomas.pecka@cesnet.cz>
+ *
+ */
+
+#include "rpc.h"
+#include "sysrepo-helpers/common.h"
+
+RPCWatcher::RPCWatcher(sysrepo::Session& session, const std::string& xpath)
+ : m_sub(session.onRPCAction(xpath, [&](auto, auto, auto, const libyang::DataNode input, auto, auto, auto) {
+ std::map<std::string, std::string> in;
+
+ for (auto n : input.childrenDfs()) {
+ in.emplace(n.path(), nodeAsString(n));
+ }
+
+ rpc(in);
+ return sysrepo::ErrorCode::Ok;
+ }))
+{
+}
diff --git a/tests/sysrepo-helpers/rpc.h b/tests/sysrepo-helpers/rpc.h
new file mode 100644
index 0000000..2ea3045
--- /dev/null
+++ b/tests/sysrepo-helpers/rpc.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 CESNET, https://photonics.cesnet.cz/
+ *
+ * Written by Tomáš Pecka <tomas.pecka@cesnet.cz>
+ *
+ */
+
+#pragma once
+
+#include "trompeloeil_doctest.h"
+#include <sysrepo-cpp/Subscription.hpp>
+#include "sysrepo-helpers/common.h"
+#include "test_log_setup.h"
+
+/** @brief Watch for a given RPC */
+struct RPCWatcher {
+ RPCWatcher(sysrepo::Session& session, const std::string& xpath);
+ MAKE_MOCK1(rpc, void(const Values&));
+
+private:
+ sysrepo::Subscription m_sub;
+};
+
+#define REQUIRE_RPC_CALL(WATCHER, VALUES) REQUIRE_CALL(WATCHER, rpc(VALUES))
diff --git a/tests/sysrepo_ietf-hardware.cpp b/tests/sysrepo_ietf-hardware.cpp
index 2888716..4bb3ecc 100644
--- a/tests/sysrepo_ietf-hardware.cpp
+++ b/tests/sysrepo_ietf-hardware.cpp
@@ -7,15 +7,12 @@
#include "mock/ietf_hardware.h"
#include "pretty_printers.h"
#include "sysrepo-helpers/datastore.h"
+#include "sysrepo-helpers/rpc.h"
#include "test_log_setup.h"
#include "tests/sysrepo-helpers/common.h"
using namespace std::literals;
-struct AlarmEvent {
- MAKE_CONST_MOCK1(event, void(const std::map<std::string, std::string>&));
-};
-
struct AlarmInventory {
std::map<std::pair<std::string, std::string>, std::vector<std::string>> inventory;
@@ -48,7 +45,7 @@
.LR_SIDE_EFFECT(alarmInventory.add(ALARM_TYPE, "", COMPONENT(IETF_HARDWARE_RESOURCE)))
#define REQUIRE_ALARM_RPC(ALARM_TYPE_ID, IETF_HARDWARE_RESOURCE_KEY, SEVERITY, TEXT) \
- REQUIRE_CALL(alarmEvents, event(std::map<std::string, std::string>{ \
+ REQUIRE_RPC_CALL(alarmEvents, (Values{ \
{"/sysrepo-ietf-alarms:create-or-update-alarm", "(unprintable)"}, \
{"/sysrepo-ietf-alarms:create-or-update-alarm/alarm-text", TEXT}, \
{"/sysrepo-ietf-alarms:create-or-update-alarm/alarm-type-id", ALARM_TYPE_ID}, \
@@ -72,22 +69,10 @@
client.switchDatastore(sysrepo::Datastore::Operational);
- AlarmEvent alarmEvents;
- AlarmInventory alarmInventory;
-
trompeloeil::sequence seq1;
- auto alarmsRPC = alarmsClient.onRPCAction("/sysrepo-ietf-alarms:create-or-update-alarm", [&](auto, auto, auto, const libyang::DataNode input, auto, auto, auto) {
- std::map<std::string, std::string> inputData;
-
- for (const auto& node : input.childrenDfs()) {
- inputData.emplace(node.path(), nodeAsString(node));
- }
-
- alarmEvents.event(inputData);
-
- return sysrepo::ErrorCode::Ok;
- });
+ AlarmInventory alarmInventory;
+ RPCWatcher alarmEvents(alarmsClient, "/sysrepo-ietf-alarms:create-or-update-alarm");
auto directLeafNodeQuery = [&](const std::string& xpath) {
auto val = client.getData(xpath);