blob: 31eabc693fc042b73fce343448363b7231a43dd2 [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
Krzysztof Grobelny60fee072022-01-13 16:25:04 +0100176MetricParams defaultCollectionFunctionParams()
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000177{
178 return MetricParams()
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000179 .readings(TestMetricCalculationFunctions::defaultReadings())
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100180 .expectedReading(systemTimestamp + 16ms, 7.0);
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000181}
182
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000183MetricParams defaultPointParams()
184{
Krzysztof Grobelny60fee072022-01-13 16:25:04 +0100185 return defaultCollectionFunctionParams().collectionTimeScope(
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000186 CollectionTimeScope::point);
187}
188
189INSTANTIATE_TEST_SUITE_P(
190 TimeScopePointReturnsLastReading, TestMetricCalculationFunctions,
Krzysztof Grobelny60fee072022-01-13 16:25:04 +0100191 Values(defaultPointParams().operationType(OperationType::min),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000192 defaultPointParams().operationType(OperationType::max),
193 defaultPointParams().operationType(OperationType::sum),
194 defaultPointParams().operationType(OperationType::avg)));
195
196MetricParams defaultMinParams()
197{
Krzysztof Grobelny60fee072022-01-13 16:25:04 +0100198 return defaultCollectionFunctionParams().operationType(OperationType::min);
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000199}
200
201INSTANTIATE_TEST_SUITE_P(
202 ReturnsMinForGivenTimeScope, TestMetricCalculationFunctions,
203 Values(defaultMinParams()
204 .collectionTimeScope(CollectionTimeScope::interval)
205 .collectionDuration(CollectionDuration(100ms))
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100206 .expectedReading(systemTimestamp + 16ms, 3.0),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000207 defaultMinParams()
208 .collectionTimeScope(CollectionTimeScope::interval)
209 .collectionDuration(CollectionDuration(3ms))
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100210 .expectedReading(systemTimestamp + 16ms, 7.0),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000211 defaultMinParams()
212 .collectionTimeScope(CollectionTimeScope::startup)
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100213 .expectedReading(systemTimestamp + 16ms, 3.0)));
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000214
215MetricParams defaultMaxParams()
216{
Krzysztof Grobelny60fee072022-01-13 16:25:04 +0100217 return defaultCollectionFunctionParams().operationType(OperationType::max);
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000218}
219
220INSTANTIATE_TEST_SUITE_P(
221 ReturnsMaxForGivenTimeScope, TestMetricCalculationFunctions,
222 Values(defaultMaxParams()
223 .collectionTimeScope(CollectionTimeScope::interval)
224 .collectionDuration(CollectionDuration(100ms))
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100225 .expectedReading(systemTimestamp + 16ms, 14.0),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000226 defaultMaxParams()
227 .collectionTimeScope(CollectionTimeScope::interval)
228 .collectionDuration(CollectionDuration(6ms))
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100229 .expectedReading(systemTimestamp + 16ms, 14.0),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000230 defaultMaxParams()
231 .collectionTimeScope(CollectionTimeScope::interval)
232 .collectionDuration(CollectionDuration(5ms))
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100233 .expectedReading(systemTimestamp + 16ms, 7.0),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000234 defaultMaxParams()
235 .collectionTimeScope(CollectionTimeScope::startup)
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100236 .expectedReading(systemTimestamp + 16ms, 14.0)));
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000237
238MetricParams defaultSumParams()
239{
Krzysztof Grobelny60fee072022-01-13 16:25:04 +0100240 return defaultCollectionFunctionParams().operationType(OperationType::sum);
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000241}
242
243INSTANTIATE_TEST_SUITE_P(
244 ReturnsSumForGivenTimeScope, TestMetricCalculationFunctions,
245 Values(defaultSumParams()
246 .collectionTimeScope(CollectionTimeScope::interval)
247 .collectionDuration(CollectionDuration(100ms))
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100248 .expectedReading(systemTimestamp + 16ms,
249 14. * 0.01 + 3. * 0.001 + 7. * 0.005),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000250 defaultSumParams()
251 .collectionTimeScope(CollectionTimeScope::interval)
252 .collectionDuration(CollectionDuration(8ms))
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100253 .expectedReading(systemTimestamp + 16ms,
254 14. * 0.002 + 3. * 0.001 + 7 * 0.005),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000255 defaultSumParams()
256 .collectionTimeScope(CollectionTimeScope::interval)
257 .collectionDuration(CollectionDuration(6ms))
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100258 .expectedReading(systemTimestamp + 16ms, 3. * 0.001 + 7 * 0.005),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000259 defaultSumParams()
260 .collectionTimeScope(CollectionTimeScope::startup)
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100261 .expectedReading(systemTimestamp + 16ms,
262 14. * 0.01 + 3. * 0.001 + 7 * 0.005)));
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000263
264MetricParams defaultAvgParams()
265{
Krzysztof Grobelny60fee072022-01-13 16:25:04 +0100266 return defaultCollectionFunctionParams().operationType(OperationType::avg);
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000267}
268
269INSTANTIATE_TEST_SUITE_P(
270 ReturnsAvgForGivenTimeScope, TestMetricCalculationFunctions,
271 Values(defaultAvgParams()
272 .collectionTimeScope(CollectionTimeScope::interval)
273 .collectionDuration(CollectionDuration(100ms))
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100274 .expectedReading(systemTimestamp + 16ms,
275 (14. * 10 + 3. * 1 + 7 * 5) / 16.),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000276 defaultAvgParams()
277 .collectionTimeScope(CollectionTimeScope::interval)
278 .collectionDuration(CollectionDuration(8ms))
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100279 .expectedReading(systemTimestamp + 16ms,
280 (14. * 2 + 3. * 1 + 7 * 5) / 8.),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000281 defaultAvgParams()
282 .collectionTimeScope(CollectionTimeScope::interval)
283 .collectionDuration(CollectionDuration(6ms))
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100284 .expectedReading(systemTimestamp + 16ms, (3. * 1 + 7 * 5) / 6.),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000285 defaultAvgParams()
286 .collectionTimeScope(CollectionTimeScope::startup)
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100287 .expectedReading(systemTimestamp + 16ms,
288 (14. * 10 + 3. * 1 + 7 * 5) / 16.)));
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000289
290TEST_P(TestMetricCalculationFunctions, calculatesReadingValue)
291{
292 for (auto [timestamp, reading] : GetParam().readings())
293 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100294 sut->sensorUpdated(*sensorMocks.front(), clockFake.steadyTimestamp(),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000295 reading);
296 clockFake.advance(timestamp);
297 }
298
299 const auto [expectedTimestamp, expectedReading] =
300 GetParam().expectedReading();
301 const auto readings = sut->getReadings();
302
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100303 EXPECT_THAT(readings,
304 ElementsAre(MetricValue{"id", "metadata", expectedReading,
305 expectedTimestamp.count()}));
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000306}
307
308TEST_P(TestMetricCalculationFunctions,
309 calculatedReadingValueWithIntermediateCalculations)
310{
311 for (auto [timestamp, reading] : GetParam().readings())
312 {
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100313 sut->sensorUpdated(*sensorMocks.front(), clockFake.steadyTimestamp(),
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000314 reading);
315 clockFake.advance(timestamp);
316 sut->getReadings();
317 }
318
319 const auto [expectedTimestamp, expectedReading] =
320 GetParam().expectedReading();
321 const auto readings = sut->getReadings();
322
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100323 EXPECT_THAT(readings,
324 ElementsAre(MetricValue{"id", "metadata", expectedReading,
325 expectedTimestamp.count()}));
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000326}