blob: a8c3d8687e6ffb89f4365209d0b03e17a1b6fa23 [file] [log] [blame]
Krzysztof Grobelny80697712021-03-04 09:49:27 +00001#include "fakes/clock_fake.hpp"
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +00002#include "helpers.hpp"
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +02003#include "metric.hpp"
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +01004#include "mocks/sensor_mock.hpp"
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +00005#include "params/metric_params.hpp"
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +01006#include "utils/conv_container.hpp"
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +00007#include "utils/conversion.hpp"
8#include "utils/tstring.hpp"
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +01009
10#include <gmock/gmock.h>
11
12using namespace testing;
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000013using namespace std::chrono_literals;
14
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +000015namespace tstring = utils::tstring;
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +010016
17using Timestamp = uint64_t;
18
19class TestMetric : public Test
20{
21 public:
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000022 static std::vector<std::shared_ptr<SensorMock>>
23 makeSensorMocks(size_t amount)
24 {
25 std::vector<std::shared_ptr<SensorMock>> result;
26 for (size_t i = 0; i < amount; ++i)
27 {
28 result.emplace_back(std::make_shared<NiceMock<SensorMock>>());
29 }
30 return result;
31 }
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +010032
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000033 std::shared_ptr<Metric> makeSut(const MetricParams& p)
34 {
35 return std::make_shared<Metric>(
36 utils::convContainer<std::shared_ptr<interfaces::Sensor>>(
37 sensorMocks),
38 p.operationType(), p.id(), p.metadata(), p.collectionTimeScope(),
Krzysztof Grobelny80697712021-03-04 09:49:27 +000039 p.collectionDuration(), std::move(clockFakePtr));
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000040 }
41
Krzysztof Grobelny80697712021-03-04 09:49:27 +000042 MetricParams params = MetricParams()
43 .id("id")
44 .metadata("metadata")
45 .operationType(OperationType::avg)
46 .collectionTimeScope(CollectionTimeScope::point)
47 .collectionDuration(CollectionDuration(0ms));
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000048 std::vector<std::shared_ptr<SensorMock>> sensorMocks = makeSensorMocks(1u);
Krzysztof Grobelny80697712021-03-04 09:49:27 +000049 std::unique_ptr<ClockFake> clockFakePtr = std::make_unique<ClockFake>();
50 ClockFake& clockFake = *clockFakePtr;
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000051 std::shared_ptr<Metric> sut;
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +010052};
53
54TEST_F(TestMetric, subscribesForSensorDuringInitialization)
55{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000056 sut = makeSut(params);
57
58 EXPECT_CALL(*sensorMocks.front(),
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +000059 registerForUpdates(Truly([sut = sut.get()](const auto& a0) {
60 return a0.lock().get() == sut;
61 })));
62
63 sut->initialize();
64}
65
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +020066TEST_F(TestMetric, unsubscribesForSensorDuringDeinitialization)
67{
68 sut = makeSut(params);
69
70 EXPECT_CALL(*sensorMocks.front(),
71 unregisterFromUpdates(Truly([sut = sut.get()](const auto& a0) {
72 return a0.lock().get() == sut;
73 })));
74
75 sut->deinitialize();
76}
77
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +000078TEST_F(TestMetric, containsEmptyReadingAfterCreated)
79{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000080 sut = makeSut(params);
81
82 ASSERT_THAT(sut->getReadings(),
83 ElementsAre(MetricValue({"id", "metadata", 0., 0u})));
84}
85
86TEST_F(TestMetric, parsesSensorMetadata)
87{
Szymon Dompke3a617022021-07-19 18:23:02 +020088 using ReadingMetadata =
89 utils::LabeledTuple<std::tuple<std::string, std::string>,
90 utils::tstring::SensorDbusPath,
91 utils::tstring::SensorRedfishUri>;
92
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000093 nlohmann::json metadata;
94 metadata["MetricProperties"] = {"sensor1", "sensor2"};
95
96 sensorMocks = makeSensorMocks(2);
97 sut = makeSut(params.metadata(metadata.dump()));
98
Szymon Dompke3a617022021-07-19 18:23:02 +020099 EXPECT_THAT(
100 sut->getReadings(),
101 ElementsAre(
102 MetricValue{"id", ReadingMetadata("", "sensor1").dump(), 0., 0u},
103 MetricValue{"id", ReadingMetadata("", "sensor2").dump(), 0., 0u}));
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000104}
105
106TEST_F(TestMetric, parsesSensorMetadataWhenMoreMetadataThanSensors)
107{
108 nlohmann::json metadata;
109 metadata["MetricProperties"] = {"sensor1", "sensor2"};
110
111 sensorMocks = makeSensorMocks(1);
112 sut = makeSut(params.metadata(metadata.dump()));
113
114 EXPECT_THAT(sut->getReadings(),
115 ElementsAre(MetricValue{"id", metadata.dump(), 0., 0u}));
116}
117
118TEST_F(TestMetric, parsesSensorMetadataWhenMoreSensorsThanMetadata)
119{
120 nlohmann::json metadata;
121 metadata["MetricProperties"] = {"sensor1"};
122
123 sensorMocks = makeSensorMocks(2);
124 sut = makeSut(params.metadata(metadata.dump()));
125
126 EXPECT_THAT(sut->getReadings(),
127 ElementsAre(MetricValue{"id", metadata.dump(), 0., 0u},
128 MetricValue{"id", metadata.dump(), 0., 0u}));
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000129}
130
131class TestMetricAfterInitialization : public TestMetric
132{
133 public:
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000134 void SetUp() override
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100135 {
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000136 sut = makeSut(params);
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000137 sut->initialize();
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100138 }
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000139};
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100140
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000141TEST_F(TestMetricAfterInitialization, containsEmptyReading)
142{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000143 ASSERT_THAT(sut->getReadings(),
144 ElementsAre(MetricValue({"id", "metadata", 0., 0u})));
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100145}
146
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000147TEST_F(TestMetricAfterInitialization, updatesMetricValuesOnSensorUpdate)
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100148{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000149 sut->sensorUpdated(*sensorMocks.front(), Timestamp{18}, 31.2);
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000150
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000151 ASSERT_THAT(sut->getReadings(),
152 ElementsAre(MetricValue{"id", "metadata", 31.2, 18u}));
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100153}
154
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000155TEST_F(TestMetricAfterInitialization,
156 throwsWhenUpdateIsPerformedOnUnknownSensor)
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100157{
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100158 auto sensor = std::make_shared<StrictMock<SensorMock>>();
159 EXPECT_THROW(sut->sensorUpdated(*sensor, Timestamp{10}), std::out_of_range);
160 EXPECT_THROW(sut->sensorUpdated(*sensor, Timestamp{10}, 20.0),
161 std::out_of_range);
162}
163
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000164TEST_F(TestMetricAfterInitialization, dumpsConfiguration)
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100165{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000166 namespace ts = utils::tstring;
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000167
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000168 ON_CALL(*sensorMocks.front(), id())
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000169 .WillByDefault(Return(SensorMock::makeId("service1", "path1")));
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100170
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000171 const auto conf = sut->dumpConfiguration();
172
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000173 LabeledMetricParameters expected = {};
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000174 expected.at_label<ts::Id>() = params.id();
175 expected.at_label<ts::MetricMetadata>() = params.metadata();
176 expected.at_label<ts::OperationType>() = params.operationType();
177 expected.at_label<ts::CollectionTimeScope>() = params.collectionTimeScope();
178 expected.at_label<ts::CollectionDuration>() = params.collectionDuration();
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000179 expected.at_label<ts::SensorPath>() = {
180 LabeledSensorParameters("service1", "path1")};
181
182 EXPECT_THAT(conf, Eq(expected));
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100183}
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000184
185class TestMetricCalculationFunctions :
186 public TestMetric,
187 public WithParamInterface<MetricParams>
188{
189 public:
190 void SetUp() override
191 {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200192 clockFake.reset();
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000193 sut = makeSut(params.operationType(GetParam().operationType())
194 .collectionTimeScope(GetParam().collectionTimeScope())
195 .collectionDuration(GetParam().collectionDuration()));
196 }
197
198 static std::vector<std::pair<Milliseconds, double>> defaultReadings()
199 {
200 std::vector<std::pair<Milliseconds, double>> ret;
201 ret.emplace_back(0ms, std::numeric_limits<double>::quiet_NaN());
202 ret.emplace_back(10ms, 14.);
203 ret.emplace_back(1ms, 3.);
204 ret.emplace_back(5ms, 7.);
205 return ret;
206 }
207};
208
209MetricParams defaultSingleParams()
210{
211 return MetricParams()
212 .operationType(OperationType::single)
213 .readings(TestMetricCalculationFunctions::defaultReadings())
214 .expectedReading(11ms, 7.0);
215}
216
217INSTANTIATE_TEST_SUITE_P(
218 OperationSingleReturnsLastReading, TestMetricCalculationFunctions,
219 Values(
220 defaultSingleParams().collectionTimeScope(CollectionTimeScope::point),
221 defaultSingleParams()
222 .collectionTimeScope(CollectionTimeScope::interval)
223 .collectionDuration(CollectionDuration(100ms)),
224 defaultSingleParams().collectionTimeScope(
225 CollectionTimeScope::startup)));
226
227MetricParams defaultPointParams()
228{
229 return defaultSingleParams().collectionTimeScope(
230 CollectionTimeScope::point);
231}
232
233INSTANTIATE_TEST_SUITE_P(
234 TimeScopePointReturnsLastReading, TestMetricCalculationFunctions,
235 Values(defaultPointParams().operationType(OperationType::single),
236 defaultPointParams().operationType(OperationType::min),
237 defaultPointParams().operationType(OperationType::max),
238 defaultPointParams().operationType(OperationType::sum),
239 defaultPointParams().operationType(OperationType::avg)));
240
241MetricParams defaultMinParams()
242{
243 return defaultSingleParams().operationType(OperationType::min);
244}
245
246INSTANTIATE_TEST_SUITE_P(
247 ReturnsMinForGivenTimeScope, TestMetricCalculationFunctions,
248 Values(defaultMinParams()
249 .collectionTimeScope(CollectionTimeScope::interval)
250 .collectionDuration(CollectionDuration(100ms))
251 .expectedReading(10ms, 3.0),
252 defaultMinParams()
253 .collectionTimeScope(CollectionTimeScope::interval)
254 .collectionDuration(CollectionDuration(3ms))
255 .expectedReading(13ms, 7.0),
256 defaultMinParams()
257 .collectionTimeScope(CollectionTimeScope::startup)
258 .expectedReading(10ms, 3.0)));
259
260MetricParams defaultMaxParams()
261{
262 return defaultSingleParams().operationType(OperationType::max);
263}
264
265INSTANTIATE_TEST_SUITE_P(
266 ReturnsMaxForGivenTimeScope, TestMetricCalculationFunctions,
267 Values(defaultMaxParams()
268 .collectionTimeScope(CollectionTimeScope::interval)
269 .collectionDuration(CollectionDuration(100ms))
270 .expectedReading(0ms, 14.0),
271 defaultMaxParams()
272 .collectionTimeScope(CollectionTimeScope::interval)
273 .collectionDuration(CollectionDuration(6ms))
274 .expectedReading(10ms, 14.0),
275 defaultMaxParams()
276 .collectionTimeScope(CollectionTimeScope::interval)
277 .collectionDuration(CollectionDuration(5ms))
278 .expectedReading(11ms, 7.0),
279 defaultMaxParams()
280 .collectionTimeScope(CollectionTimeScope::startup)
281 .expectedReading(0ms, 14.0)));
282
283MetricParams defaultSumParams()
284{
285 return defaultSingleParams().operationType(OperationType::sum);
286}
287
288INSTANTIATE_TEST_SUITE_P(
289 ReturnsSumForGivenTimeScope, TestMetricCalculationFunctions,
290 Values(defaultSumParams()
291 .collectionTimeScope(CollectionTimeScope::interval)
292 .collectionDuration(CollectionDuration(100ms))
293 .expectedReading(16ms, 14. * 10 + 3. * 1 + 7 * 5),
294 defaultSumParams()
295 .collectionTimeScope(CollectionTimeScope::interval)
296 .collectionDuration(CollectionDuration(8ms))
297 .expectedReading(16ms, 14. * 2 + 3. * 1 + 7 * 5),
298 defaultSumParams()
299 .collectionTimeScope(CollectionTimeScope::interval)
300 .collectionDuration(CollectionDuration(6ms))
301 .expectedReading(16ms, 3. * 1 + 7 * 5),
302 defaultSumParams()
303 .collectionTimeScope(CollectionTimeScope::startup)
304 .expectedReading(16ms, 14. * 10 + 3. * 1 + 7 * 5)));
305
306MetricParams defaultAvgParams()
307{
308 return defaultSingleParams().operationType(OperationType::avg);
309}
310
311INSTANTIATE_TEST_SUITE_P(
312 ReturnsAvgForGivenTimeScope, TestMetricCalculationFunctions,
313 Values(defaultAvgParams()
314 .collectionTimeScope(CollectionTimeScope::interval)
315 .collectionDuration(CollectionDuration(100ms))
316 .expectedReading(16ms, (14. * 10 + 3. * 1 + 7 * 5) / 16.),
317 defaultAvgParams()
318 .collectionTimeScope(CollectionTimeScope::interval)
319 .collectionDuration(CollectionDuration(8ms))
320 .expectedReading(16ms, (14. * 2 + 3. * 1 + 7 * 5) / 8.),
321 defaultAvgParams()
322 .collectionTimeScope(CollectionTimeScope::interval)
323 .collectionDuration(CollectionDuration(6ms))
324 .expectedReading(16ms, (3. * 1 + 7 * 5) / 6.),
325 defaultAvgParams()
326 .collectionTimeScope(CollectionTimeScope::startup)
327 .expectedReading(16ms, (14. * 10 + 3. * 1 + 7 * 5) / 16.)));
328
329TEST_P(TestMetricCalculationFunctions, calculatesReadingValue)
330{
331 for (auto [timestamp, reading] : GetParam().readings())
332 {
333 sut->sensorUpdated(*sensorMocks.front(), clockFake.timestamp(),
334 reading);
335 clockFake.advance(timestamp);
336 }
337
338 const auto [expectedTimestamp, expectedReading] =
339 GetParam().expectedReading();
340 const auto readings = sut->getReadings();
341
342 EXPECT_THAT(readings, ElementsAre(MetricValue{
343 "id", "metadata", expectedReading,
344 ClockFake::toTimestamp(expectedTimestamp)}));
345}
346
347TEST_P(TestMetricCalculationFunctions,
348 calculatedReadingValueWithIntermediateCalculations)
349{
350 for (auto [timestamp, reading] : GetParam().readings())
351 {
352 sut->sensorUpdated(*sensorMocks.front(), clockFake.timestamp(),
353 reading);
354 clockFake.advance(timestamp);
355 sut->getReadings();
356 }
357
358 const auto [expectedTimestamp, expectedReading] =
359 GetParam().expectedReading();
360 const auto readings = sut->getReadings();
361
362 EXPECT_THAT(readings, ElementsAre(MetricValue{
363 "id", "metadata", expectedReading,
364 ClockFake::toTimestamp(expectedTimestamp)}));
365}