blob: 914c0e517f09c0854975b4565bba2c84ba6df4f0 [file] [log] [blame]
Tomáš Peckabaf289c2024-01-24 15:12:44 +01001/*
2 * Copyright (C) 2024 CESNET, https://photonics.cesnet.cz/
3 *
4 * Written by Tomáš Pecka <tomas.pecka@cesnet.cz>
5 *
6 */
7
8#pragma once
9
10#include "trompeloeil_doctest.h"
Tomáš Pecka1211fd92024-01-24 15:24:07 +010011#include <optional>
Tomáš Peckabaf289c2024-01-24 15:12:44 +010012#include <sysrepo-cpp/Subscription.hpp>
13#include "sysrepo-helpers/common.h"
14#include "sysrepo-helpers/datastore.h"
15#include "sysrepo-helpers/rpc.h"
16#include "test_log_setup.h"
17
Tomáš Pecka87844292024-01-30 15:20:21 +010018enum class EntryAction {
19 Create,
20 Update,
21};
22
23inline ValueChanges constructAlarmInventoryChange(EntryAction action,
24 const std::string& alarmType,
Tomáš Peckae66a1932024-01-25 13:43:51 +010025 const std::set<std::string>& resources,
26 const std::set<std::string>& severities,
27 const std::optional<bool>& willClear,
28 const std::optional<std::string>& description)
Tomáš Pecka1211fd92024-01-24 15:24:07 +010029{
Tomáš Pecka4163c0c2024-01-31 13:21:03 +010030 const std::string prefix = "/ietf-alarms:alarms/alarm-inventory/alarm-type[alarm-type-id='" + alarmType + "'][alarm-type-qualifier='']";
Tomáš Pecka1211fd92024-01-24 15:24:07 +010031
Tomáš Pecka87844292024-01-30 15:20:21 +010032 ValueChanges ret;
33
34 if (action == EntryAction::Create) {
35 ret.emplace(prefix + "/alarm-type-id", alarmType);
Tomáš Pecka4163c0c2024-01-31 13:21:03 +010036 ret.emplace(prefix + "/alarm-type-qualifier", "");
Tomáš Pecka87844292024-01-30 15:20:21 +010037 }
Tomáš Pecka1211fd92024-01-24 15:24:07 +010038
Tomáš Peckae66a1932024-01-25 13:43:51 +010039 if (willClear) {
40 ret.emplace(prefix + "/will-clear", *willClear ? "true" : "false");
41 }
42
43 if (description) {
44 ret.emplace(prefix + "/description", *description);
45 }
46
Tomáš Pecka1211fd92024-01-24 15:24:07 +010047 size_t i = 1; /* YANG uses 1-based indexing */
48 for (const auto& severity : severities) {
49 ret.emplace(prefix + "/severity-level[" + std::to_string(i++) + "]", severity);
50 }
51
52 i = 1;
53 for (const auto& resource : resources) {
54 ret.emplace(prefix + "/resource[" + std::to_string(i++) + "]", resource);
55 }
56
57 return ret;
58}
59
Tomáš Peckabaf289c2024-01-24 15:12:44 +010060/** @brief A simple mock implementation of the alarm server */
61struct AlarmWatcher {
62 /** @brief Poor man's /ietf-alarms:alarms/alarm-inventory implementation in C++. */
63 struct AlarmInventory {
Tomáš Pecka4163c0c2024-01-31 13:21:03 +010064 using AlarmType = std::string;
65
Tomáš Pecka1211fd92024-01-24 15:24:07 +010066 struct AllowedResourcesAndSeverities {
67 std::set<std::string> resources;
68 std::set<std::string> severities;
69 };
Tomáš Peckabaf289c2024-01-24 15:12:44 +010070
Tomáš Pecka4163c0c2024-01-31 13:21:03 +010071 std::map<AlarmType, AllowedResourcesAndSeverities> inventory;
72
73 void add(const std::string& alarmTypeId, const std::set<std::string>& resources, const std::set<std::string>& severities);
74 bool contains(const std::string& alarmTypeId, const std::optional<std::string>& resource, const std::optional<std::string>& severity) const;
Tomáš Peckabaf289c2024-01-24 15:12:44 +010075 };
76
77 AlarmInventory alarmInventory;
78 DatastoreWatcher datastoreWatcher;
79 RPCWatcher rpcWatcher;
80
81 AlarmWatcher(sysrepo::Session& session);
82};
83
84// checks if the alarm is contained in AlarmInventory
Tomáš Pecka4163c0c2024-01-31 13:21:03 +010085#define WITH_ALARM_IN_INVENTORY(INV, ALARM_TYPE, RESOURCE, SEVERITY) \
86 LR_WITH(INV.contains(ALARM_TYPE, RESOURCE, SEVERITY))
Tomáš Peckabaf289c2024-01-24 15:12:44 +010087
88// inserts the alarm in AlarmInventory as a side effect
Tomáš Pecka4163c0c2024-01-31 13:21:03 +010089#define INSERT_INTO_INVENTORY(INV, ALARM_TYPE, RESOURCE, SEVERITIES) \
90 LR_SIDE_EFFECT(INV.add(ALARM_TYPE, RESOURCE, SEVERITIES))
Tomáš Peckabaf289c2024-01-24 15:12:44 +010091
Tomáš Pecka4163c0c2024-01-31 13:21:03 +010092#define REQUIRE_NEW_ALARM_INVENTORY_ENTRY(WATCHER, ALARM_TYPE, RESOURCES, SEVERITIES, WILL_CLEAR, DESCRIPTION) \
93 REQUIRE_DATASTORE_CHANGE(WATCHER.datastoreWatcher, constructAlarmInventoryChange(EntryAction::Create, ALARM_TYPE, RESOURCES, SEVERITIES, WILL_CLEAR, DESCRIPTION)) \
94 .INSERT_INTO_INVENTORY(WATCHER.alarmInventory, ALARM_TYPE, RESOURCES, SEVERITIES)
Tomáš Peckabaf289c2024-01-24 15:12:44 +010095
Tomáš Pecka4163c0c2024-01-31 13:21:03 +010096#define REQUIRE_NEW_ALARM_INVENTORY_RESOURCE(WATCHER, ALARM_TYPE, RESOURCES) \
97 REQUIRE_DATASTORE_CHANGE(WATCHER.datastoreWatcher, constructAlarmInventoryChange(EntryAction::Update, ALARM_TYPE, RESOURCES, {}, std::nullopt, std::nullopt)) \
98 .INSERT_INTO_INVENTORY(WATCHER.alarmInventory, ALARM_TYPE, RESOURCES, (std::set<std::string>{}))
Tomáš Peckabaf289c2024-01-24 15:12:44 +010099
Tomáš Pecka4163c0c2024-01-31 13:21:03 +0100100#define REQUIRE_NEW_ALARM(WATCHER, ALARM_TYPE, RESOURCE, SEVERITY, TEXT) \
Tomáš Peckabaf289c2024-01-24 15:12:44 +0100101 REQUIRE_RPC_CALL(WATCHER.rpcWatcher, (Values{ \
102 {"/sysrepo-ietf-alarms:create-or-update-alarm", "(unprintable)"}, \
103 {"/sysrepo-ietf-alarms:create-or-update-alarm/alarm-text", TEXT}, \
104 {"/sysrepo-ietf-alarms:create-or-update-alarm/alarm-type-id", ALARM_TYPE}, \
Tomáš Pecka4163c0c2024-01-31 13:21:03 +0100105 {"/sysrepo-ietf-alarms:create-or-update-alarm/alarm-type-qualifier", ""}, \
Tomáš Peckabaf289c2024-01-24 15:12:44 +0100106 {"/sysrepo-ietf-alarms:create-or-update-alarm/resource", RESOURCE}, \
107 {"/sysrepo-ietf-alarms:create-or-update-alarm/severity", SEVERITY}, \
108 })) \
Tomáš Pecka4163c0c2024-01-31 13:21:03 +0100109 .WITH_ALARM_IN_INVENTORY(WATCHER.alarmInventory, ALARM_TYPE, RESOURCE, SEVERITY)