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