blob: 87e32f90bf8c840138559c4a8bb1fae180534b4e [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
66TEST_F(TestMetric, containsEmptyReadingAfterCreated)
67{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000068 sut = makeSut(params);
69
70 ASSERT_THAT(sut->getReadings(),
71 ElementsAre(MetricValue({"id", "metadata", 0., 0u})));
72}
73
74TEST_F(TestMetric, parsesSensorMetadata)
75{
Szymon Dompke3a617022021-07-19 18:23:02 +020076 using ReadingMetadata =
77 utils::LabeledTuple<std::tuple<std::string, std::string>,
78 utils::tstring::SensorDbusPath,
79 utils::tstring::SensorRedfishUri>;
80
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000081 nlohmann::json metadata;
82 metadata["MetricProperties"] = {"sensor1", "sensor2"};
83
84 sensorMocks = makeSensorMocks(2);
85 sut = makeSut(params.metadata(metadata.dump()));
86
Szymon Dompke3a617022021-07-19 18:23:02 +020087 EXPECT_THAT(
88 sut->getReadings(),
89 ElementsAre(
90 MetricValue{"id", ReadingMetadata("", "sensor1").dump(), 0., 0u},
91 MetricValue{"id", ReadingMetadata("", "sensor2").dump(), 0., 0u}));
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000092}
93
94TEST_F(TestMetric, parsesSensorMetadataWhenMoreMetadataThanSensors)
95{
96 nlohmann::json metadata;
97 metadata["MetricProperties"] = {"sensor1", "sensor2"};
98
99 sensorMocks = makeSensorMocks(1);
100 sut = makeSut(params.metadata(metadata.dump()));
101
102 EXPECT_THAT(sut->getReadings(),
103 ElementsAre(MetricValue{"id", metadata.dump(), 0., 0u}));
104}
105
106TEST_F(TestMetric, parsesSensorMetadataWhenMoreSensorsThanMetadata)
107{
108 nlohmann::json metadata;
109 metadata["MetricProperties"] = {"sensor1"};
110
111 sensorMocks = makeSensorMocks(2);
112 sut = makeSut(params.metadata(metadata.dump()));
113
114 EXPECT_THAT(sut->getReadings(),
115 ElementsAre(MetricValue{"id", metadata.dump(), 0., 0u},
116 MetricValue{"id", metadata.dump(), 0., 0u}));
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000117}
118
119class TestMetricAfterInitialization : public TestMetric
120{
121 public:
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000122 void SetUp() override
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100123 {
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000124 sut = makeSut(params);
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000125 sut->initialize();
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100126 }
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000127};
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100128
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000129TEST_F(TestMetricAfterInitialization, containsEmptyReading)
130{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000131 ASSERT_THAT(sut->getReadings(),
132 ElementsAre(MetricValue({"id", "metadata", 0., 0u})));
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100133}
134
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000135TEST_F(TestMetricAfterInitialization, updatesMetricValuesOnSensorUpdate)
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100136{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000137 sut->sensorUpdated(*sensorMocks.front(), Timestamp{18}, 31.2);
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000138
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000139 ASSERT_THAT(sut->getReadings(),
140 ElementsAre(MetricValue{"id", "metadata", 31.2, 18u}));
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100141}
142
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000143TEST_F(TestMetricAfterInitialization,
144 throwsWhenUpdateIsPerformedOnUnknownSensor)
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100145{
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100146 auto sensor = std::make_shared<StrictMock<SensorMock>>();
147 EXPECT_THROW(sut->sensorUpdated(*sensor, Timestamp{10}), std::out_of_range);
148 EXPECT_THROW(sut->sensorUpdated(*sensor, Timestamp{10}, 20.0),
149 std::out_of_range);
150}
151
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000152TEST_F(TestMetricAfterInitialization, dumpsConfiguration)
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100153{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000154 namespace ts = utils::tstring;
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000155
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000156 ON_CALL(*sensorMocks.front(), id())
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000157 .WillByDefault(Return(SensorMock::makeId("service1", "path1")));
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100158
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000159 const auto conf = sut->dumpConfiguration();
160
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000161 LabeledMetricParameters expected = {};
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000162 expected.at_label<ts::Id>() = params.id();
163 expected.at_label<ts::MetricMetadata>() = params.metadata();
164 expected.at_label<ts::OperationType>() = params.operationType();
165 expected.at_label<ts::CollectionTimeScope>() = params.collectionTimeScope();
166 expected.at_label<ts::CollectionDuration>() = params.collectionDuration();
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000167 expected.at_label<ts::SensorPath>() = {
168 LabeledSensorParameters("service1", "path1")};
169
170 EXPECT_THAT(conf, Eq(expected));
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100171}
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000172
173class TestMetricCalculationFunctions :
174 public TestMetric,
175 public WithParamInterface<MetricParams>
176{
177 public:
178 void SetUp() override
179 {
180 clockFakePtr->set(0ms);
181
182 sut = makeSut(params.operationType(GetParam().operationType())
183 .collectionTimeScope(GetParam().collectionTimeScope())
184 .collectionDuration(GetParam().collectionDuration()));
185 }
186
187 static std::vector<std::pair<Milliseconds, double>> defaultReadings()
188 {
189 std::vector<std::pair<Milliseconds, double>> ret;
190 ret.emplace_back(0ms, std::numeric_limits<double>::quiet_NaN());
191 ret.emplace_back(10ms, 14.);
192 ret.emplace_back(1ms, 3.);
193 ret.emplace_back(5ms, 7.);
194 return ret;
195 }
196};
197
198MetricParams defaultSingleParams()
199{
200 return MetricParams()
201 .operationType(OperationType::single)
202 .readings(TestMetricCalculationFunctions::defaultReadings())
203 .expectedReading(11ms, 7.0);
204}
205
206INSTANTIATE_TEST_SUITE_P(
207 OperationSingleReturnsLastReading, TestMetricCalculationFunctions,
208 Values(
209 defaultSingleParams().collectionTimeScope(CollectionTimeScope::point),
210 defaultSingleParams()
211 .collectionTimeScope(CollectionTimeScope::interval)
212 .collectionDuration(CollectionDuration(100ms)),
213 defaultSingleParams().collectionTimeScope(
214 CollectionTimeScope::startup)));
215
216MetricParams defaultPointParams()
217{
218 return defaultSingleParams().collectionTimeScope(
219 CollectionTimeScope::point);
220}
221
222INSTANTIATE_TEST_SUITE_P(
223 TimeScopePointReturnsLastReading, TestMetricCalculationFunctions,
224 Values(defaultPointParams().operationType(OperationType::single),
225 defaultPointParams().operationType(OperationType::min),
226 defaultPointParams().operationType(OperationType::max),
227 defaultPointParams().operationType(OperationType::sum),
228 defaultPointParams().operationType(OperationType::avg)));
229
230MetricParams defaultMinParams()
231{
232 return defaultSingleParams().operationType(OperationType::min);
233}
234
235INSTANTIATE_TEST_SUITE_P(
236 ReturnsMinForGivenTimeScope, TestMetricCalculationFunctions,
237 Values(defaultMinParams()
238 .collectionTimeScope(CollectionTimeScope::interval)
239 .collectionDuration(CollectionDuration(100ms))
240 .expectedReading(10ms, 3.0),
241 defaultMinParams()
242 .collectionTimeScope(CollectionTimeScope::interval)
243 .collectionDuration(CollectionDuration(3ms))
244 .expectedReading(13ms, 7.0),
245 defaultMinParams()
246 .collectionTimeScope(CollectionTimeScope::startup)
247 .expectedReading(10ms, 3.0)));
248
249MetricParams defaultMaxParams()
250{
251 return defaultSingleParams().operationType(OperationType::max);
252}
253
254INSTANTIATE_TEST_SUITE_P(
255 ReturnsMaxForGivenTimeScope, TestMetricCalculationFunctions,
256 Values(defaultMaxParams()
257 .collectionTimeScope(CollectionTimeScope::interval)
258 .collectionDuration(CollectionDuration(100ms))
259 .expectedReading(0ms, 14.0),
260 defaultMaxParams()
261 .collectionTimeScope(CollectionTimeScope::interval)
262 .collectionDuration(CollectionDuration(6ms))
263 .expectedReading(10ms, 14.0),
264 defaultMaxParams()
265 .collectionTimeScope(CollectionTimeScope::interval)
266 .collectionDuration(CollectionDuration(5ms))
267 .expectedReading(11ms, 7.0),
268 defaultMaxParams()
269 .collectionTimeScope(CollectionTimeScope::startup)
270 .expectedReading(0ms, 14.0)));
271
272MetricParams defaultSumParams()
273{
274 return defaultSingleParams().operationType(OperationType::sum);
275}
276
277INSTANTIATE_TEST_SUITE_P(
278 ReturnsSumForGivenTimeScope, TestMetricCalculationFunctions,
279 Values(defaultSumParams()
280 .collectionTimeScope(CollectionTimeScope::interval)
281 .collectionDuration(CollectionDuration(100ms))
282 .expectedReading(16ms, 14. * 10 + 3. * 1 + 7 * 5),
283 defaultSumParams()
284 .collectionTimeScope(CollectionTimeScope::interval)
285 .collectionDuration(CollectionDuration(8ms))
286 .expectedReading(16ms, 14. * 2 + 3. * 1 + 7 * 5),
287 defaultSumParams()
288 .collectionTimeScope(CollectionTimeScope::interval)
289 .collectionDuration(CollectionDuration(6ms))
290 .expectedReading(16ms, 3. * 1 + 7 * 5),
291 defaultSumParams()
292 .collectionTimeScope(CollectionTimeScope::startup)
293 .expectedReading(16ms, 14. * 10 + 3. * 1 + 7 * 5)));
294
295MetricParams defaultAvgParams()
296{
297 return defaultSingleParams().operationType(OperationType::avg);
298}
299
300INSTANTIATE_TEST_SUITE_P(
301 ReturnsAvgForGivenTimeScope, TestMetricCalculationFunctions,
302 Values(defaultAvgParams()
303 .collectionTimeScope(CollectionTimeScope::interval)
304 .collectionDuration(CollectionDuration(100ms))
305 .expectedReading(16ms, (14. * 10 + 3. * 1 + 7 * 5) / 16.),
306 defaultAvgParams()
307 .collectionTimeScope(CollectionTimeScope::interval)
308 .collectionDuration(CollectionDuration(8ms))
309 .expectedReading(16ms, (14. * 2 + 3. * 1 + 7 * 5) / 8.),
310 defaultAvgParams()
311 .collectionTimeScope(CollectionTimeScope::interval)
312 .collectionDuration(CollectionDuration(6ms))
313 .expectedReading(16ms, (3. * 1 + 7 * 5) / 6.),
314 defaultAvgParams()
315 .collectionTimeScope(CollectionTimeScope::startup)
316 .expectedReading(16ms, (14. * 10 + 3. * 1 + 7 * 5) / 16.)));
317
318TEST_P(TestMetricCalculationFunctions, calculatesReadingValue)
319{
320 for (auto [timestamp, reading] : GetParam().readings())
321 {
322 sut->sensorUpdated(*sensorMocks.front(), clockFake.timestamp(),
323 reading);
324 clockFake.advance(timestamp);
325 }
326
327 const auto [expectedTimestamp, expectedReading] =
328 GetParam().expectedReading();
329 const auto readings = sut->getReadings();
330
331 EXPECT_THAT(readings, ElementsAre(MetricValue{
332 "id", "metadata", expectedReading,
333 ClockFake::toTimestamp(expectedTimestamp)}));
334}
335
336TEST_P(TestMetricCalculationFunctions,
337 calculatedReadingValueWithIntermediateCalculations)
338{
339 for (auto [timestamp, reading] : GetParam().readings())
340 {
341 sut->sensorUpdated(*sensorMocks.front(), clockFake.timestamp(),
342 reading);
343 clockFake.advance(timestamp);
344 sut->getReadings();
345 }
346
347 const auto [expectedTimestamp, expectedReading] =
348 GetParam().expectedReading();
349 const auto readings = sut->getReadings();
350
351 EXPECT_THAT(readings, ElementsAre(MetricValue{
352 "id", "metadata", expectedReading,
353 ClockFake::toTimestamp(expectedTimestamp)}));
354}