blob: a9424a987e25b6d4ad89f8334206483e87993b30 [file] [log] [blame]
Tomáš Pecka3f811962023-04-14 10:54:32 +02001#include "trompeloeil_doctest.h"
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +02002#include <iterator>
3#include <sysrepo-cpp/Enum.hpp>
4#include <trompeloeil.hpp>
Tomáš Pecka3f811962023-04-14 10:54:32 +02005#include "ietf-hardware/IETFHardware.h"
6#include "ietf-hardware/sysrepo/Sysrepo.h"
7#include "mock/ietf_hardware.h"
8#include "pretty_printers.h"
Tomáš Peckabaf289c2024-01-24 15:12:44 +01009#include "sysrepo-helpers/alarms.h"
Tomáš Pecka7eb64592024-01-24 14:10:47 +010010#include "sysrepo-helpers/datastore.h"
Tomáš Pecka3f811962023-04-14 10:54:32 +020011#include "test_log_setup.h"
Tomáš Peckac164ca62024-01-24 13:38:03 +010012#include "tests/sysrepo-helpers/common.h"
Tomáš Pecka3f811962023-04-14 10:54:32 +020013
14using namespace std::literals;
15
Tomáš Pecka2fdc8ce2024-01-18 12:28:37 +010016#define COMPONENT(RESOURCE) "/ietf-hardware:hardware/component[name='" RESOURCE "']"
Jan Kundrátc1511512024-01-15 13:47:28 +010017
Tomáš Pecka2848fd02024-01-30 12:05:59 +010018#define REQUIRE_ALARM_INVENTORY_ADD_ALARM(ALARM_TYPE, DESCRIPTION) \
Tomáš Pecka4163c0c2024-01-31 13:21:03 +010019 REQUIRE_NEW_ALARM_INVENTORY_ENTRY(alarmWatcher, ALARM_TYPE, (std::set<std::string>{}), \
Tomáš Pecka2848fd02024-01-30 12:05:59 +010020 (std::set<std::string>{}), true, DESCRIPTION)
Jan Kundrátc1511512024-01-15 13:47:28 +010021
Tomáš Pecka87844292024-01-30 15:20:21 +010022#define REQUIRE_ALARM_INVENTORY_ADD_RESOURCES(ALARM_TYPE, ...) \
Tomáš Pecka4163c0c2024-01-31 13:21:03 +010023 REQUIRE_NEW_ALARM_INVENTORY_RESOURCE(alarmWatcher, ALARM_TYPE, (std::set<std::string>{__VA_ARGS__}))
Jan Kundrátc1511512024-01-15 13:47:28 +010024
25#define REQUIRE_ALARM_RPC(ALARM_TYPE, RESOURCE, SEVERITY, TEXT) \
Tomáš Pecka4163c0c2024-01-31 13:21:03 +010026 REQUIRE_NEW_ALARM(alarmWatcher, ALARM_TYPE, COMPONENT(RESOURCE), SEVERITY, TEXT)
Tomáš Pecka1b3c1732023-05-12 11:45:01 +020027
Tomáš Pecka3f811962023-04-14 10:54:32 +020028TEST_CASE("IETF Hardware with sysrepo")
29{
30 TEST_SYSREPO_INIT_LOGS;
31 TEST_SYSREPO_INIT;
32 TEST_SYSREPO_INIT_CLIENT;
Tomáš Peckac0991ce2023-12-20 15:46:03 +010033
34 srSess.sendRPC(srSess.getContext().newPath("/ietf-factory-default:factory-reset"));
35
Tomáš Pecka2117ce52023-05-12 11:28:34 +020036 auto alarmsClient = sysrepo::Connection{}.sessionStart(sysrepo::Datastore::Operational);
37
Tomáš Pecka3f811962023-04-14 10:54:32 +020038 static const auto modulePrefix = "/ietf-hardware:hardware"s;
39
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +020040 client.switchDatastore(sysrepo::Datastore::Operational);
41
Tomáš Pecka3f811962023-04-14 10:54:32 +020042 trompeloeil::sequence seq1;
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +020043
44 auto directLeafNodeQuery = [&](const std::string& xpath) {
45 auto val = client.getData(xpath);
46 REQUIRE(val);
47 return std::string{val->findPath(xpath)->asTerm().valueStr()};
48 };
Tomáš Pecka3f811962023-04-14 10:54:32 +020049
Tomáš Pecka3f811962023-04-14 10:54:32 +020050 auto sysfsTempCpu = std::make_shared<FakeHWMon>();
Tomáš Pecka3f811962023-04-14 10:54:32 +020051 auto sysfsPower = std::make_shared<FakeHWMon>();
Tomáš Pecka3f811962023-04-14 10:54:32 +020052
Tomáš Pecka9af47392023-05-23 14:56:48 +020053 using velia::ietf_hardware::OneThreshold;
54 using velia::ietf_hardware::Thresholds;
Tomáš Pecka3f811962023-04-14 10:54:32 +020055 using velia::ietf_hardware::data_reader::SensorType;
56 using velia::ietf_hardware::data_reader::StaticData;
57 using velia::ietf_hardware::data_reader::SysfsValue;
Tomáš Peckae5366c62023-04-14 11:03:04 +020058
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +020059 std::atomic<bool> psuActive; // this needs to be destroyed after ietfHardware to avoid dangling reference (we are passing it as a ref to PsuDataReader)
Tomáš Pecka9af47392023-05-23 14:56:48 +020060 std::atomic<int64_t> psuSensorValue;
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +020061 std::atomic<int64_t> cpuTempValue;
62 std::atomic<int64_t> powerValue;
63
Tomáš Pecka3f811962023-04-14 10:54:32 +020064 // register components into hw state
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +020065 auto ietfHardware = std::make_shared<velia::ietf_hardware::IETFHardware>();
Tomáš Pecka3f811962023-04-14 10:54:32 +020066 ietfHardware->registerDataReader(StaticData("ne", std::nullopt, {{"class", "iana-hardware:chassis"}, {"mfg-name", "CESNET"s}}));
Tomáš Peckae5366c62023-04-14 11:03:04 +020067 ietfHardware->registerDataReader(SysfsValue<SensorType::Temperature>("ne:temperature-cpu", "ne", sysfsTempCpu, 1));
Jan Kundrátc1511512024-01-15 13:47:28 +010068 ietfHardware->registerDataReader(SysfsValue<SensorType::Power>(
69 "ne:power",
70 "ne",
71 sysfsPower,
72 1,
73 Thresholds<int64_t>{
74 .criticalLow = OneThreshold<int64_t>{8'000'000, 500'000},
75 .warningLow = OneThreshold<int64_t>{10'000'000, 500'000},
76 .warningHigh = OneThreshold<int64_t>{20'000'000, 500'000},
77 .criticalHigh = OneThreshold<int64_t>{22'000'000, 500'000},
78 }));
Tomáš Pecka3f811962023-04-14 10:54:32 +020079
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +020080 /* Some data readers (like our PSU reader, see the FspYhPsu test) may set oper-state to enabled/disabled depending on whether the device is present and Some
81 * data might not even be pushed (e.g. the child sensors).
82 * Since we push data into sysrepo we have to erase old data (that should no longer be present) from the sysrepo operational DS.
83 * We test such situation via the following data reader which returns data only when psuActive is set to true.
84 */
85 struct PsuDataReader {
86 const std::atomic<bool>& active;
Tomáš Pecka9af47392023-05-23 14:56:48 +020087 const std::atomic<int64_t>& value;
Tomáš Pecka3f811962023-04-14 10:54:32 +020088
Tomáš Peckac0991ce2023-12-20 15:46:03 +010089 velia::ietf_hardware::SensorPollData operator()()
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +020090 {
Tomáš Pecka26b38212024-01-16 17:23:31 +010091 velia::ietf_hardware::SideLoadedAlarm alarm;
Tomáš Peckac0991ce2023-12-20 15:46:03 +010092 velia::ietf_hardware::ThresholdsBySensorPath thr;
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +020093 velia::ietf_hardware::DataTree res = {
Jan Kundrátf85b5cb2024-01-15 13:11:51 +010094 {COMPONENT("ne:psu") "/class", "iana-hardware:power-supply"},
95 {COMPONENT("ne:psu") "/parent", "ne"},
96 {COMPONENT("ne:psu") "/state/oper-state", "disabled"},
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +020097 };
Tomáš Pecka3f811962023-04-14 10:54:32 +020098
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +020099 if (active) {
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100100 res[COMPONENT("ne:psu") "/state/oper-state"] = "enabled";
101 res[COMPONENT("ne:psu:child") "/class"] = "iana-hardware:sensor";
102 res[COMPONENT("ne:psu:child") "/parent"] = "ne:psu";
103 res[COMPONENT("ne:psu:child") "/state/oper-state"] = "enabled";
104 res[COMPONENT("ne:psu:child") "/sensor-data/oper-status"] = "ok";
105 res[COMPONENT("ne:psu:child") "/sensor-data/value"] = std::to_string(value);
106 res[COMPONENT("ne:psu:child") "/sensor-data/value-precision"] = "0";
107 res[COMPONENT("ne:psu:child") "/sensor-data/value-scale"] = "milli";
108 res[COMPONENT("ne:psu:child") "/sensor-data/value-type"] = "volts-DC";
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100109
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100110 thr[COMPONENT("ne:psu:child") "/sensor-data/value"] = Thresholds<int64_t>{
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100111 .criticalLow = std::nullopt,
112 .warningLow = OneThreshold<int64_t>{10000, 2000},
113 .warningHigh = OneThreshold<int64_t>{15000, 2000},
114 .criticalHigh = std::nullopt,
115 };
Tomáš Pecka26b38212024-01-16 17:23:31 +0100116
117 alarm = {"velia-alarms:sensor-missing-alarm", COMPONENT("ne:psu"), "cleared", "PSU missing."};
118 } else {
119 alarm = {"velia-alarms:sensor-missing-alarm", COMPONENT("ne:psu"), "critical", "PSU missing."};
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +0200120 }
Tomáš Pecka3f811962023-04-14 10:54:32 +0200121
Tomáš Pecka26b38212024-01-16 17:23:31 +0100122 return {res, thr, {alarm}};
Tomáš Pecka4886db22023-05-10 10:46:15 +0200123 }
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +0200124 };
Tomáš Pecka9af47392023-05-23 14:56:48 +0200125 ietfHardware->registerDataReader(PsuDataReader{psuActive, psuSensorValue});
Tomáš Pecka3f811962023-04-14 10:54:32 +0200126
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +0200127 /* Ensure that there are sane data after each sysrepo change callback (all the component subtrees are expected). */
Tomáš Pecka7eb64592024-01-24 14:10:47 +0100128 DatastoreWatcher dsChangeHardware(client, "/ietf-hardware:hardware/component", {"/ietf-hardware:hardware/last-change"});
Tomáš Peckabaf289c2024-01-24 15:12:44 +0100129 AlarmWatcher alarmWatcher(client);
Tomáš Pecka2117ce52023-05-12 11:28:34 +0200130
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100131 SECTION("Disappearing sensor plugged from the beginning")
132 {
133 // first batch of values
134 cpuTempValue = 41800;
135 powerValue = 0;
136 psuActive = true;
137 psuSensorValue = 12000;
138 REQUIRE_CALL(*sysfsTempCpu, attribute("temp1_input")).LR_RETURN(cpuTempValue).TIMES(AT_LEAST(1));
139 REQUIRE_CALL(*sysfsPower, attribute("power1_input")).LR_RETURN(powerValue).TIMES(AT_LEAST(1));
Tomáš Pecka2848fd02024-01-30 12:05:59 +0100140
141 REQUIRE_ALARM_INVENTORY_ADD_ALARM("velia-alarms:sensor-low-value-alarm", "Sensor value is below the low threshold.").IN_SEQUENCE(seq1);
142 REQUIRE_ALARM_INVENTORY_ADD_ALARM("velia-alarms:sensor-high-value-alarm", "Sensor value is above the high threshold.").IN_SEQUENCE(seq1);
143 REQUIRE_ALARM_INVENTORY_ADD_ALARM("velia-alarms:sensor-missing-alarm", "Sensor is missing.").IN_SEQUENCE(seq1);
144 REQUIRE_ALARM_INVENTORY_ADD_ALARM("velia-alarms:sensor-nonoperational", "Sensor is flagged as nonoperational.").IN_SEQUENCE(seq1);
145
Tomáš Pecka87844292024-01-30 15:20:21 +0100146 REQUIRE_ALARM_INVENTORY_ADD_RESOURCES("velia-alarms:sensor-low-value-alarm", COMPONENT("ne:power"), COMPONENT("ne:psu:child"), COMPONENT("ne:temperature-cpu")).IN_SEQUENCE(seq1);
147 REQUIRE_ALARM_INVENTORY_ADD_RESOURCES("velia-alarms:sensor-high-value-alarm", COMPONENT("ne:power"), COMPONENT("ne:psu:child"), COMPONENT("ne:temperature-cpu")).IN_SEQUENCE(seq1);
148 REQUIRE_ALARM_INVENTORY_ADD_RESOURCES("velia-alarms:sensor-missing-alarm", COMPONENT("ne:power"), COMPONENT("ne:psu:child"), COMPONENT("ne:temperature-cpu")).IN_SEQUENCE(seq1);
149 REQUIRE_ALARM_INVENTORY_ADD_RESOURCES("velia-alarms:sensor-nonoperational", COMPONENT("ne:power"), COMPONENT("ne:psu:child"), COMPONENT("ne:temperature-cpu")).IN_SEQUENCE(seq1);
Tomáš Pecka2117ce52023-05-12 11:28:34 +0200150
Tomáš Pecka7eb64592024-01-24 14:10:47 +0100151 REQUIRE_DATASTORE_CHANGE(dsChangeHardware, (ValueChanges{
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100152 {COMPONENT("ne") "/class", "iana-hardware:chassis"},
153 {COMPONENT("ne") "/mfg-name", "CESNET"},
154 {COMPONENT("ne") "/name", "ne"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100155 {COMPONENT("ne") "/state/oper-state", "enabled"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100156 {COMPONENT("ne:power") "/class", "iana-hardware:sensor"},
157 {COMPONENT("ne:power") "/name", "ne:power"},
158 {COMPONENT("ne:power") "/parent", "ne"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100159 {COMPONENT("ne:power") "/sensor-data/oper-status", "ok"},
160 {COMPONENT("ne:power") "/sensor-data/value", "0"},
161 {COMPONENT("ne:power") "/sensor-data/value-precision", "0"},
162 {COMPONENT("ne:power") "/sensor-data/value-scale", "micro"},
163 {COMPONENT("ne:power") "/sensor-data/value-type", "watts"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100164 {COMPONENT("ne:power") "/state/oper-state", "enabled"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100165 {COMPONENT("ne:psu") "/class", "iana-hardware:power-supply"},
166 {COMPONENT("ne:psu") "/name", "ne:psu"},
167 {COMPONENT("ne:psu") "/parent", "ne"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100168 {COMPONENT("ne:psu") "/state/oper-state", "enabled"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100169 {COMPONENT("ne:psu:child") "/class", "iana-hardware:sensor"},
170 {COMPONENT("ne:psu:child") "/name", "ne:psu:child"},
171 {COMPONENT("ne:psu:child") "/parent", "ne:psu"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100172 {COMPONENT("ne:psu:child") "/sensor-data/oper-status", "ok"},
173 {COMPONENT("ne:psu:child") "/sensor-data/value", "12000"},
174 {COMPONENT("ne:psu:child") "/sensor-data/value-precision", "0"},
175 {COMPONENT("ne:psu:child") "/sensor-data/value-scale", "milli"},
176 {COMPONENT("ne:psu:child") "/sensor-data/value-type", "volts-DC"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100177 {COMPONENT("ne:psu:child") "/state/oper-state", "enabled"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100178 {COMPONENT("ne:temperature-cpu") "/class", "iana-hardware:sensor"},
179 {COMPONENT("ne:temperature-cpu") "/name", "ne:temperature-cpu"},
180 {COMPONENT("ne:temperature-cpu") "/parent", "ne"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100181 {COMPONENT("ne:temperature-cpu") "/sensor-data/oper-status", "ok"},
182 {COMPONENT("ne:temperature-cpu") "/sensor-data/value", "41800"},
183 {COMPONENT("ne:temperature-cpu") "/sensor-data/value-precision", "0"},
184 {COMPONENT("ne:temperature-cpu") "/sensor-data/value-scale", "milli"},
185 {COMPONENT("ne:temperature-cpu") "/sensor-data/value-type", "celsius"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100186 {COMPONENT("ne:temperature-cpu") "/state/oper-state", "enabled"},
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100187 }))
188 .IN_SEQUENCE(seq1);
Tomáš Pecka87844292024-01-30 15:20:21 +0100189 REQUIRE_ALARM_INVENTORY_ADD_RESOURCES("velia-alarms:sensor-missing-alarm", COMPONENT("ne:psu")).TIMES(AT_LEAST(1));
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100190 REQUIRE_ALARM_RPC("velia-alarms:sensor-low-value-alarm", "ne:power", "critical", "Sensor value crossed low threshold.").IN_SEQUENCE(seq1);
Tomáš Pecka3f811962023-04-14 10:54:32 +0200191
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100192 auto ietfHardwareSysrepo = std::make_shared<velia::ietf_hardware::sysrepo::Sysrepo>(srSess, ietfHardware, 150ms);
193 std::this_thread::sleep_for(400ms); // let's wait until the bg polling thread is spawned; 400 ms is probably enough to spawn the thread and poll 2 or 3 times
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +0200194
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100195 std::string lastChange = directLeafNodeQuery(modulePrefix + "/last-change");
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +0200196
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100197 // second batch of values, sensor data changed, PSU ejected
Tomáš Pecka7eb64592024-01-24 14:10:47 +0100198 REQUIRE_DATASTORE_CHANGE(dsChangeHardware, (ValueChanges{
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100199 {COMPONENT("ne:psu:child") "/class", Deleted{}},
200 {COMPONENT("ne:psu:child") "/parent", Deleted{}},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100201 {COMPONENT("ne:psu:child") "/sensor-data/oper-status", Deleted{}},
202 {COMPONENT("ne:psu:child") "/sensor-data/value", Deleted{}},
203 {COMPONENT("ne:psu:child") "/sensor-data/value-precision", Deleted{}},
204 {COMPONENT("ne:psu:child") "/sensor-data/value-scale", Deleted{}},
205 {COMPONENT("ne:psu:child") "/sensor-data/value-type", Deleted{}},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100206 {COMPONENT("ne:psu:child") "/state/oper-state", Deleted{}},
207 {COMPONENT("ne:power") "/sensor-data/value", "11222333"},
208 {COMPONENT("ne:psu") "/state/oper-state", "disabled"},
209 {COMPONENT("ne:temperature-cpu") "/sensor-data/value", "222"},
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100210 }))
211 .IN_SEQUENCE(seq1);
Tomáš Pecka26b38212024-01-16 17:23:31 +0100212 REQUIRE_ALARM_RPC("velia-alarms:sensor-missing-alarm", "ne:psu", "critical", "PSU missing.").IN_SEQUENCE(seq1);
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100213 REQUIRE_ALARM_RPC("velia-alarms:sensor-low-value-alarm", "ne:power", "cleared", "Sensor value crossed low threshold.").IN_SEQUENCE(seq1);
Jan Kundrátc1511512024-01-15 13:47:28 +0100214 REQUIRE_ALARM_RPC("velia-alarms:sensor-missing-alarm", "ne:psu:child", "warning",
215 "Sensor value not reported. Maybe the sensor was unplugged?").IN_SEQUENCE(seq1);
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100216 REQUIRE_CALL(*sysfsTempCpu, attribute("temp1_input")).LR_RETURN(cpuTempValue).TIMES(AT_LEAST(1));
217 REQUIRE_CALL(*sysfsPower, attribute("power1_input")).LR_RETURN(powerValue).TIMES(AT_LEAST(1));
218 cpuTempValue = 222;
219 powerValue = 11222333;
220 psuActive = false;
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +0200221
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100222 std::this_thread::sleep_for(2000ms); // longer sleep here: last-change does not report milliseconds so this should increase last-change timestamp at least by one second
223 REQUIRE(directLeafNodeQuery(modulePrefix + "/last-change") > lastChange); // check that last-change leaf has timestamp that is greater than the previous one
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +0200224
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100225 // third batch of changes, wild PSU appears with a warning
Tomáš Pecka7eb64592024-01-24 14:10:47 +0100226 REQUIRE_DATASTORE_CHANGE(dsChangeHardware, (ValueChanges{
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100227 {COMPONENT("ne:psu") "/state/oper-state", "enabled"},
228 {COMPONENT("ne:psu:child") "/class", "iana-hardware:sensor"},
229 {COMPONENT("ne:psu:child") "/parent", "ne:psu"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100230 {COMPONENT("ne:psu:child") "/sensor-data/oper-status", "ok"},
231 {COMPONENT("ne:psu:child") "/sensor-data/value", "50000"},
232 {COMPONENT("ne:psu:child") "/sensor-data/value-precision", "0"},
233 {COMPONENT("ne:psu:child") "/sensor-data/value-scale", "milli"},
234 {COMPONENT("ne:psu:child") "/sensor-data/value-type", "volts-DC"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100235 {COMPONENT("ne:psu:child") "/state/oper-state", "enabled"},
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100236 }))
237 .IN_SEQUENCE(seq1);
Tomáš Pecka26b38212024-01-16 17:23:31 +0100238 REQUIRE_ALARM_RPC("velia-alarms:sensor-missing-alarm", "ne:psu", "cleared", "PSU missing.").IN_SEQUENCE(seq1);
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100239 REQUIRE_ALARM_RPC("velia-alarms:sensor-missing-alarm", "ne:psu:child", "cleared", "Sensor value not reported. Maybe the sensor was unplugged?").IN_SEQUENCE(seq1);
240 REQUIRE_ALARM_RPC("velia-alarms:sensor-high-value-alarm", "ne:psu:child", "warning", "Sensor value crossed high threshold.").IN_SEQUENCE(seq1);
241 psuSensorValue = 50000;
242 psuActive = true;
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +0200243
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100244 waitForCompletionAndBitMore(seq1);
Tomáš Pecka9af47392023-05-23 14:56:48 +0200245
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100246 // fourth round. We unplug with a warning
Tomáš Pecka7eb64592024-01-24 14:10:47 +0100247 REQUIRE_DATASTORE_CHANGE(dsChangeHardware, (ValueChanges{
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100248 {COMPONENT("ne:psu:child") "/class", Deleted{}},
249 {COMPONENT("ne:psu:child") "/parent", Deleted{}},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100250 {COMPONENT("ne:psu:child") "/sensor-data/oper-status", Deleted{}},
251 {COMPONENT("ne:psu:child") "/sensor-data/value", Deleted{}},
252 {COMPONENT("ne:psu:child") "/sensor-data/value-precision", Deleted{}},
253 {COMPONENT("ne:psu:child") "/sensor-data/value-scale", Deleted{}},
254 {COMPONENT("ne:psu:child") "/sensor-data/value-type", Deleted{}},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100255 {COMPONENT("ne:psu:child") "/state/oper-state", Deleted{}},
256 {COMPONENT("ne:psu") "/state/oper-state", "disabled"},
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100257 }))
258 .IN_SEQUENCE(seq1);
Tomáš Pecka26b38212024-01-16 17:23:31 +0100259 REQUIRE_ALARM_RPC("velia-alarms:sensor-missing-alarm", "ne:psu", "critical", "PSU missing.").IN_SEQUENCE(seq1);
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100260 REQUIRE_ALARM_RPC("velia-alarms:sensor-missing-alarm", "ne:psu:child", "warning", "Sensor value not reported. Maybe the sensor was unplugged?").IN_SEQUENCE(seq1);
261 REQUIRE_ALARM_RPC("velia-alarms:sensor-high-value-alarm", "ne:psu:child", "cleared", "Sensor value crossed high threshold.").IN_SEQUENCE(seq1);
262 psuActive = false;
263 waitForCompletionAndBitMore(seq1);
Tomáš Pecka9af47392023-05-23 14:56:48 +0200264
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100265 // 5+th round: test threshold crossings
Tomáš Pecka7eb64592024-01-24 14:10:47 +0100266 REQUIRE_DATASTORE_CHANGE(dsChangeHardware, (ValueChanges{
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100267 {COMPONENT("ne:power") "/sensor-data/value", "21000000"},
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100268 }))
269 .IN_SEQUENCE(seq1);
270 REQUIRE_ALARM_RPC("velia-alarms:sensor-high-value-alarm", "ne:power", "warning", "Sensor value crossed high threshold.").IN_SEQUENCE(seq1);
271 powerValue = 21'000'000;
272 waitForCompletionAndBitMore(seq1);
Tomáš Pecka9af47392023-05-23 14:56:48 +0200273
Tomáš Pecka7eb64592024-01-24 14:10:47 +0100274 REQUIRE_DATASTORE_CHANGE(dsChangeHardware, (ValueChanges{
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100275 {COMPONENT("ne:power") "/sensor-data/value", "24000000"},
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100276 }))
277 .IN_SEQUENCE(seq1);
278 REQUIRE_ALARM_RPC("velia-alarms:sensor-high-value-alarm", "ne:power", "critical", "Sensor value crossed high threshold.").IN_SEQUENCE(seq1);
279 powerValue = 24'000'000;
280 waitForCompletionAndBitMore(seq1);
Tomáš Pecka9af47392023-05-23 14:56:48 +0200281
Tomáš Pecka7eb64592024-01-24 14:10:47 +0100282 REQUIRE_DATASTORE_CHANGE(dsChangeHardware, (ValueChanges{
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100283 {COMPONENT("ne:power") "/sensor-data/value", "1"},
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100284 }))
285 .IN_SEQUENCE(seq1);
286 REQUIRE_ALARM_RPC("velia-alarms:sensor-low-value-alarm", "ne:power", "critical", "Sensor value crossed low threshold.").IN_SEQUENCE(seq1);
287 REQUIRE_ALARM_RPC("velia-alarms:sensor-high-value-alarm", "ne:power", "cleared", "Sensor value crossed high threshold.").IN_SEQUENCE(seq1);
288 powerValue = 1;
289 waitForCompletionAndBitMore(seq1);
Tomáš Pecka9af47392023-05-23 14:56:48 +0200290
Tomáš Pecka7eb64592024-01-24 14:10:47 +0100291 REQUIRE_DATASTORE_CHANGE(dsChangeHardware, (ValueChanges{
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100292 {COMPONENT("ne:power") "/sensor-data/value", "14000000"},
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100293 }))
294 .IN_SEQUENCE(seq1);
295 REQUIRE_ALARM_RPC("velia-alarms:sensor-low-value-alarm", "ne:power", "cleared", "Sensor value crossed low threshold.").IN_SEQUENCE(seq1);
296 powerValue = 14'000'000;
297 waitForCompletionAndBitMore(seq1);
Tomáš Pecka9af47392023-05-23 14:56:48 +0200298
Tomáš Pecka5a4c0352023-12-12 12:29:28 +0100299
Tomáš Pecka7eb64592024-01-24 14:10:47 +0100300 REQUIRE_DATASTORE_CHANGE(dsChangeHardware, (ValueChanges{
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100301 {COMPONENT("ne:power") "/sensor-data/value", "1000000000"},
302 {COMPONENT("ne:power") "/sensor-data/oper-status", "nonoperational"},
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100303 }))
304 .IN_SEQUENCE(seq1);
Jan Kundrátc1511512024-01-15 13:47:28 +0100305 REQUIRE_ALARM_RPC("velia-alarms:sensor-nonoperational", "ne:power", "warning",
306 "Sensor is nonoperational. The values it reports may not be relevant.").IN_SEQUENCE(seq1);
307 REQUIRE_ALARM_RPC("velia-alarms:sensor-high-value-alarm", "ne:power", "critical",
308 "Sensor value crossed high threshold.").IN_SEQUENCE(seq1);
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100309 powerValue = 2'999'999'999;
310 waitForCompletionAndBitMore(seq1);
Tomáš Pecka5a4c0352023-12-12 12:29:28 +0100311
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100312 powerValue = 1'999'999'999;
313 waitForCompletionAndBitMore(seq1);
Tomáš Pecka5a4c0352023-12-12 12:29:28 +0100314
Tomáš Pecka7eb64592024-01-24 14:10:47 +0100315 REQUIRE_DATASTORE_CHANGE(dsChangeHardware, (ValueChanges{
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100316 {COMPONENT("ne:power") "/sensor-data/value", "-1000000000"},
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100317 }))
318 .IN_SEQUENCE(seq1);
319 REQUIRE_ALARM_RPC("velia-alarms:sensor-low-value-alarm", "ne:power", "critical", "Sensor value crossed low threshold.").IN_SEQUENCE(seq1);
320 REQUIRE_ALARM_RPC("velia-alarms:sensor-high-value-alarm", "ne:power", "cleared", "Sensor value crossed high threshold.").IN_SEQUENCE(seq1);
321 powerValue = -2'999'999'999;
322 waitForCompletionAndBitMore(seq1);
Tomáš Pecka5a4c0352023-12-12 12:29:28 +0100323
Tomáš Pecka7eb64592024-01-24 14:10:47 +0100324 REQUIRE_DATASTORE_CHANGE(dsChangeHardware, (ValueChanges{
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100325 {COMPONENT("ne:power") "/sensor-data/value", "-999999999"},
326 {COMPONENT("ne:power") "/sensor-data/oper-status", "ok"},
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100327 }))
328 .IN_SEQUENCE(seq1);
Jan Kundrátc1511512024-01-15 13:47:28 +0100329 REQUIRE_ALARM_RPC("velia-alarms:sensor-nonoperational", "ne:power", "cleared",
330 "Sensor is nonoperational. The values it reports may not be relevant.").IN_SEQUENCE(seq1);
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100331 powerValue = -999'999'999;
332 waitForCompletionAndBitMore(seq1);
333 }
334
335 SECTION("Disappearing sensor unplugged in the beginning")
336 {
337 cpuTempValue = 41800;
338 powerValue = 0;
339 psuActive = false;
340 psuSensorValue = 12000;
341 REQUIRE_CALL(*sysfsTempCpu, attribute("temp1_input")).LR_RETURN(cpuTempValue).TIMES(AT_LEAST(1));
342 REQUIRE_CALL(*sysfsPower, attribute("power1_input")).LR_RETURN(powerValue).TIMES(AT_LEAST(1));
Tomáš Pecka2848fd02024-01-30 12:05:59 +0100343 REQUIRE_ALARM_INVENTORY_ADD_ALARM("velia-alarms:sensor-low-value-alarm", "Sensor value is below the low threshold.").IN_SEQUENCE(seq1);
344 REQUIRE_ALARM_INVENTORY_ADD_ALARM("velia-alarms:sensor-high-value-alarm", "Sensor value is above the high threshold.").IN_SEQUENCE(seq1);
345 REQUIRE_ALARM_INVENTORY_ADD_ALARM("velia-alarms:sensor-missing-alarm", "Sensor is missing.").IN_SEQUENCE(seq1);
346 REQUIRE_ALARM_INVENTORY_ADD_ALARM("velia-alarms:sensor-nonoperational", "Sensor is flagged as nonoperational.").IN_SEQUENCE(seq1);
347
Tomáš Pecka87844292024-01-30 15:20:21 +0100348 REQUIRE_ALARM_INVENTORY_ADD_RESOURCES("velia-alarms:sensor-low-value-alarm", COMPONENT("ne:power"), COMPONENT("ne:temperature-cpu")).IN_SEQUENCE(seq1);
349 REQUIRE_ALARM_INVENTORY_ADD_RESOURCES("velia-alarms:sensor-high-value-alarm", COMPONENT("ne:power"), COMPONENT("ne:temperature-cpu")).IN_SEQUENCE(seq1);
350 REQUIRE_ALARM_INVENTORY_ADD_RESOURCES("velia-alarms:sensor-missing-alarm", COMPONENT("ne:power"), COMPONENT("ne:temperature-cpu")).IN_SEQUENCE(seq1);
351 REQUIRE_ALARM_INVENTORY_ADD_RESOURCES("velia-alarms:sensor-nonoperational", COMPONENT("ne:power"), COMPONENT("ne:temperature-cpu")).IN_SEQUENCE(seq1);
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100352
Tomáš Pecka7eb64592024-01-24 14:10:47 +0100353 REQUIRE_DATASTORE_CHANGE(dsChangeHardware, (ValueChanges{
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100354 {COMPONENT("ne") "/class", "iana-hardware:chassis"},
355 {COMPONENT("ne") "/mfg-name", "CESNET"},
356 {COMPONENT("ne") "/name", "ne"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100357 {COMPONENT("ne") "/state/oper-state", "enabled"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100358 {COMPONENT("ne:power") "/class", "iana-hardware:sensor"},
359 {COMPONENT("ne:power") "/name", "ne:power"},
360 {COMPONENT("ne:power") "/parent", "ne"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100361 {COMPONENT("ne:power") "/sensor-data/oper-status", "ok"},
362 {COMPONENT("ne:power") "/sensor-data/value", "0"},
363 {COMPONENT("ne:power") "/sensor-data/value-precision", "0"},
364 {COMPONENT("ne:power") "/sensor-data/value-scale", "micro"},
365 {COMPONENT("ne:power") "/sensor-data/value-type", "watts"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100366 {COMPONENT("ne:power") "/state/oper-state", "enabled"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100367 {COMPONENT("ne:psu") "/class", "iana-hardware:power-supply"},
368 {COMPONENT("ne:psu") "/name", "ne:psu"},
369 {COMPONENT("ne:psu") "/parent", "ne"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100370 {COMPONENT("ne:psu") "/state/oper-state", "disabled"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100371 {COMPONENT("ne:temperature-cpu") "/class", "iana-hardware:sensor"},
372 {COMPONENT("ne:temperature-cpu") "/name", "ne:temperature-cpu"},
373 {COMPONENT("ne:temperature-cpu") "/parent", "ne"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100374 {COMPONENT("ne:temperature-cpu") "/sensor-data/oper-status", "ok"},
375 {COMPONENT("ne:temperature-cpu") "/sensor-data/value", "41800"},
376 {COMPONENT("ne:temperature-cpu") "/sensor-data/value-precision", "0"},
377 {COMPONENT("ne:temperature-cpu") "/sensor-data/value-scale", "milli"},
378 {COMPONENT("ne:temperature-cpu") "/sensor-data/value-type", "celsius"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100379 {COMPONENT("ne:temperature-cpu") "/state/oper-state", "enabled"},
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100380 }))
381 .IN_SEQUENCE(seq1);
Tomáš Pecka87844292024-01-30 15:20:21 +0100382 REQUIRE_ALARM_INVENTORY_ADD_RESOURCES("velia-alarms:sensor-missing-alarm", COMPONENT("ne:psu")).TIMES(AT_LEAST(1));
Tomáš Pecka26b38212024-01-16 17:23:31 +0100383 REQUIRE_ALARM_RPC("velia-alarms:sensor-missing-alarm", "ne:psu", "critical", "PSU missing.").IN_SEQUENCE(seq1);
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100384 REQUIRE_ALARM_RPC("velia-alarms:sensor-low-value-alarm", "ne:power", "critical", "Sensor value crossed low threshold.").IN_SEQUENCE(seq1);
385
386 auto ietfHardwareSysrepo = std::make_shared<velia::ietf_hardware::sysrepo::Sysrepo>(srSess, ietfHardware, 150ms);
387 std::this_thread::sleep_for(400ms); // let's wait until the bg polling thread is spawned; 400 ms is probably enough to spawn the thread and poll 2 or 3 times
388 waitForCompletionAndBitMore(seq1);
389
390 std::string lastChange = directLeafNodeQuery(modulePrefix + "/last-change");
391
392 // PSU inserted
Tomáš Pecka87844292024-01-30 15:20:21 +0100393 REQUIRE_ALARM_INVENTORY_ADD_RESOURCES("velia-alarms:sensor-low-value-alarm", COMPONENT("ne:psu:child")).IN_SEQUENCE(seq1);
394 REQUIRE_ALARM_INVENTORY_ADD_RESOURCES("velia-alarms:sensor-high-value-alarm", COMPONENT("ne:psu:child")).IN_SEQUENCE(seq1);
395 REQUIRE_ALARM_INVENTORY_ADD_RESOURCES("velia-alarms:sensor-missing-alarm", COMPONENT("ne:psu:child")).IN_SEQUENCE(seq1);
396 REQUIRE_ALARM_INVENTORY_ADD_RESOURCES("velia-alarms:sensor-nonoperational", COMPONENT("ne:psu:child")).IN_SEQUENCE(seq1);
Tomáš Pecka7eb64592024-01-24 14:10:47 +0100397 REQUIRE_DATASTORE_CHANGE(dsChangeHardware, (ValueChanges{
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100398 {COMPONENT("ne:psu") "/state/oper-state", "enabled"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100399 {COMPONENT("ne:psu:child") "/class", "iana-hardware:sensor"},
400 {COMPONENT("ne:psu:child") "/name", "ne:psu:child"},
401 {COMPONENT("ne:psu:child") "/parent", "ne:psu"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100402 {COMPONENT("ne:psu:child") "/sensor-data/oper-status", "ok"},
403 {COMPONENT("ne:psu:child") "/sensor-data/value", "12000"},
404 {COMPONENT("ne:psu:child") "/sensor-data/value-precision", "0"},
405 {COMPONENT("ne:psu:child") "/sensor-data/value-scale", "milli"},
406 {COMPONENT("ne:psu:child") "/sensor-data/value-type", "volts-DC"},
Jan Kundrátf85b5cb2024-01-15 13:11:51 +0100407 {COMPONENT("ne:psu:child") "/state/oper-state", "enabled"},
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100408 }))
409 .IN_SEQUENCE(seq1);
Tomáš Pecka26b38212024-01-16 17:23:31 +0100410 REQUIRE_ALARM_RPC("velia-alarms:sensor-missing-alarm", "ne:psu", "cleared", "PSU missing.").IN_SEQUENCE(seq1);
Tomáš Peckac0991ce2023-12-20 15:46:03 +0100411 psuActive = true;
412 waitForCompletionAndBitMore(seq1);
413
414 std::this_thread::sleep_for(1000ms); // last-change leaf resolution is in seconds, let's wait until the second increments
415 REQUIRE(directLeafNodeQuery(modulePrefix + "/last-change") > lastChange); // check that last-change leaf has timestamp that is greater than the previous one
416 }
Tomáš Pecka3f811962023-04-14 10:54:32 +0200417}