blob: fcb2deda88d09a83cd3be0cc7278ef31dc963180 [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
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010017constexpr Milliseconds systemTimestamp = 42ms;
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +010018
19class TestMetric : public Test
20{
21 public:
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +010022 TestMetric()
23 {
24 clockFake.steady.reset();
25 clockFake.system.set(systemTimestamp);
26 }
27
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000028 static std::vector<std::shared_ptr<SensorMock>>
29 makeSensorMocks(size_t amount)
30 {
31 std::vector<std::shared_ptr<SensorMock>> result;
32 for (size_t i = 0; i < amount; ++i)
33 {
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010034 auto& metricMock =
35 result.emplace_back(std::make_shared<NiceMock<SensorMock>>());
36 ON_CALL(*metricMock, metadata()).WillByDefault(Return("metadata"));
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000037 }
38 return result;
39 }
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +010040
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000041 std::shared_ptr<Metric> makeSut(const MetricParams& p)
42 {
43 return std::make_shared<Metric>(
44 utils::convContainer<std::shared_ptr<interfaces::Sensor>>(
45 sensorMocks),
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010046 p.operationType(), p.id(), p.collectionTimeScope(),
Krzysztof Grobelny80697712021-03-04 09:49:27 +000047 p.collectionDuration(), std::move(clockFakePtr));
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000048 }
49
Krzysztof Grobelny80697712021-03-04 09:49:27 +000050 MetricParams params = MetricParams()
51 .id("id")
Krzysztof Grobelny80697712021-03-04 09:49:27 +000052 .operationType(OperationType::avg)
53 .collectionTimeScope(CollectionTimeScope::point)
54 .collectionDuration(CollectionDuration(0ms));
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000055 std::vector<std::shared_ptr<SensorMock>> sensorMocks = makeSensorMocks(1u);
Krzysztof Grobelny80697712021-03-04 09:49:27 +000056 std::unique_ptr<ClockFake> clockFakePtr = std::make_unique<ClockFake>();
57 ClockFake& clockFake = *clockFakePtr;
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000058 std::shared_ptr<Metric> sut;
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +010059};
60
61TEST_F(TestMetric, subscribesForSensorDuringInitialization)
62{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000063 sut = makeSut(params);
64
65 EXPECT_CALL(*sensorMocks.front(),
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +000066 registerForUpdates(Truly([sut = sut.get()](const auto& a0) {
67 return a0.lock().get() == sut;
68 })));
69
70 sut->initialize();
71}
72
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +020073TEST_F(TestMetric, unsubscribesForSensorDuringDeinitialization)
74{
75 sut = makeSut(params);
76
77 EXPECT_CALL(*sensorMocks.front(),
78 unregisterFromUpdates(Truly([sut = sut.get()](const auto& a0) {
79 return a0.lock().get() == sut;
80 })));
81
82 sut->deinitialize();
83}
84
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +000085TEST_F(TestMetric, containsEmptyReadingAfterCreated)
86{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000087 sut = makeSut(params);
88
89 ASSERT_THAT(sut->getReadings(),
90 ElementsAre(MetricValue({"id", "metadata", 0., 0u})));
91}
92
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +000093class TestMetricAfterInitialization : public TestMetric
94{
95 public:
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000096 void SetUp() override
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +010097 {
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000098 sut = makeSut(params);
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +000099 sut->initialize();
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100100 }
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000101};
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100102
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000103TEST_F(TestMetricAfterInitialization, containsEmptyReading)
104{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000105 ASSERT_THAT(sut->getReadings(),
106 ElementsAre(MetricValue({"id", "metadata", 0., 0u})));
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100107}
108
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000109TEST_F(TestMetricAfterInitialization, updatesMetricValuesOnSensorUpdate)
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100110{
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100111 sut->sensorUpdated(*sensorMocks.front(), Milliseconds{18}, 31.2);
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000112
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100113 ASSERT_THAT(
114 sut->getReadings(),
115 ElementsAre(MetricValue{"id", "metadata", 31.2,
116 std::chrono::duration_cast<Milliseconds>(
117 clockFake.system.timestamp())
118 .count()}));
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100119}
120
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000121TEST_F(TestMetricAfterInitialization,
122 throwsWhenUpdateIsPerformedOnUnknownSensor)
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100123{
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100124 auto sensor = std::make_shared<StrictMock<SensorMock>>();
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100125 EXPECT_THROW(sut->sensorUpdated(*sensor, Milliseconds{10}),
126 std::out_of_range);
127 EXPECT_THROW(sut->sensorUpdated(*sensor, Milliseconds{10}, 20.0),
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100128 std::out_of_range);
129}
130
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000131TEST_F(TestMetricAfterInitialization, dumpsConfiguration)
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100132{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000133 namespace ts = utils::tstring;
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000134
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000135 ON_CALL(*sensorMocks.front(), id())
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000136 .WillByDefault(Return(SensorMock::makeId("service1", "path1")));
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100137 ON_CALL(*sensorMocks.front(), metadata())
138 .WillByDefault(Return("metadata1"));
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100139
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000140 const auto conf = sut->dumpConfiguration();
141
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000142 LabeledMetricParameters expected = {};
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000143 expected.at_label<ts::Id>() = params.id();
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000144 expected.at_label<ts::OperationType>() = params.operationType();
145 expected.at_label<ts::CollectionTimeScope>() = params.collectionTimeScope();
146 expected.at_label<ts::CollectionDuration>() = params.collectionDuration();
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000147 expected.at_label<ts::SensorPath>() = {
Szymon Dompke94f71c52021-12-10 07:16:33 +0100148 LabeledSensorInfo("service1", "path1", "metadata1")};
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000149
150 EXPECT_THAT(conf, Eq(expected));
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100151}
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000152
153class TestMetricCalculationFunctions :
154 public TestMetric,
155 public WithParamInterface<MetricParams>
156{
157 public:
158 void SetUp() override
159 {
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000160 sut = makeSut(params.operationType(GetParam().operationType())
161 .collectionTimeScope(GetParam().collectionTimeScope())
162 .collectionDuration(GetParam().collectionDuration()));
163 }
164
165 static std::vector<std::pair<Milliseconds, double>> defaultReadings()
166 {
167 std::vector<std::pair<Milliseconds, double>> ret;
168 ret.emplace_back(0ms, std::numeric_limits<double>::quiet_NaN());
169 ret.emplace_back(10ms, 14.);
170 ret.emplace_back(1ms, 3.);
171 ret.emplace_back(5ms, 7.);
172 return ret;
173 }
174};
175
176MetricParams defaultSingleParams()
177{
178 return MetricParams()
179 .operationType(OperationType::single)
180 .readings(TestMetricCalculationFunctions::defaultReadings())
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100181 .expectedReading(systemTimestamp + 16ms, 7.0);
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000182}
183
184INSTANTIATE_TEST_SUITE_P(
185 OperationSingleReturnsLastReading, TestMetricCalculationFunctions,
186 Values(
187 defaultSingleParams().collectionTimeScope(CollectionTimeScope::point),
188 defaultSingleParams()
189 .collectionTimeScope(CollectionTimeScope::interval)
190 .collectionDuration(CollectionDuration(100ms)),
191 defaultSingleParams().collectionTimeScope(
192 CollectionTimeScope::startup)));
193
194MetricParams defaultPointParams()
195{
196 return defaultSingleParams().collectionTimeScope(
197 CollectionTimeScope::point);
198}
199
200INSTANTIATE_TEST_SUITE_P(
201 TimeScopePointReturnsLastReading, TestMetricCalculationFunctions,
202 Values(defaultPointParams().operationType(OperationType::single),
203 defaultPointParams().operationType(OperationType::min),
204 defaultPointParams().operationType(OperationType::max),
205 defaultPointParams().operationType(OperationType::sum),
206 defaultPointParams().operationType(OperationType::avg)));
207
208MetricParams defaultMinParams()
209{
210 return defaultSingleParams().operationType(OperationType::min);
211}
212
213INSTANTIATE_TEST_SUITE_P(
214 ReturnsMinForGivenTimeScope, TestMetricCalculationFunctions,
215 Values(defaultMinParams()
216 .collectionTimeScope(CollectionTimeScope::interval)
217 .collectionDuration(CollectionDuration(100ms))
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100218 .expectedReading(systemTimestamp + 16ms, 3.0),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000219 defaultMinParams()
220 .collectionTimeScope(CollectionTimeScope::interval)
221 .collectionDuration(CollectionDuration(3ms))
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100222 .expectedReading(systemTimestamp + 16ms, 7.0),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000223 defaultMinParams()
224 .collectionTimeScope(CollectionTimeScope::startup)
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100225 .expectedReading(systemTimestamp + 16ms, 3.0)));
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000226
227MetricParams defaultMaxParams()
228{
229 return defaultSingleParams().operationType(OperationType::max);
230}
231
232INSTANTIATE_TEST_SUITE_P(
233 ReturnsMaxForGivenTimeScope, TestMetricCalculationFunctions,
234 Values(defaultMaxParams()
235 .collectionTimeScope(CollectionTimeScope::interval)
236 .collectionDuration(CollectionDuration(100ms))
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100237 .expectedReading(systemTimestamp + 16ms, 14.0),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000238 defaultMaxParams()
239 .collectionTimeScope(CollectionTimeScope::interval)
240 .collectionDuration(CollectionDuration(6ms))
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100241 .expectedReading(systemTimestamp + 16ms, 14.0),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000242 defaultMaxParams()
243 .collectionTimeScope(CollectionTimeScope::interval)
244 .collectionDuration(CollectionDuration(5ms))
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100245 .expectedReading(systemTimestamp + 16ms, 7.0),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000246 defaultMaxParams()
247 .collectionTimeScope(CollectionTimeScope::startup)
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100248 .expectedReading(systemTimestamp + 16ms, 14.0)));
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000249
250MetricParams defaultSumParams()
251{
252 return defaultSingleParams().operationType(OperationType::sum);
253}
254
255INSTANTIATE_TEST_SUITE_P(
256 ReturnsSumForGivenTimeScope, TestMetricCalculationFunctions,
257 Values(defaultSumParams()
258 .collectionTimeScope(CollectionTimeScope::interval)
259 .collectionDuration(CollectionDuration(100ms))
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100260 .expectedReading(systemTimestamp + 16ms,
261 14. * 0.01 + 3. * 0.001 + 7. * 0.005),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000262 defaultSumParams()
263 .collectionTimeScope(CollectionTimeScope::interval)
264 .collectionDuration(CollectionDuration(8ms))
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100265 .expectedReading(systemTimestamp + 16ms,
266 14. * 0.002 + 3. * 0.001 + 7 * 0.005),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000267 defaultSumParams()
268 .collectionTimeScope(CollectionTimeScope::interval)
269 .collectionDuration(CollectionDuration(6ms))
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100270 .expectedReading(systemTimestamp + 16ms, 3. * 0.001 + 7 * 0.005),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000271 defaultSumParams()
272 .collectionTimeScope(CollectionTimeScope::startup)
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100273 .expectedReading(systemTimestamp + 16ms,
274 14. * 0.01 + 3. * 0.001 + 7 * 0.005)));
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000275
276MetricParams defaultAvgParams()
277{
278 return defaultSingleParams().operationType(OperationType::avg);
279}
280
281INSTANTIATE_TEST_SUITE_P(
282 ReturnsAvgForGivenTimeScope, TestMetricCalculationFunctions,
283 Values(defaultAvgParams()
284 .collectionTimeScope(CollectionTimeScope::interval)
285 .collectionDuration(CollectionDuration(100ms))
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100286 .expectedReading(systemTimestamp + 16ms,
287 (14. * 10 + 3. * 1 + 7 * 5) / 16.),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000288 defaultAvgParams()
289 .collectionTimeScope(CollectionTimeScope::interval)
290 .collectionDuration(CollectionDuration(8ms))
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100291 .expectedReading(systemTimestamp + 16ms,
292 (14. * 2 + 3. * 1 + 7 * 5) / 8.),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000293 defaultAvgParams()
294 .collectionTimeScope(CollectionTimeScope::interval)
295 .collectionDuration(CollectionDuration(6ms))
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100296 .expectedReading(systemTimestamp + 16ms, (3. * 1 + 7 * 5) / 6.),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000297 defaultAvgParams()
298 .collectionTimeScope(CollectionTimeScope::startup)
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100299 .expectedReading(systemTimestamp + 16ms,
300 (14. * 10 + 3. * 1 + 7 * 5) / 16.)));
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000301
302TEST_P(TestMetricCalculationFunctions, calculatesReadingValue)
303{
304 for (auto [timestamp, reading] : GetParam().readings())
305 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100306 sut->sensorUpdated(*sensorMocks.front(), clockFake.steadyTimestamp(),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000307 reading);
308 clockFake.advance(timestamp);
309 }
310
311 const auto [expectedTimestamp, expectedReading] =
312 GetParam().expectedReading();
313 const auto readings = sut->getReadings();
314
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100315 EXPECT_THAT(readings,
316 ElementsAre(MetricValue{"id", "metadata", expectedReading,
317 expectedTimestamp.count()}));
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000318}
319
320TEST_P(TestMetricCalculationFunctions,
321 calculatedReadingValueWithIntermediateCalculations)
322{
323 for (auto [timestamp, reading] : GetParam().readings())
324 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100325 sut->sensorUpdated(*sensorMocks.front(), clockFake.steadyTimestamp(),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000326 reading);
327 clockFake.advance(timestamp);
328 sut->getReadings();
329 }
330
331 const auto [expectedTimestamp, expectedReading] =
332 GetParam().expectedReading();
333 const auto readings = sut->getReadings();
334
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100335 EXPECT_THAT(readings,
336 ElementsAre(MetricValue{"id", "metadata", expectedReading,
337 expectedTimestamp.count()}));
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000338}