blob: e19446cd8bd9fd0629a6991312402c4c48bcd49f [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 {
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010028 auto& metricMock =
29 result.emplace_back(std::make_shared<NiceMock<SensorMock>>());
30 ON_CALL(*metricMock, metadata()).WillByDefault(Return("metadata"));
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000031 }
32 return result;
33 }
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +010034
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000035 std::shared_ptr<Metric> makeSut(const MetricParams& p)
36 {
37 return std::make_shared<Metric>(
38 utils::convContainer<std::shared_ptr<interfaces::Sensor>>(
39 sensorMocks),
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +010040 p.operationType(), p.id(), p.collectionTimeScope(),
Krzysztof Grobelny80697712021-03-04 09:49:27 +000041 p.collectionDuration(), std::move(clockFakePtr));
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000042 }
43
Krzysztof Grobelny80697712021-03-04 09:49:27 +000044 MetricParams params = MetricParams()
45 .id("id")
Krzysztof Grobelny80697712021-03-04 09:49:27 +000046 .operationType(OperationType::avg)
47 .collectionTimeScope(CollectionTimeScope::point)
48 .collectionDuration(CollectionDuration(0ms));
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000049 std::vector<std::shared_ptr<SensorMock>> sensorMocks = makeSensorMocks(1u);
Krzysztof Grobelny80697712021-03-04 09:49:27 +000050 std::unique_ptr<ClockFake> clockFakePtr = std::make_unique<ClockFake>();
51 ClockFake& clockFake = *clockFakePtr;
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000052 std::shared_ptr<Metric> sut;
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +010053};
54
55TEST_F(TestMetric, subscribesForSensorDuringInitialization)
56{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000057 sut = makeSut(params);
58
59 EXPECT_CALL(*sensorMocks.front(),
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +000060 registerForUpdates(Truly([sut = sut.get()](const auto& a0) {
61 return a0.lock().get() == sut;
62 })));
63
64 sut->initialize();
65}
66
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +020067TEST_F(TestMetric, unsubscribesForSensorDuringDeinitialization)
68{
69 sut = makeSut(params);
70
71 EXPECT_CALL(*sensorMocks.front(),
72 unregisterFromUpdates(Truly([sut = sut.get()](const auto& a0) {
73 return a0.lock().get() == sut;
74 })));
75
76 sut->deinitialize();
77}
78
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +000079TEST_F(TestMetric, containsEmptyReadingAfterCreated)
80{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000081 sut = makeSut(params);
82
83 ASSERT_THAT(sut->getReadings(),
84 ElementsAre(MetricValue({"id", "metadata", 0., 0u})));
85}
86
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +000087class TestMetricAfterInitialization : public TestMetric
88{
89 public:
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000090 void SetUp() override
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +010091 {
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000092 sut = makeSut(params);
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +000093 sut->initialize();
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +010094 }
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +000095};
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +010096
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +000097TEST_F(TestMetricAfterInitialization, containsEmptyReading)
98{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +000099 ASSERT_THAT(sut->getReadings(),
100 ElementsAre(MetricValue({"id", "metadata", 0., 0u})));
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100101}
102
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000103TEST_F(TestMetricAfterInitialization, updatesMetricValuesOnSensorUpdate)
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100104{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000105 sut->sensorUpdated(*sensorMocks.front(), Timestamp{18}, 31.2);
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000106
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000107 ASSERT_THAT(sut->getReadings(),
108 ElementsAre(MetricValue{"id", "metadata", 31.2, 18u}));
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100109}
110
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000111TEST_F(TestMetricAfterInitialization,
112 throwsWhenUpdateIsPerformedOnUnknownSensor)
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100113{
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100114 auto sensor = std::make_shared<StrictMock<SensorMock>>();
115 EXPECT_THROW(sut->sensorUpdated(*sensor, Timestamp{10}), std::out_of_range);
116 EXPECT_THROW(sut->sensorUpdated(*sensor, Timestamp{10}, 20.0),
117 std::out_of_range);
118}
119
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000120TEST_F(TestMetricAfterInitialization, dumpsConfiguration)
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100121{
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000122 namespace ts = utils::tstring;
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000123
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000124 ON_CALL(*sensorMocks.front(), id())
Krzysztof Grobelnye8fc5752021-02-05 14:30:45 +0000125 .WillByDefault(Return(SensorMock::makeId("service1", "path1")));
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100126 ON_CALL(*sensorMocks.front(), metadata())
127 .WillByDefault(Return("metadata1"));
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100128
Krzysztof Grobelnyd2238192020-12-02 09:27:28 +0000129 const auto conf = sut->dumpConfiguration();
130
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000131 LabeledMetricParameters expected = {};
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000132 expected.at_label<ts::Id>() = params.id();
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000133 expected.at_label<ts::OperationType>() = params.operationType();
134 expected.at_label<ts::CollectionTimeScope>() = params.collectionTimeScope();
135 expected.at_label<ts::CollectionDuration>() = params.collectionDuration();
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000136 expected.at_label<ts::SensorPath>() = {
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100137 LabeledSensorParameters("service1", "path1", "metadata1")};
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000138
139 EXPECT_THAT(conf, Eq(expected));
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100140}
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000141
142class TestMetricCalculationFunctions :
143 public TestMetric,
144 public WithParamInterface<MetricParams>
145{
146 public:
147 void SetUp() override
148 {
Lukasz Kazmierczak7e098e92021-09-16 15:59:56 +0200149 clockFake.reset();
Krzysztof Grobelny80697712021-03-04 09:49:27 +0000150 sut = makeSut(params.operationType(GetParam().operationType())
151 .collectionTimeScope(GetParam().collectionTimeScope())
152 .collectionDuration(GetParam().collectionDuration()));
153 }
154
155 static std::vector<std::pair<Milliseconds, double>> defaultReadings()
156 {
157 std::vector<std::pair<Milliseconds, double>> ret;
158 ret.emplace_back(0ms, std::numeric_limits<double>::quiet_NaN());
159 ret.emplace_back(10ms, 14.);
160 ret.emplace_back(1ms, 3.);
161 ret.emplace_back(5ms, 7.);
162 return ret;
163 }
164};
165
166MetricParams defaultSingleParams()
167{
168 return MetricParams()
169 .operationType(OperationType::single)
170 .readings(TestMetricCalculationFunctions::defaultReadings())
171 .expectedReading(11ms, 7.0);
172}
173
174INSTANTIATE_TEST_SUITE_P(
175 OperationSingleReturnsLastReading, TestMetricCalculationFunctions,
176 Values(
177 defaultSingleParams().collectionTimeScope(CollectionTimeScope::point),
178 defaultSingleParams()
179 .collectionTimeScope(CollectionTimeScope::interval)
180 .collectionDuration(CollectionDuration(100ms)),
181 defaultSingleParams().collectionTimeScope(
182 CollectionTimeScope::startup)));
183
184MetricParams defaultPointParams()
185{
186 return defaultSingleParams().collectionTimeScope(
187 CollectionTimeScope::point);
188}
189
190INSTANTIATE_TEST_SUITE_P(
191 TimeScopePointReturnsLastReading, TestMetricCalculationFunctions,
192 Values(defaultPointParams().operationType(OperationType::single),
193 defaultPointParams().operationType(OperationType::min),
194 defaultPointParams().operationType(OperationType::max),
195 defaultPointParams().operationType(OperationType::sum),
196 defaultPointParams().operationType(OperationType::avg)));
197
198MetricParams defaultMinParams()
199{
200 return defaultSingleParams().operationType(OperationType::min);
201}
202
203INSTANTIATE_TEST_SUITE_P(
204 ReturnsMinForGivenTimeScope, TestMetricCalculationFunctions,
205 Values(defaultMinParams()
206 .collectionTimeScope(CollectionTimeScope::interval)
207 .collectionDuration(CollectionDuration(100ms))
208 .expectedReading(10ms, 3.0),
209 defaultMinParams()
210 .collectionTimeScope(CollectionTimeScope::interval)
211 .collectionDuration(CollectionDuration(3ms))
212 .expectedReading(13ms, 7.0),
213 defaultMinParams()
214 .collectionTimeScope(CollectionTimeScope::startup)
215 .expectedReading(10ms, 3.0)));
216
217MetricParams defaultMaxParams()
218{
219 return defaultSingleParams().operationType(OperationType::max);
220}
221
222INSTANTIATE_TEST_SUITE_P(
223 ReturnsMaxForGivenTimeScope, TestMetricCalculationFunctions,
224 Values(defaultMaxParams()
225 .collectionTimeScope(CollectionTimeScope::interval)
226 .collectionDuration(CollectionDuration(100ms))
227 .expectedReading(0ms, 14.0),
228 defaultMaxParams()
229 .collectionTimeScope(CollectionTimeScope::interval)
230 .collectionDuration(CollectionDuration(6ms))
231 .expectedReading(10ms, 14.0),
232 defaultMaxParams()
233 .collectionTimeScope(CollectionTimeScope::interval)
234 .collectionDuration(CollectionDuration(5ms))
235 .expectedReading(11ms, 7.0),
236 defaultMaxParams()
237 .collectionTimeScope(CollectionTimeScope::startup)
238 .expectedReading(0ms, 14.0)));
239
240MetricParams defaultSumParams()
241{
242 return defaultSingleParams().operationType(OperationType::sum);
243}
244
245INSTANTIATE_TEST_SUITE_P(
246 ReturnsSumForGivenTimeScope, TestMetricCalculationFunctions,
247 Values(defaultSumParams()
248 .collectionTimeScope(CollectionTimeScope::interval)
249 .collectionDuration(CollectionDuration(100ms))
250 .expectedReading(16ms, 14. * 10 + 3. * 1 + 7 * 5),
251 defaultSumParams()
252 .collectionTimeScope(CollectionTimeScope::interval)
253 .collectionDuration(CollectionDuration(8ms))
254 .expectedReading(16ms, 14. * 2 + 3. * 1 + 7 * 5),
255 defaultSumParams()
256 .collectionTimeScope(CollectionTimeScope::interval)
257 .collectionDuration(CollectionDuration(6ms))
258 .expectedReading(16ms, 3. * 1 + 7 * 5),
259 defaultSumParams()
260 .collectionTimeScope(CollectionTimeScope::startup)
261 .expectedReading(16ms, 14. * 10 + 3. * 1 + 7 * 5)));
262
263MetricParams defaultAvgParams()
264{
265 return defaultSingleParams().operationType(OperationType::avg);
266}
267
268INSTANTIATE_TEST_SUITE_P(
269 ReturnsAvgForGivenTimeScope, TestMetricCalculationFunctions,
270 Values(defaultAvgParams()
271 .collectionTimeScope(CollectionTimeScope::interval)
272 .collectionDuration(CollectionDuration(100ms))
273 .expectedReading(16ms, (14. * 10 + 3. * 1 + 7 * 5) / 16.),
274 defaultAvgParams()
275 .collectionTimeScope(CollectionTimeScope::interval)
276 .collectionDuration(CollectionDuration(8ms))
277 .expectedReading(16ms, (14. * 2 + 3. * 1 + 7 * 5) / 8.),
278 defaultAvgParams()
279 .collectionTimeScope(CollectionTimeScope::interval)
280 .collectionDuration(CollectionDuration(6ms))
281 .expectedReading(16ms, (3. * 1 + 7 * 5) / 6.),
282 defaultAvgParams()
283 .collectionTimeScope(CollectionTimeScope::startup)
284 .expectedReading(16ms, (14. * 10 + 3. * 1 + 7 * 5) / 16.)));
285
286TEST_P(TestMetricCalculationFunctions, calculatesReadingValue)
287{
288 for (auto [timestamp, reading] : GetParam().readings())
289 {
290 sut->sensorUpdated(*sensorMocks.front(), clockFake.timestamp(),
291 reading);
292 clockFake.advance(timestamp);
293 }
294
295 const auto [expectedTimestamp, expectedReading] =
296 GetParam().expectedReading();
297 const auto readings = sut->getReadings();
298
299 EXPECT_THAT(readings, ElementsAre(MetricValue{
300 "id", "metadata", expectedReading,
301 ClockFake::toTimestamp(expectedTimestamp)}));
302}
303
304TEST_P(TestMetricCalculationFunctions,
305 calculatedReadingValueWithIntermediateCalculations)
306{
307 for (auto [timestamp, reading] : GetParam().readings())
308 {
309 sut->sensorUpdated(*sensorMocks.front(), clockFake.timestamp(),
310 reading);
311 clockFake.advance(timestamp);
312 sut->getReadings();
313 }
314
315 const auto [expectedTimestamp, expectedReading] =
316 GetParam().expectedReading();
317 const auto readings = sut->getReadings();
318
319 EXPECT_THAT(readings, ElementsAre(MetricValue{
320 "id", "metadata", expectedReading,
321 ClockFake::toTimestamp(expectedTimestamp)}));
322}