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