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