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