xref: /openbmc/telemetry/tests/src/test_report.cpp (revision b8cc78dd)
1 #include "dbus_environment.hpp"
2 #include "helpers.hpp"
3 #include "mocks/json_storage_mock.hpp"
4 #include "mocks/metric_mock.hpp"
5 #include "mocks/report_manager_mock.hpp"
6 #include "params/report_params.hpp"
7 #include "report.hpp"
8 #include "report_manager.hpp"
9 #include "utils/clock.hpp"
10 #include "utils/contains.hpp"
11 #include "utils/conv_container.hpp"
12 #include "utils/transform.hpp"
13 #include "utils/tstring.hpp"
14 
15 #include <sdbusplus/exception.hpp>
16 
17 using namespace testing;
18 using namespace std::literals::string_literals;
19 using namespace std::chrono_literals;
20 namespace tstring = utils::tstring;
21 
22 class TestReport : public Test
23 {
24   public:
25     ReportParams defaultParams;
26 
27     std::unique_ptr<ReportManagerMock> reportManagerMock =
28         std::make_unique<NiceMock<ReportManagerMock>>();
29     testing::NiceMock<StorageMock> storageMock;
30     std::vector<std::shared_ptr<MetricMock>> metricMocks;
31     std::unique_ptr<Report> sut;
32 
33     MockFunction<void()> checkPoint;
34 
35     void initMetricMocks(
36         const std::vector<LabeledMetricParameters>& metricParameters)
37     {
38         for (auto i = metricMocks.size(); i < metricParameters.size(); ++i)
39         {
40             metricMocks.emplace_back(std::make_shared<NiceMock<MetricMock>>());
41         }
42         metricMocks.resize(metricParameters.size());
43 
44         std::vector<MetricValue> readings{{MetricValue{"a", "b", 17.1, 114},
45                                            MetricValue{"aa", "bb", 42.0, 74}}};
46         readings.resize(metricParameters.size());
47 
48         for (size_t i = 0; i < metricParameters.size(); ++i)
49         {
50             ON_CALL(*metricMocks[i], getReadings())
51                 .WillByDefault(Return(std::vector({readings[i]})));
52             ON_CALL(*metricMocks[i], dumpConfiguration())
53                 .WillByDefault(Return(metricParameters[i]));
54         }
55     }
56 
57     void SetUp() override
58     {
59         sut = makeReport(ReportParams());
60     }
61 
62     static interfaces::JsonStorage::FilePath to_file_path(std::string id)
63     {
64         return interfaces::JsonStorage::FilePath(
65             std::to_string(std::hash<std::string>{}(id)));
66     }
67 
68     std::unique_ptr<Report> makeReport(const ReportParams& params)
69     {
70         initMetricMocks(params.metricParameters());
71 
72         return std::make_unique<Report>(
73             DbusEnvironment::getIoc(), DbusEnvironment::getObjServer(),
74             params.reportId(), params.reportName(), params.reportingType(),
75             params.reportActions(), params.interval(), params.appendLimit(),
76             params.reportUpdates(), *reportManagerMock, storageMock,
77             utils::convContainer<std::shared_ptr<interfaces::Metric>>(
78                 metricMocks),
79             params.enabled());
80     }
81 
82     template <class T>
83     static T getProperty(const std::string& path, const std::string& property)
84     {
85         return DbusEnvironment::getProperty<T>(path, Report::reportIfaceName,
86                                                property);
87     }
88 
89     template <class T>
90     static boost::system::error_code setProperty(const std::string& path,
91                                                  const std::string& property,
92                                                  const T& newValue)
93     {
94         return DbusEnvironment::setProperty<T>(path, Report::reportIfaceName,
95                                                property, newValue);
96     }
97 
98     boost::system::error_code call(const std::string& path,
99                                    const std::string& interface,
100                                    const std::string& method)
101     {
102         std::promise<boost::system::error_code> methodPromise;
103         DbusEnvironment::getBus()->async_method_call(
104             [&methodPromise](boost::system::error_code ec) {
105                 methodPromise.set_value(ec);
106             },
107             DbusEnvironment::serviceName(), path, interface, method);
108         return DbusEnvironment::waitForFuture(methodPromise.get_future());
109     }
110 
111     boost::system::error_code update(const std::string& path)
112     {
113         return call(path, Report::reportIfaceName, "Update");
114     }
115 
116     boost::system::error_code deleteReport(const std::string& path)
117     {
118         return call(path, Report::deleteIfaceName, "Delete");
119     }
120 };
121 
122 TEST_F(TestReport, returnsId)
123 {
124     EXPECT_THAT(sut->getId(), Eq(defaultParams.reportId()));
125 }
126 
127 TEST_F(TestReport, verifyIfPropertiesHaveValidValue)
128 {
129     EXPECT_THAT(getProperty<bool>(sut->getPath(), "Enabled"),
130                 Eq(defaultParams.enabled()));
131     EXPECT_THAT(getProperty<uint64_t>(sut->getPath(), "Interval"),
132                 Eq(defaultParams.interval().count()));
133     EXPECT_THAT(getProperty<bool>(sut->getPath(), "Persistency"), Eq(true));
134     EXPECT_THAT(
135         getProperty<std::vector<std::string>>(sut->getPath(), "ReportActions"),
136         Eq(utils::transform(defaultParams.reportActions(), [](const auto v) {
137             return utils::enumToString(v);
138         })));
139     EXPECT_THAT(getProperty<bool>(sut->getPath(), "EmitsReadingsUpdate"),
140                 Eq(utils::contains(defaultParams.reportActions(),
141                                    ReportAction::emitsReadingsUpdate)));
142     EXPECT_THAT(getProperty<uint64_t>(sut->getPath(), "AppendLimit"),
143                 Eq(defaultParams.appendLimit()));
144     EXPECT_THAT(getProperty<std::string>(sut->getPath(), "ReportingType"),
145                 Eq(utils::enumToString(defaultParams.reportingType())));
146     EXPECT_THAT(getProperty<std::string>(sut->getPath(), "ReportUpdates"),
147                 Eq(utils::enumToString(defaultParams.reportUpdates())));
148     EXPECT_THAT(
149         getProperty<bool>(sut->getPath(), "LogToMetricReportsCollection"),
150         Eq(utils::contains(defaultParams.reportActions(),
151                            ReportAction::logToMetricReportsCollection)));
152     EXPECT_THAT(getProperty<ReadingParameters>(
153                     sut->getPath(), "ReadingParametersFutureVersion"),
154                 Eq(toReadingParameters(defaultParams.metricParameters())));
155     EXPECT_THAT(getProperty<std::string>(sut->getPath(), "Name"),
156                 Eq(defaultParams.reportName()));
157 }
158 
159 TEST_F(TestReport, readingsAreInitialyEmpty)
160 {
161     EXPECT_THAT(getProperty<Readings>(sut->getPath(), "Readings"),
162                 Eq(Readings{}));
163 }
164 
165 TEST_F(TestReport, setEnabledWithNewValue)
166 {
167     bool newValue = !defaultParams.enabled();
168     EXPECT_THAT(setProperty(sut->getPath(), "Enabled", newValue).value(),
169                 Eq(boost::system::errc::success));
170     EXPECT_THAT(getProperty<bool>(sut->getPath(), "Enabled"), Eq(newValue));
171 }
172 
173 TEST_F(TestReport, setIntervalWithValidValue)
174 {
175     uint64_t newValue = defaultParams.interval().count() + 1;
176     EXPECT_THAT(setProperty(sut->getPath(), "Interval", newValue).value(),
177                 Eq(boost::system::errc::success));
178     EXPECT_THAT(getProperty<uint64_t>(sut->getPath(), "Interval"),
179                 Eq(newValue));
180 }
181 
182 TEST_F(TestReport, settingIntervalWithInvalidValueDoesNotChangeProperty)
183 {
184     uint64_t newValue = defaultParams.interval().count() - 1;
185     EXPECT_THAT(setProperty(sut->getPath(), "Interval", newValue).value(),
186                 Eq(boost::system::errc::success));
187     EXPECT_THAT(getProperty<uint64_t>(sut->getPath(), "Interval"),
188                 Eq(defaultParams.interval().count()));
189 }
190 
191 TEST_F(TestReport, settingEmitsReadingsUpdateHaveNoEffect)
192 {
193     EXPECT_THAT(
194         setProperty(sut->getPath(), "EmitsReadingsUpdate", true).value(),
195         Eq(boost::system::errc::read_only_file_system));
196     EXPECT_THAT(getProperty<bool>(sut->getPath(), "EmitsReadingsUpdate"),
197                 Eq(utils::contains(defaultParams.reportActions(),
198                                    ReportAction::emitsReadingsUpdate)));
199 }
200 
201 TEST_F(TestReport, settingLogToMetricReportCollectionHaveNoEffect)
202 {
203     EXPECT_THAT(
204         setProperty(sut->getPath(), "LogToMetricReportsCollection", true)
205             .value(),
206         Eq(boost::system::errc::read_only_file_system));
207     EXPECT_THAT(
208         getProperty<bool>(sut->getPath(), "LogToMetricReportsCollection"),
209         Eq(utils::contains(defaultParams.reportActions(),
210                            ReportAction::logToMetricReportsCollection)));
211 }
212 
213 TEST_F(TestReport, settingPersistencyToFalseRemovesReportFromStorage)
214 {
215     EXPECT_CALL(storageMock, remove(to_file_path(sut->getId())));
216 
217     bool persistency = false;
218     EXPECT_THAT(setProperty(sut->getPath(), "Persistency", persistency).value(),
219                 Eq(boost::system::errc::success));
220     EXPECT_THAT(getProperty<bool>(sut->getPath(), "Persistency"),
221                 Eq(persistency));
222 }
223 
224 TEST_F(TestReport, deleteReport)
225 {
226     EXPECT_CALL(*reportManagerMock, removeReport(sut.get()));
227     auto ec = deleteReport(sut->getPath());
228     EXPECT_THAT(ec, Eq(boost::system::errc::success));
229 }
230 
231 TEST_F(TestReport, deletingNonExistingReportReturnInvalidRequestDescriptor)
232 {
233     auto ec = deleteReport(Report::reportDir + "NonExisting"s);
234     EXPECT_THAT(ec.value(), Eq(EBADR));
235 }
236 
237 TEST_F(TestReport, deleteReportExpectThatFileIsRemoveFromStorage)
238 {
239     EXPECT_CALL(storageMock, remove(to_file_path(sut->getId())));
240     auto ec = deleteReport(sut->getPath());
241     EXPECT_THAT(ec, Eq(boost::system::errc::success));
242 }
243 
244 class TestReportStore :
245     public TestReport,
246     public WithParamInterface<std::pair<std::string, nlohmann::json>>
247 {
248   public:
249     void SetUp() override
250     {}
251 
252     nlohmann::json storedConfiguration;
253 };
254 
255 INSTANTIATE_TEST_SUITE_P(
256     _, TestReportStore,
257     Values(std::make_pair("Enabled"s, nlohmann::json(ReportParams().enabled())),
258            std::make_pair("Version"s, nlohmann::json(6)),
259            std::make_pair("Id"s, nlohmann::json(ReportParams().reportId())),
260            std::make_pair("Name"s, nlohmann::json(ReportParams().reportName())),
261            std::make_pair("ReportingType",
262                           nlohmann::json(ReportParams().reportingType())),
263            std::make_pair("ReportActions", nlohmann::json(utils::transform(
264                                                ReportParams().reportActions(),
265                                                [](const auto v) {
266                                                    return utils::toUnderlying(
267                                                        v);
268                                                }))),
269            std::make_pair("Interval",
270                           nlohmann::json(ReportParams().interval().count())),
271            std::make_pair(
272                "ReadingParameters",
273                nlohmann::json(
274                    {{{tstring::SensorPath::str(),
275                       {{{tstring::Service::str(), "Service"},
276                         {tstring::Path::str(),
277                          "/xyz/openbmc_project/sensors/power/p1"},
278                         {tstring::Metadata::str(), "metadata1"}}}},
279                      {tstring::OperationType::str(), OperationType::single},
280                      {tstring::Id::str(), "MetricId1"},
281                      {tstring::CollectionTimeScope::str(),
282                       CollectionTimeScope::point},
283                      {tstring::CollectionDuration::str(), 0}},
284                     {{tstring::SensorPath::str(),
285                       {{{tstring::Service::str(), "Service"},
286                         {tstring::Path::str(),
287                          "/xyz/openbmc_project/sensors/power/p2"},
288                         {tstring::Metadata::str(), "metadata2"}}}},
289                      {tstring::OperationType::str(), OperationType::single},
290                      {tstring::Id::str(), "MetricId2"},
291                      {tstring::CollectionTimeScope::str(),
292                       CollectionTimeScope::point},
293                      {tstring::CollectionDuration::str(), 0}}}))));
294 
295 TEST_P(TestReportStore, settingPersistencyToTrueStoresReport)
296 {
297     sut = makeReport(ReportParams());
298 
299     {
300         InSequence seq;
301         EXPECT_CALL(storageMock, remove(to_file_path(sut->getId())));
302         EXPECT_CALL(checkPoint, Call());
303         EXPECT_CALL(storageMock, store(to_file_path(sut->getId()), _))
304             .WillOnce(SaveArg<1>(&storedConfiguration));
305     }
306 
307     setProperty(sut->getPath(), "Persistency", false);
308     checkPoint.Call();
309     setProperty(sut->getPath(), "Persistency", true);
310 
311     const auto& [key, value] = GetParam();
312 
313     ASSERT_THAT(storedConfiguration.at(key), Eq(value));
314 }
315 
316 TEST_P(TestReportStore, reportIsSavedToStorageAfterCreated)
317 {
318     EXPECT_CALL(storageMock, store(to_file_path(ReportParams().reportId()), _))
319         .WillOnce(SaveArg<1>(&storedConfiguration));
320 
321     sut = makeReport(ReportParams());
322 
323     const auto& [key, value] = GetParam();
324 
325     ASSERT_THAT(storedConfiguration.at(key), Eq(value));
326 }
327 
328 class TestReportValidNames :
329     public TestReport,
330     public WithParamInterface<ReportParams>
331 {
332   public:
333     void SetUp() override
334     {}
335 };
336 
337 INSTANTIATE_TEST_SUITE_P(
338     ValidNames, TestReportValidNames,
339     Values(ReportParams().reportName("Valid_1"),
340            ReportParams().reportName("Valid_1/Valid_2"),
341            ReportParams().reportName("Valid_1/Valid_2/Valid_3")));
342 
343 TEST_P(TestReportValidNames, reportCtorDoesNotThrowOnValidName)
344 {
345     EXPECT_NO_THROW(makeReport(GetParam()));
346 }
347 
348 class TestReportInvalidIds :
349     public TestReport,
350     public WithParamInterface<ReportParams>
351 {
352   public:
353     void SetUp() override
354     {}
355 };
356 
357 INSTANTIATE_TEST_SUITE_P(InvalidNames, TestReportInvalidIds,
358                          Values(ReportParams().reportId("/"),
359                                 ReportParams().reportId("/Invalid"),
360                                 ReportParams().reportId("Invalid/"),
361                                 ReportParams().reportId("Invalid/Invalid/"),
362                                 ReportParams().reportId("Invalid?")));
363 
364 TEST_P(TestReportInvalidIds, failsToCreateReportWithInvalidName)
365 {
366     EXPECT_CALL(storageMock, store).Times(0);
367 
368     EXPECT_THROW(makeReport(GetParam()), sdbusplus::exception::SdBusError);
369 }
370 
371 class TestReportAllReportTypes :
372     public TestReport,
373     public WithParamInterface<ReportParams>
374 {
375   public:
376     void SetUp() override
377     {
378         sut = makeReport(GetParam());
379     }
380 };
381 
382 INSTANTIATE_TEST_SUITE_P(
383     _, TestReportAllReportTypes,
384     Values(ReportParams().reportingType(ReportingType::onRequest),
385            ReportParams().reportingType(ReportingType::onChange),
386            ReportParams().reportingType(ReportingType::periodic)));
387 
388 TEST_P(TestReportAllReportTypes, returnPropertValueOfReportType)
389 {
390     EXPECT_THAT(utils::toReportingType(
391                     getProperty<std::string>(sut->getPath(), "ReportingType")),
392                 Eq(GetParam().reportingType()));
393 }
394 
395 TEST_P(TestReportAllReportTypes, updateReadingsCallEnabledPropertyOff)
396 {
397     const uint64_t expectedTime = Clock().timestamp();
398 
399     setProperty(sut->getPath(), "Enabled", false);
400     sut->updateReadings();
401     const auto [timestamp, readings] =
402         getProperty<Readings>(sut->getPath(), "Readings");
403 
404     EXPECT_THAT(getProperty<bool>(sut->getPath(), "Enabled"), Eq(false));
405     EXPECT_THAT(timestamp, Lt(expectedTime));
406 }
407 
408 TEST_P(TestReportAllReportTypes, updateReadingsCallEnabledPropertyOn)
409 {
410     const uint64_t expectedTime = Clock().timestamp();
411 
412     sut->updateReadings();
413     const auto [timestamp, readings] =
414         getProperty<Readings>(sut->getPath(), "Readings");
415 
416     EXPECT_THAT(getProperty<bool>(sut->getPath(), "Enabled"), Eq(true));
417     EXPECT_THAT(timestamp, Ge(expectedTime));
418 }
419 
420 class TestReportOnRequestType : public TestReport
421 {
422     void SetUp() override
423     {
424         sut =
425             makeReport(ReportParams().reportingType(ReportingType::onRequest));
426     }
427 };
428 
429 TEST_F(TestReportOnRequestType, updatesReadingTimestamp)
430 {
431     const uint64_t expectedTime = Clock().timestamp();
432 
433     ASSERT_THAT(update(sut->getPath()), Eq(boost::system::errc::success));
434 
435     const auto [timestamp, readings] =
436         getProperty<Readings>(sut->getPath(), "Readings");
437 
438     EXPECT_THAT(timestamp, Ge(expectedTime));
439 }
440 
441 TEST_F(TestReportOnRequestType, updatesReadingWhenUpdateIsCalled)
442 {
443     ASSERT_THAT(update(sut->getPath()), Eq(boost::system::errc::success));
444 
445     const auto [timestamp, readings] =
446         getProperty<Readings>(sut->getPath(), "Readings");
447 
448     EXPECT_THAT(readings,
449                 ElementsAre(std::make_tuple("a"s, "b"s, 17.1, 114u),
450                             std::make_tuple("aa"s, "bb"s, 42.0, 74u)));
451 }
452 
453 class TestReportNonOnRequestType :
454     public TestReport,
455     public WithParamInterface<ReportParams>
456 {
457     void SetUp() override
458     {
459         sut = makeReport(GetParam());
460     }
461 };
462 
463 INSTANTIATE_TEST_SUITE_P(
464     _, TestReportNonOnRequestType,
465     Values(ReportParams().reportingType(ReportingType::periodic),
466            ReportParams().reportingType(ReportingType::onChange)));
467 
468 TEST_P(TestReportNonOnRequestType, readingsAreNotUpdateOnUpdateCall)
469 {
470     ASSERT_THAT(update(sut->getPath()), Eq(boost::system::errc::success));
471 
472     EXPECT_THAT(getProperty<Readings>(sut->getPath(), "Readings"),
473                 Eq(Readings{}));
474 }
475 
476 class TestReportNonPeriodicReport :
477     public TestReport,
478     public WithParamInterface<ReportParams>
479 {
480   public:
481     void SetUp() override
482     {
483         sut = makeReport(GetParam());
484     }
485 };
486 
487 INSTANTIATE_TEST_SUITE_P(
488     _, TestReportNonPeriodicReport,
489     Values(ReportParams().reportingType(ReportingType::onRequest),
490            ReportParams().reportingType(ReportingType::onChange)));
491 
492 TEST_P(TestReportNonPeriodicReport, readingsAreNotUpdatedAfterIntervalExpires)
493 {
494     DbusEnvironment::sleepFor(ReportManager::minInterval + 1ms);
495 
496     EXPECT_THAT(getProperty<Readings>(sut->getPath(), "Readings"),
497                 Eq(Readings{}));
498 }
499 
500 class TestReportPeriodicReport : public TestReport
501 {
502     void SetUp() override
503     {
504         sut = makeReport(ReportParams().reportingType(ReportingType::periodic));
505     }
506 };
507 
508 TEST_F(TestReportPeriodicReport, readingTimestampIsUpdatedAfterIntervalExpires)
509 {
510     const uint64_t expectedTime = Clock().timestamp();
511     DbusEnvironment::sleepFor(ReportManager::minInterval + 1ms);
512 
513     const auto [timestamp, readings] =
514         getProperty<Readings>(sut->getPath(), "Readings");
515 
516     EXPECT_THAT(timestamp, Ge(expectedTime));
517 }
518 
519 TEST_F(TestReportPeriodicReport, readingsAreUpdatedAfterIntervalExpires)
520 {
521     DbusEnvironment::sleepFor(ReportManager::minInterval + 1ms);
522 
523     const auto [timestamp, readings] =
524         getProperty<Readings>(sut->getPath(), "Readings");
525 
526     EXPECT_THAT(readings,
527                 ElementsAre(std::make_tuple("a"s, "b"s, 17.1, 114u),
528                             std::make_tuple("aa"s, "bb"s, 42.0, 74u)));
529 }
530 
531 struct ReportUpdatesReportParams
532 {
533     ReportParams reportParams;
534     std::vector<ReadingData> expectedReadings;
535     bool expectedEnabled;
536 };
537 
538 class TestReportWithReportUpdatesAndLimit :
539     public TestReport,
540     public WithParamInterface<ReportUpdatesReportParams>
541 {
542     void SetUp() override
543     {
544         sut = makeReport(ReportParams(GetParam().reportParams)
545                              .reportingType(ReportingType::periodic)
546                              .interval(std::chrono::hours(1000)));
547     }
548 };
549 
550 INSTANTIATE_TEST_SUITE_P(
551     _, TestReportWithReportUpdatesAndLimit,
552     Values(
553         ReportUpdatesReportParams{
554             ReportParams()
555                 .reportUpdates(ReportUpdates::appendWrapsWhenFull)
556                 .appendLimit(5),
557             std::vector<ReadingData>{{std::make_tuple("aa"s, "bb"s, 42.0, 74u),
558                                       std::make_tuple("a"s, "b"s, 17.1, 114u),
559                                       std::make_tuple("aa"s, "bb"s, 42.0, 74u),
560                                       std::make_tuple("aa"s, "bb"s, 42.0, 74u),
561                                       std::make_tuple("a"s, "b"s, 17.1, 114u)}},
562             true},
563         ReportUpdatesReportParams{
564             ReportParams()
565                 .reportUpdates(ReportUpdates::appendWrapsWhenFull)
566                 .appendLimit(4),
567             std::vector<ReadingData>{
568                 {std::make_tuple("a"s, "b"s, 17.1, 114u),
569                  std::make_tuple("aa"s, "bb"s, 42.0, 74u),
570                  std::make_tuple("a"s, "b"s, 17.1, 114u),
571                  std::make_tuple("aa"s, "bb"s, 42.0, 74u)}},
572             true},
573         ReportUpdatesReportParams{
574             ReportParams()
575                 .reportUpdates(ReportUpdates::appendWrapsWhenFull)
576                 .appendLimit(0),
577             std::vector<ReadingData>{}, true},
578         ReportUpdatesReportParams{
579             ReportParams()
580                 .reportUpdates(ReportUpdates::appendStopsWhenFull)
581                 .appendLimit(10),
582             std::vector<ReadingData>{
583                 {std::make_tuple("a"s, "b"s, 17.1, 114u),
584                  std::make_tuple("aa"s, "bb"s, 42.0, 74u),
585                  std::make_tuple("a"s, "b"s, 17.1, 114u),
586                  std::make_tuple("aa"s, "bb"s, 42.0, 74u),
587                  std::make_tuple("a"s, "b"s, 17.1, 114u),
588                  std::make_tuple("aa"s, "bb"s, 42.0, 74u),
589                  std::make_tuple("a"s, "b"s, 17.1, 114u),
590                  std::make_tuple("aa"s, "bb"s, 42.0, 74u)}},
591             true},
592         ReportUpdatesReportParams{
593             ReportParams()
594                 .reportUpdates(ReportUpdates::appendStopsWhenFull)
595                 .appendLimit(5),
596             std::vector<ReadingData>{{std::make_tuple("a"s, "b"s, 17.1, 114u),
597                                       std::make_tuple("aa"s, "bb"s, 42.0, 74u),
598                                       std::make_tuple("a"s, "b"s, 17.1, 114u),
599                                       std::make_tuple("aa"s, "bb"s, 42.0, 74u),
600                                       std::make_tuple("a"s, "b"s, 17.1, 114u)}},
601             false},
602         ReportUpdatesReportParams{
603             ReportParams()
604                 .reportUpdates(ReportUpdates::appendStopsWhenFull)
605                 .appendLimit(4),
606             std::vector<ReadingData>{
607                 {std::make_tuple("a"s, "b"s, 17.1, 114u),
608                  std::make_tuple("aa"s, "bb"s, 42.0, 74u),
609                  std::make_tuple("a"s, "b"s, 17.1, 114u),
610                  std::make_tuple("aa"s, "bb"s, 42.0, 74u)}},
611             false},
612         ReportUpdatesReportParams{
613             ReportParams()
614                 .reportUpdates(ReportUpdates::appendStopsWhenFull)
615                 .appendLimit(0),
616             std::vector<ReadingData>{}, false},
617         ReportUpdatesReportParams{
618             ReportParams()
619                 .reportUpdates(ReportUpdates::overwrite)
620                 .appendLimit(500),
621             std::vector<ReadingData>{
622                 {std::make_tuple("a"s, "b"s, 17.1, 114u),
623                  std::make_tuple("aa"s, "bb"s, 42.0, 74u)}},
624             true},
625         ReportUpdatesReportParams{
626             ReportParams()
627                 .reportUpdates(ReportUpdates::overwrite)
628                 .appendLimit(1),
629             std::vector<ReadingData>{
630                 {std::make_tuple("a"s, "b"s, 17.1, 114u),
631                  std::make_tuple("aa"s, "bb"s, 42.0, 74u)}},
632             true},
633         ReportUpdatesReportParams{
634             ReportParams()
635                 .reportUpdates(ReportUpdates::overwrite)
636                 .appendLimit(0),
637             std::vector<ReadingData>{
638                 {std::make_tuple("a"s, "b"s, 17.1, 114u),
639                  std::make_tuple("aa"s, "bb"s, 42.0, 74u)}},
640             true}));
641 
642 TEST_P(TestReportWithReportUpdatesAndLimit,
643        readingsAreUpdatedAfterIntervalExpires)
644 {
645     for (int i = 0; i < 4; i++)
646     {
647         sut->updateReadings();
648     }
649 
650     const auto [timestamp, readings] =
651         getProperty<Readings>(sut->getPath(), "Readings");
652     const auto enabled = getProperty<bool>(sut->getPath(), "Enabled");
653 
654     EXPECT_THAT(readings, ElementsAreArray(GetParam().expectedReadings));
655     EXPECT_EQ(enabled, GetParam().expectedEnabled);
656 }
657 
658 class TestReportInitialization : public TestReport
659 {
660   public:
661     void SetUp() override
662     {}
663 
664     void monitorProc(sdbusplus::message::message& msg)
665     {
666         std::string iface;
667         std::vector<std::pair<std::string, std::variant<Readings>>>
668             changed_properties;
669         std::vector<std::string> invalidated_properties;
670 
671         msg.read(iface, changed_properties, invalidated_properties);
672 
673         if (iface == Report::reportIfaceName)
674         {
675             for (const auto& [name, value] : changed_properties)
676             {
677                 if (name == "Readings")
678                 {
679                     readingsUpdated.Call();
680                 }
681             }
682         }
683     }
684 
685     void makeMonitor()
686     {
687         monitor = std::make_unique<sdbusplus::bus::match_t>(
688             *DbusEnvironment::getBus(),
689             sdbusplus::bus::match::rules::propertiesChanged(
690                 sut->getPath(), Report::reportIfaceName),
691             [this](auto& msg) { monitorProc(msg); });
692     }
693 
694     std::unique_ptr<sdbusplus::bus::match_t> monitor;
695     MockFunction<void()> readingsUpdated;
696 };
697 
698 TEST_F(TestReportInitialization,
699        metricsAreInitializedWhenEnabledReportConstructed)
700 {
701     initMetricMocks(defaultParams.metricParameters());
702     for (auto& metric : metricMocks)
703     {
704         EXPECT_CALL(*metric, initialize()).Times(1);
705     }
706     sut = makeReport(defaultParams.enabled(true));
707 }
708 
709 TEST_F(TestReportInitialization,
710        metricsAreNotInitializedWhenDisabledReportConstructed)
711 {
712     initMetricMocks(defaultParams.metricParameters());
713     for (auto& metric : metricMocks)
714     {
715         EXPECT_CALL(*metric, initialize()).Times(0);
716     }
717     sut = makeReport(defaultParams.enabled(false));
718 }
719 
720 TEST_F(TestReportInitialization,
721        emitReadingsUpdateIsTrueReadingsPropertiesChangedSingalEmits)
722 {
723     EXPECT_CALL(readingsUpdated, Call())
724         .WillOnce(
725             InvokeWithoutArgs(DbusEnvironment::setPromise("readingsUpdated")));
726 
727     const auto elapsed = DbusEnvironment::measureTime([this] {
728         sut =
729             makeReport(defaultParams.reportingType(ReportingType::periodic)
730                            .reportActions({ReportAction::emitsReadingsUpdate}));
731         makeMonitor();
732         EXPECT_TRUE(DbusEnvironment::waitForFuture("readingsUpdated"));
733     });
734 
735     EXPECT_THAT(elapsed, AllOf(Ge(defaultParams.interval()),
736                                Lt(defaultParams.interval() * 2)));
737 }
738 
739 TEST_F(TestReportInitialization,
740        emitReadingsUpdateIsFalseReadingsPropertiesChangesSigalDoesNotEmits)
741 {
742     EXPECT_CALL(readingsUpdated, Call()).Times(0);
743 
744     sut = makeReport(
745         defaultParams.reportingType(ReportingType::periodic).reportActions({}));
746     makeMonitor();
747     DbusEnvironment::sleepFor(defaultParams.interval() * 2);
748 }
749 
750 TEST_F(TestReportInitialization, appendLimitDeducedProperly)
751 {
752     sut = makeReport(
753         ReportParams().appendLimit(std::numeric_limits<uint64_t>::max()));
754     auto appendLimit = getProperty<uint64_t>(sut->getPath(), "AppendLimit");
755     EXPECT_EQ(appendLimit, 2ull);
756 }
757