xref: /openbmc/telemetry/tests/src/test_report.cpp (revision 892f7c81)
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_factory_mock.hpp"
10 #include "mocks/report_manager_mock.hpp"
11 #include "params/report_params.hpp"
12 #include "report.hpp"
13 #include "report_manager.hpp"
14 #include "utils/clock.hpp"
15 #include "utils/contains.hpp"
16 #include "utils/conv_container.hpp"
17 #include "utils/dbus_path_utils.hpp"
18 #include "utils/messanger.hpp"
19 #include "utils/string_utils.hpp"
20 #include "utils/transform.hpp"
21 #include "utils/tstring.hpp"
22 
23 #include <sdbusplus/exception.hpp>
24 
25 #include <ranges>
26 
27 using namespace testing;
28 using namespace std::literals::string_literals;
29 using namespace std::chrono_literals;
30 using sdbusplus::message::object_path;
31 namespace tstring = utils::tstring;
32 
33 using ErrorMessageDbusType = std::tuple<std::string, std::string>;
34 using ErrorMessagesDbusType = std::vector<ErrorMessageDbusType>;
35 
36 constexpr Milliseconds systemTimestamp = 55ms;
37 
38 namespace
39 {
40 
41 ReportParams defaultParams()
42 {
43     return ReportParams();
44 }
45 
46 ReportParams defaultOnChangeParams()
47 {
48     return defaultParams().reportingType(ReportingType::onChange);
49 }
50 
51 } // namespace
52 
53 class TestReport : public Test
54 {
55   public:
56     std::unique_ptr<ReportManagerMock> reportManagerMock =
57         std::make_unique<NiceMock<ReportManagerMock>>();
58     std::unique_ptr<ReportFactoryMock> reportFactoryMock =
59         std::make_unique<NiceMock<ReportFactoryMock>>();
60     nlohmann::json storedConfiguration;
61     NiceMock<StorageMock> storageMock;
62     std::vector<std::shared_ptr<MetricMock>> metricMocks;
63     std::unique_ptr<ClockFake> clockFakePtr = std::make_unique<ClockFake>();
64     ClockFake& clockFake = *clockFakePtr;
65     std::unique_ptr<Report> sut;
66     utils::Messanger messanger;
67 
68     MockFunction<void()> checkPoint;
69 
70     TestReport() : messanger(DbusEnvironment::getIoc())
71     {
72         clockFake.system.set(systemTimestamp);
73         ON_CALL(storageMock, store(to_file_path(ReportParams().reportId()), _))
74             .WillByDefault(SaveArg<1>(&storedConfiguration));
75     }
76 
77     void initMetricMocks(
78         const std::vector<LabeledMetricParameters>& metricParameters)
79     {
80         for (auto i = metricMocks.size(); i < metricParameters.size(); ++i)
81         {
82             metricMocks.emplace_back(std::make_shared<NiceMock<MetricMock>>());
83         }
84         metricMocks.resize(metricParameters.size());
85 
86         std::vector<MetricValue> readings{{MetricValue{"a", "b", 17.1, 114},
87                                            MetricValue{"aa", "bb", 42.0, 74}}};
88 
89         ASSERT_THAT(readings.size(), Ge(metricParameters.size()));
90 
91         for (size_t i = 0; i < metricParameters.size(); ++i)
92         {
93             ON_CALL(*metricMocks[i], getUpdatedReadings())
94                 .WillByDefault(ReturnRefOfCopy(std::vector({readings[i]})));
95             ON_CALL(*metricMocks[i], dumpConfiguration())
96                 .WillByDefault(Return(metricParameters[i]));
97         }
98     }
99 
100     std::vector<std::shared_ptr<interfaces::Metric>>
101         getMetricsFromReadingParams(const ReadingParameters& params)
102     {
103         const auto metricParameters =
104             reportFactoryMock->convertMetricParams(params);
105         std::vector<std::shared_ptr<MetricMock>> metricMocks;
106 
107         for (size_t i = 0; i < metricParameters.size(); ++i)
108         {
109             metricMocks.emplace_back(std::make_shared<NiceMock<MetricMock>>());
110             ON_CALL(*metricMocks[i], dumpConfiguration())
111                 .WillByDefault(Return(metricParameters[i]));
112             ON_CALL(*metricMocks[i], sensorCount())
113                 .WillByDefault(Return(metricParameters[i]
114                                           .at_label<tstring::SensorPath>()
115                                           .size()));
116         }
117 
118         return utils::convContainer<std::shared_ptr<interfaces::Metric>>(
119             metricMocks);
120     }
121 
122     void SetUp() override
123     {
124         sut = makeReport(defaultParams());
125     }
126 
127     static interfaces::JsonStorage::FilePath to_file_path(std::string id)
128     {
129         return interfaces::JsonStorage::FilePath(
130             std::to_string(std::hash<std::string>{}(id)));
131     }
132 
133     std::unique_ptr<Report> makeReport(const ReportParams& params)
134     {
135         initMetricMocks(params.metricParameters());
136 
137         return std::make_unique<Report>(
138             DbusEnvironment::getIoc(), DbusEnvironment::getObjServer(),
139             params.reportId(), params.reportName(), params.reportingType(),
140             params.reportActions(), params.interval(), params.appendLimit(),
141             params.reportUpdates(), *reportManagerMock, storageMock,
142             utils::convContainer<std::shared_ptr<interfaces::Metric>>(
143                 metricMocks),
144             *reportFactoryMock, params.enabled(), std::move(clockFakePtr),
145             params.readings());
146     }
147 
148     template <class T>
149     static T getProperty(const std::string& path, const std::string& property)
150     {
151         return DbusEnvironment::getProperty<T>(path, Report::reportIfaceName,
152                                                property);
153     }
154 
155     template <class T>
156     static boost::system::error_code setProperty(const std::string& path,
157                                                  const std::string& property,
158                                                  const T& newValue)
159     {
160         return DbusEnvironment::setProperty<T>(path, Report::reportIfaceName,
161                                                property, newValue);
162     }
163 
164     template <class T>
165     struct ChangePropertyParams
166     {
167         Matcher<T> valueBefore = _;
168         T newValue;
169         Matcher<boost::system::error_code> ec =
170             Eq(boost::system::errc::success);
171         Matcher<T> valueAfter = Eq(newValue);
172     };
173 
174     template <class T>
175     static void changeProperty(const std::string& path,
176                                const std::string& property,
177                                ChangePropertyParams<T> p)
178     {
179         ASSERT_THAT(getProperty<T>(path, property), p.valueBefore);
180         ASSERT_THAT(setProperty<T>(path, property, p.newValue), p.ec);
181         EXPECT_THAT(getProperty<T>(path, property), p.valueAfter);
182     }
183 
184     boost::system::error_code call(const std::string& path,
185                                    const std::string& interface,
186                                    const std::string& method)
187     {
188         std::promise<boost::system::error_code> methodPromise;
189         DbusEnvironment::getBus()->async_method_call(
190             [&methodPromise](boost::system::error_code ec) {
191                 methodPromise.set_value(ec);
192             },
193             DbusEnvironment::serviceName(), path, interface, method);
194         return DbusEnvironment::waitForFuture(methodPromise.get_future());
195     }
196 
197     boost::system::error_code update(const std::string& path)
198     {
199         return call(path, Report::reportIfaceName, "Update");
200     }
201 
202     boost::system::error_code deleteReport(const std::string& path)
203     {
204         return call(path, Report::deleteIfaceName, "Delete");
205     }
206 
207     static std::pair<std::string, std::vector<std::string>>
208         makeStateDetail(const std::string& detailType,
209                         std::vector<std::string> detailArgs)
210     {
211         return make_pair(detailType, detailArgs);
212     }
213 };
214 
215 TEST_F(TestReport, returnsId)
216 {
217     EXPECT_THAT(sut->getId(), Eq(defaultParams().reportId()));
218 }
219 
220 TEST_F(TestReport, verifyIfPropertiesHaveValidValue)
221 {
222     EXPECT_THAT(getProperty<bool>(sut->getPath(), "Enabled"),
223                 Eq(defaultParams().enabled()));
224     EXPECT_THAT(getProperty<uint64_t>(sut->getPath(), "Interval"),
225                 Eq(defaultParams().interval().count()));
226     EXPECT_THAT(getProperty<bool>(sut->getPath(), "Persistency"), Eq(true));
227     EXPECT_THAT(
228         getProperty<std::vector<std::string>>(sut->getPath(), "ReportActions"),
229         Eq(utils::transform(defaultParams().reportActions(), [](const auto v) {
230             return utils::enumToString(v);
231         })));
232     EXPECT_THAT(getProperty<bool>(sut->getPath(), "EmitsReadingsUpdate"),
233                 Eq(utils::contains(defaultParams().reportActions(),
234                                    ReportAction::emitsReadingsUpdate)));
235     EXPECT_THAT(getProperty<uint64_t>(sut->getPath(), "AppendLimit"),
236                 Eq(defaultParams().appendLimit()));
237     EXPECT_THAT(getProperty<std::string>(sut->getPath(), "ReportingType"),
238                 Eq(utils::enumToString(defaultParams().reportingType())));
239     EXPECT_THAT(getProperty<std::string>(sut->getPath(), "ReportUpdates"),
240                 Eq(utils::enumToString(defaultParams().reportUpdates())));
241     EXPECT_THAT(
242         getProperty<bool>(sut->getPath(), "LogToMetricReportsCollection"),
243         Eq(utils::contains(defaultParams().reportActions(),
244                            ReportAction::logToMetricReportsCollection)));
245     EXPECT_THAT(getProperty<ReadingParameters>(
246                     sut->getPath(), "ReadingParametersFutureVersion"),
247                 Eq(toReadingParameters(defaultParams().metricParameters())));
248     EXPECT_THAT(getProperty<std::string>(sut->getPath(), "Name"),
249                 Eq(defaultParams().reportName()));
250     EXPECT_THAT(
251         getProperty<std::vector<object_path>>(sut->getPath(), "Triggers"),
252         IsEmpty());
253     EXPECT_THAT(
254         getProperty<ErrorMessagesDbusType>(sut->getPath(), "ErrorMessages"),
255         IsEmpty());
256 }
257 
258 TEST_F(TestReport, readingsAreInitialyEmpty)
259 {
260     EXPECT_THAT(getProperty<Readings>(sut->getPath(), "Readings"),
261                 Eq(Readings{}));
262 }
263 
264 TEST_F(TestReport, setReadingParametersWithNewParams)
265 {
266     ReadingParameters newParams = toReadingParameters(
267         std::vector<LabeledMetricParameters>{{LabeledMetricParameters{
268             {LabeledSensorInfo{"Service",
269                                "/xyz/openbmc_project/sensors/power/psu",
270                                "NewMetadata123"}},
271             OperationType::avg,
272             "NewMetricId123",
273             CollectionTimeScope::startup,
274             CollectionDuration(250ms)}}});
275     auto metrics = getMetricsFromReadingParams(newParams);
276 
277     EXPECT_CALL(*reportFactoryMock, updateMetrics(_, _, _))
278         .WillOnce(SetArgReferee<0>(metrics));
279     EXPECT_THAT(
280         setProperty(sut->getPath(), "ReadingParametersFutureVersion", newParams)
281             .value(),
282         Eq(boost::system::errc::success));
283     EXPECT_THAT(getProperty<ReadingParameters>(
284                     sut->getPath(), "ReadingParametersFutureVersion"),
285                 Eq(newParams));
286 }
287 
288 TEST_F(TestReport, setReadingParametersWithNewParamsUpdatesSensorCount)
289 {
290     auto report =
291         makeReport(ReportParams()
292                        .appendLimit(std::numeric_limits<uint64_t>::max())
293                        .reportId("DefaultAppendLimit"));
294 
295     ReadingParameters newParams = toReadingParameters(
296         std::vector<LabeledMetricParameters>{{LabeledMetricParameters{
297             {LabeledSensorInfo{"Service",
298                                "/xyz/openbmc_project/sensors/power/psu",
299                                "NewMetadata123"}},
300             OperationType::avg,
301             "NewMetricId123",
302             CollectionTimeScope::startup,
303             CollectionDuration(250ms)}}});
304     auto metrics = getMetricsFromReadingParams(newParams);
305 
306     EXPECT_CALL(*reportFactoryMock, updateMetrics(_, _, _))
307         .WillOnce(SetArgReferee<0>(metrics));
308     EXPECT_THAT(setProperty(report->getPath(), "ReadingParametersFutureVersion",
309                             newParams)
310                     .value(),
311                 Eq(boost::system::errc::success));
312     EXPECT_THAT(getProperty<uint64_t>(report->getPath(), "AppendLimit"),
313                 Eq(1ull));
314 }
315 
316 TEST_F(TestReport, setReadingParametersWithTooLongMetricId)
317 {
318     const ReadingParameters currentValue =
319         toReadingParameters(defaultParams().metricParameters());
320 
321     ReadingParameters newParams = toReadingParameters(
322         std::vector<LabeledMetricParameters>{{LabeledMetricParameters{
323             {LabeledSensorInfo{"Service",
324                                "/xyz/openbmc_project/sensors/power/psu",
325                                "NewMetadata123"}},
326             OperationType::avg,
327             utils::string_utils::getTooLongId(),
328             CollectionTimeScope::startup,
329             CollectionDuration(250ms)}}});
330 
331     changeProperty<ReadingParameters>(
332         sut->getPath(), "ReadingParametersFutureVersion",
333         {.valueBefore = Eq(currentValue),
334          .newValue = newParams,
335          .ec = Eq(boost::system::errc::invalid_argument),
336          .valueAfter = Eq(currentValue)});
337 }
338 
339 TEST_F(TestReport, setReportingTypeWithValidNewType)
340 {
341     changeProperty<std::string>(
342         sut->getPath(), "ReportingType",
343         {.valueBefore = Not(Eq(utils::enumToString(ReportingType::onRequest))),
344          .newValue = utils::enumToString(ReportingType::onRequest)});
345 }
346 
347 TEST_F(TestReport, setReportingTypeWithInvalidType)
348 {
349     const std::string currentValue =
350         utils::enumToString(defaultParams().reportingType());
351 
352     changeProperty<std::string>(
353         sut->getPath(), "ReportingType",
354         {.valueBefore = Eq(currentValue),
355          .newValue = "Periodic_ABC",
356          .ec = Eq(boost::system::errc::invalid_argument),
357          .valueAfter = Eq(currentValue)});
358 }
359 
360 TEST_F(TestReport, setReportActionsWithValidNewActions)
361 {
362     std::vector<std::string> newActions = {"EmitsReadingsUpdate"};
363     std::vector<std::string> currActions =
364         utils::transform(defaultParams().reportActions(),
365                          [](const auto v) { return utils::enumToString(v); });
366 
367     EXPECT_THAT(newActions, Ne(currActions));
368     EXPECT_THAT(
369         setProperty(sut->getPath(), "ReportActions", newActions).value(),
370         Eq(boost::system::errc::success));
371     EXPECT_THAT(
372         getProperty<std::vector<std::string>>(sut->getPath(), "ReportActions"),
373         UnorderedElementsAre("EmitsReadingsUpdate",
374                              "LogToMetricReportsCollection"));
375 }
376 
377 TEST_F(TestReport, setReportActionsWithValidUnsortedActions)
378 {
379     std::vector<std::string> newActions = {"LogToMetricReportsCollection",
380                                            "EmitsReadingsUpdate"};
381     std::vector<std::string> expectedActions = {"EmitsReadingsUpdate",
382                                                 "LogToMetricReportsCollection"};
383     std::vector<std::string> currActions =
384         utils::transform(defaultParams().reportActions(),
385                          [](const auto v) { return utils::enumToString(v); });
386 
387     EXPECT_THAT(newActions, Ne(currActions));
388     EXPECT_THAT(
389         setProperty(sut->getPath(), "ReportActions", newActions).value(),
390         Eq(boost::system::errc::success));
391     EXPECT_THAT(
392         getProperty<std::vector<std::string>>(sut->getPath(), "ReportActions"),
393         Eq(expectedActions));
394 }
395 
396 TEST_F(TestReport, setReportActionsWithEmptyActions)
397 {
398     std::vector<std::string> newActions = {};
399     std::vector<std::string> expectedActions = {"LogToMetricReportsCollection"};
400     std::vector<std::string> currActions =
401         utils::transform(defaultParams().reportActions(),
402                          [](const auto v) { return utils::enumToString(v); });
403 
404     EXPECT_THAT(newActions, Ne(currActions));
405     EXPECT_THAT(
406         setProperty(sut->getPath(), "ReportActions", newActions).value(),
407         Eq(boost::system::errc::success));
408     EXPECT_THAT(
409         getProperty<std::vector<std::string>>(sut->getPath(), "ReportActions"),
410         Eq(expectedActions));
411 }
412 
413 TEST_F(TestReport, setReportActionsWithInvalidActions)
414 {
415     std::vector<std::string> invalidActions = {"EmitsReadingsUpdate_1"};
416     EXPECT_THAT(
417         setProperty(sut->getPath(), "ReportActions", invalidActions).value(),
418         Eq(boost::system::errc::invalid_argument));
419     EXPECT_THAT(
420         getProperty<std::vector<std::string>>(sut->getPath(), "ReportActions"),
421         Eq(utils::transform(defaultParams().reportActions(), [](const auto v) {
422             return utils::enumToString(v);
423         })));
424 }
425 
426 TEST_F(TestReport, createReportWithEmptyActions)
427 {
428     std::vector<std::string> expectedActions = {"LogToMetricReportsCollection"};
429 
430     sut = makeReport(ReportParams().reportId("TestId_1").reportActions({}));
431     EXPECT_THAT(
432         getProperty<std::vector<std::string>>(sut->getPath(), "ReportActions"),
433         Eq(expectedActions));
434 }
435 
436 TEST_F(TestReport, createReportWithValidUnsortedActions)
437 {
438     std::vector<std::string> newActions = {"LogToMetricReportsCollection",
439                                            "EmitsReadingsUpdate"};
440     std::vector<std::string> expectedActions = {"EmitsReadingsUpdate",
441                                                 "LogToMetricReportsCollection"};
442 
443     sut = makeReport(
444         ReportParams()
445             .reportId("TestId_1")
446             .reportActions(utils::transform(newActions, [](const auto& action) {
447                 return utils::toReportAction(action);
448             })));
449     EXPECT_THAT(
450         getProperty<std::vector<std::string>>(sut->getPath(), "ReportActions"),
451         Eq(expectedActions));
452 }
453 
454 TEST_F(TestReport, setEnabledWithNewValue)
455 {
456     bool newValue = !defaultParams().enabled();
457     EXPECT_THAT(setProperty(sut->getPath(), "Enabled", newValue).value(),
458                 Eq(boost::system::errc::success));
459     EXPECT_THAT(getProperty<bool>(sut->getPath(), "Enabled"), Eq(newValue));
460 }
461 
462 TEST_F(TestReport, setIntervalWithValidValue)
463 {
464     uint64_t newValue = ReportManager::minInterval.count() * 42;
465     EXPECT_THAT(setProperty(sut->getPath(), "Interval", newValue).value(),
466                 Eq(boost::system::errc::success));
467     EXPECT_THAT(getProperty<uint64_t>(sut->getPath(), "Interval"),
468                 Eq(newValue));
469 }
470 
471 TEST_F(
472     TestReport,
473     settingIntervalWithInvalidValueDoesNotChangePropertyAndReturnsInvalidArgument)
474 {
475     uint64_t newValue = ReportManager::minInterval.count() - 1;
476     EXPECT_THAT(setProperty(sut->getPath(), "Interval", newValue).value(),
477                 Eq(boost::system::errc::invalid_argument));
478     EXPECT_THAT(getProperty<uint64_t>(sut->getPath(), "Interval"),
479                 Eq(defaultParams().interval().count()));
480 }
481 
482 TEST_F(TestReport, settingInvalidReportingTypeCreatesErrorMessage)
483 {
484     auto report = makeReport(defaultParams()
485                                  .reportId("report2")
486                                  .reportingType(ReportingType::onRequest)
487                                  .interval(Milliseconds{0}));
488 
489     EXPECT_THAT(
490         setProperty<std::string>(report->getPath(), "ReportingType", "Periodic")
491             .value(),
492         Eq(boost::system::errc::success));
493 
494     EXPECT_THAT(getProperty<std::string>(report->getPath(), "ReportingType"),
495                 Eq("Periodic"));
496     EXPECT_THAT(
497         getProperty<ErrorMessagesDbusType>(report->getPath(), "ErrorMessages"),
498         UnorderedElementsAre(
499             ErrorMessageDbusType(
500                 utils::enumToString(ErrorType::propertyConflict), "Interval"),
501             ErrorMessageDbusType(
502                 utils::enumToString(ErrorType::propertyConflict),
503                 "ReportingType")));
504 }
505 
506 TEST_F(TestReport, settingValidReportingTypeRemovesErrors)
507 {
508     auto report = makeReport(defaultParams()
509                                  .reportId("report2")
510                                  .reportingType(ReportingType::onRequest)
511                                  .interval(Milliseconds{0}));
512 
513     EXPECT_THAT(
514         setProperty<std::string>(report->getPath(), "ReportingType", "Periodic")
515             .value(),
516         Eq(boost::system::errc::success));
517     EXPECT_THAT(setProperty<std::string>(report->getPath(), "ReportingType",
518                                          "OnRequest")
519                     .value(),
520                 Eq(boost::system::errc::success));
521 
522     EXPECT_THAT(getProperty<std::string>(report->getPath(), "ReportingType"),
523                 Eq("OnRequest"));
524     EXPECT_THAT(
525         getProperty<ErrorMessagesDbusType>(report->getPath(), "ErrorMessages"),
526         IsEmpty());
527 }
528 
529 TEST_F(TestReport, settingInvalidIntervalDisablesReport)
530 {
531     auto report = makeReport(defaultParams()
532                                  .reportId("report2")
533                                  .reportingType(ReportingType::periodic)
534                                  .interval(ReportManager::minInterval));
535 
536     EXPECT_THAT(setProperty<uint64_t>(report->getPath(), "Interval", 0).value(),
537                 Eq(boost::system::errc::success));
538 
539     EXPECT_THAT(getProperty<uint64_t>(report->getPath(), "Interval"), Eq(0u));
540     EXPECT_THAT(
541         getProperty<ErrorMessagesDbusType>(report->getPath(), "ErrorMessages"),
542         UnorderedElementsAre(
543             ErrorMessageDbusType(
544                 utils::enumToString(ErrorType::propertyConflict), "Interval"),
545             ErrorMessageDbusType(
546                 utils::enumToString(ErrorType::propertyConflict),
547                 "ReportingType")));
548 }
549 
550 TEST_F(TestReport, settingValidIntervalEnablesReport)
551 {
552     auto report = makeReport(defaultParams()
553                                  .reportId("report2")
554                                  .reportingType(ReportingType::periodic)
555                                  .interval(ReportManager::minInterval));
556 
557     EXPECT_THAT(setProperty<uint64_t>(report->getPath(), "Interval", 0).value(),
558                 Eq(boost::system::errc::success));
559     EXPECT_THAT(setProperty<uint64_t>(report->getPath(), "Interval",
560                                       ReportManager::minInterval.count())
561                     .value(),
562                 Eq(boost::system::errc::success));
563 
564     EXPECT_THAT(getProperty<uint64_t>(report->getPath(), "Interval"),
565                 Eq(ReportManager::minInterval.count()));
566     EXPECT_THAT(
567         getProperty<ErrorMessagesDbusType>(report->getPath(), "ErrorMessages"),
568         IsEmpty());
569 }
570 
571 TEST_F(TestReport, settingEmitsReadingsUpdateHaveNoEffect)
572 {
573     EXPECT_THAT(
574         setProperty(sut->getPath(), "EmitsReadingsUpdate", true).value(),
575         Eq(boost::system::errc::read_only_file_system));
576     EXPECT_THAT(getProperty<bool>(sut->getPath(), "EmitsReadingsUpdate"),
577                 Eq(utils::contains(defaultParams().reportActions(),
578                                    ReportAction::emitsReadingsUpdate)));
579 }
580 
581 TEST_F(TestReport, settingLogToMetricReportCollectionHaveNoEffect)
582 {
583     EXPECT_THAT(
584         setProperty(sut->getPath(), "LogToMetricReportsCollection", true)
585             .value(),
586         Eq(boost::system::errc::read_only_file_system));
587     EXPECT_THAT(
588         getProperty<bool>(sut->getPath(), "LogToMetricReportsCollection"),
589         Eq(utils::contains(defaultParams().reportActions(),
590                            ReportAction::logToMetricReportsCollection)));
591 }
592 
593 TEST_F(TestReport, settingPersistencyToFalseRemovesReportFromStorage)
594 {
595     EXPECT_CALL(storageMock, store(_, _)).Times(0);
596     EXPECT_CALL(storageMock, remove(to_file_path(sut->getId())))
597         .Times(AtLeast(1));
598 
599     bool persistency = false;
600     EXPECT_THAT(setProperty(sut->getPath(), "Persistency", persistency).value(),
601                 Eq(boost::system::errc::success));
602     EXPECT_THAT(getProperty<bool>(sut->getPath(), "Persistency"),
603                 Eq(persistency));
604 }
605 
606 TEST_F(TestReport, deleteReport)
607 {
608     EXPECT_CALL(*reportManagerMock, removeReport(sut.get()));
609     auto ec = deleteReport(sut->getPath());
610     EXPECT_THAT(ec, Eq(boost::system::errc::success));
611 }
612 
613 TEST_F(TestReport, deletingNonExistingReportReturnInvalidRequestDescriptor)
614 {
615     auto ec =
616         deleteReport(utils::constants::reportDirPath.str + "NonExisting"s);
617     EXPECT_THAT(ec.value(), Eq(EBADR));
618 }
619 
620 TEST_F(TestReport, deleteReportExpectThatFileIsRemoveFromStorage)
621 {
622     EXPECT_CALL(storageMock, store(_, _)).Times(0);
623     EXPECT_CALL(storageMock, remove(to_file_path(sut->getId())))
624         .Times(AtLeast(1));
625 
626     auto ec = deleteReport(sut->getPath());
627     EXPECT_THAT(ec, Eq(boost::system::errc::success));
628 }
629 
630 TEST_F(TestReport, updatesTriggerIdWhenTriggerIsAdded)
631 {
632     utils::Messanger messanger(DbusEnvironment::getIoc());
633 
634     messanger.send(messages::TriggerPresenceChangedInd{
635         messages::Presence::Exist, "trigger1", {defaultParams().reportId()}});
636     messanger.send(messages::TriggerPresenceChangedInd{
637         messages::Presence::Exist, "trigger1", {defaultParams().reportId()}});
638     messanger.send(messages::TriggerPresenceChangedInd{
639         messages::Presence::Exist, "trigger2", {"someOtherReport"}});
640     messanger.send(messages::TriggerPresenceChangedInd{
641         messages::Presence::Exist,
642         "trigger3",
643         {"someOtherReport", defaultParams().reportId()}});
644 
645     EXPECT_THAT(
646         getProperty<std::vector<object_path>>(sut->getPath(), "Triggers"),
647         UnorderedElementsAre(utils::constants::triggerDirPath / "trigger1",
648                              utils::constants::triggerDirPath / "trigger3"));
649 }
650 
651 TEST_F(TestReport, updatesTriggerIdWhenTriggerIsRemoved)
652 {
653     utils::Messanger messanger(DbusEnvironment::getIoc());
654 
655     messanger.send(messages::TriggerPresenceChangedInd{
656         messages::Presence::Exist, "trigger1", {defaultParams().reportId()}});
657     messanger.send(messages::TriggerPresenceChangedInd{
658         messages::Presence::Exist, "trigger2", {defaultParams().reportId()}});
659     messanger.send(messages::TriggerPresenceChangedInd{
660         messages::Presence::Exist, "trigger3", {defaultParams().reportId()}});
661 
662     messanger.send(messages::TriggerPresenceChangedInd{
663         messages::Presence::Removed, "trigger1", {defaultParams().reportId()}});
664     messanger.send(messages::TriggerPresenceChangedInd{
665         messages::Presence::Removed, "trigger2", {}});
666     messanger.send(messages::TriggerPresenceChangedInd{
667         messages::Presence::Removed, "trigger1", {defaultParams().reportId()}});
668 
669     EXPECT_THAT(
670         getProperty<std::vector<object_path>>(sut->getPath(), "Triggers"),
671         UnorderedElementsAre(utils::constants::triggerDirPath / "trigger3"));
672 }
673 
674 TEST_F(TestReport, updatesTriggerIdWhenTriggerIsModified)
675 {
676     utils::Messanger messanger(DbusEnvironment::getIoc());
677 
678     messanger.send(messages::TriggerPresenceChangedInd{
679         messages::Presence::Exist, "trigger1", {defaultParams().reportId()}});
680     messanger.send(messages::TriggerPresenceChangedInd{
681         messages::Presence::Exist, "trigger2", {defaultParams().reportId()}});
682     messanger.send(messages::TriggerPresenceChangedInd{
683         messages::Presence::Exist, "trigger3", {defaultParams().reportId()}});
684 
685     messanger.send(messages::TriggerPresenceChangedInd{
686         messages::Presence::Exist, "trigger1", {defaultParams().reportId()}});
687     messanger.send(messages::TriggerPresenceChangedInd{
688         messages::Presence::Exist, "trigger2", {}});
689     messanger.send(messages::TriggerPresenceChangedInd{
690         messages::Presence::Exist, "trigger3", {defaultParams().reportId()}});
691 
692     EXPECT_THAT(
693         getProperty<std::vector<object_path>>(sut->getPath(), "Triggers"),
694         UnorderedElementsAre(utils::constants::triggerDirPath / "trigger1",
695                              utils::constants::triggerDirPath / "trigger3"));
696 }
697 
698 class TestReportStore :
699     public TestReport,
700     public WithParamInterface<std::pair<std::string, nlohmann::json>>
701 {
702     void SetUp() override
703     {}
704 };
705 
706 INSTANTIATE_TEST_SUITE_P(
707     _, TestReportStore,
708     Values(
709         std::make_pair("Enabled"s, nlohmann::json(defaultParams().enabled())),
710         std::make_pair("Version"s, nlohmann::json(6)),
711         std::make_pair("Id"s, nlohmann::json(defaultParams().reportId())),
712         std::make_pair("Name"s, nlohmann::json(defaultParams().reportName())),
713         std::make_pair("ReportingType",
714                        nlohmann::json(defaultParams().reportingType())),
715         std::make_pair("ReportActions", nlohmann::json(utils::transform(
716                                             defaultParams().reportActions(),
717                                             [](const auto v) {
718                                                 return utils::toUnderlying(v);
719                                             }))),
720         std::make_pair("Interval",
721                        nlohmann::json(defaultParams().interval().count())),
722         std::make_pair("AppendLimit",
723                        nlohmann::json(ReportParams().appendLimit())),
724         std::make_pair(
725             "ReadingParameters",
726             nlohmann::json(
727                 {{{tstring::SensorPath::str(),
728                    {{{tstring::Service::str(), "Service"},
729                      {tstring::Path::str(),
730                       "/xyz/openbmc_project/sensors/power/p1"},
731                      {tstring::Metadata::str(), "metadata1"}}}},
732                   {tstring::OperationType::str(), OperationType::avg},
733                   {tstring::Id::str(), "MetricId1"},
734                   {tstring::CollectionTimeScope::str(),
735                    CollectionTimeScope::point},
736                   {tstring::CollectionDuration::str(), 0}},
737                  {{tstring::SensorPath::str(),
738                    {{{tstring::Service::str(), "Service"},
739                      {tstring::Path::str(),
740                       "/xyz/openbmc_project/sensors/power/p2"},
741                      {tstring::Metadata::str(), "metadata2"}}}},
742                   {tstring::OperationType::str(), OperationType::avg},
743                   {tstring::Id::str(), "MetricId2"},
744                   {tstring::CollectionTimeScope::str(),
745                    CollectionTimeScope::point},
746                   {tstring::CollectionDuration::str(), 0}}}))));
747 
748 TEST_P(TestReportStore, settingPersistencyToTrueStoresReport)
749 {
750     sut = makeReport(defaultParams());
751 
752     {
753         InSequence seq;
754         EXPECT_CALL(storageMock, remove(to_file_path(sut->getId())));
755         EXPECT_CALL(checkPoint, Call());
756         EXPECT_CALL(storageMock, store(to_file_path(sut->getId()), _));
757     }
758 
759     setProperty(sut->getPath(), "Persistency", false);
760     checkPoint.Call();
761     setProperty(sut->getPath(), "Persistency", true);
762 
763     const auto& [key, value] = GetParam();
764 
765     ASSERT_THAT(storedConfiguration.at(key), Eq(value));
766 }
767 
768 TEST_P(TestReportStore, reportIsSavedToStorageAfterCreated)
769 {
770     EXPECT_CALL(storageMock,
771                 store(to_file_path(defaultParams().reportId()), _));
772 
773     sut = makeReport(defaultParams());
774 
775     const auto& [key, value] = GetParam();
776 
777     ASSERT_THAT(storedConfiguration.at(key), Eq(value));
778 }
779 
780 class TestReportValidNames :
781     public TestReport,
782     public WithParamInterface<ReportParams>
783 {
784   public:
785     void SetUp() override
786     {}
787 };
788 
789 INSTANTIATE_TEST_SUITE_P(
790     ValidNames, TestReportValidNames,
791     Values(defaultParams().reportName("Valid_1"),
792            defaultParams().reportName("Valid_1/Valid_2"),
793            defaultParams().reportName("Valid_1/Valid_2/Valid_3")));
794 
795 TEST_P(TestReportValidNames, reportCtorDoesNotThrowOnValidName)
796 {
797     EXPECT_NO_THROW(makeReport(GetParam()));
798 }
799 
800 class TestReportInvalidIds :
801     public TestReport,
802     public WithParamInterface<ReportParams>
803 {
804   public:
805     void SetUp() override
806     {}
807 };
808 
809 INSTANTIATE_TEST_SUITE_P(InvalidNames, TestReportInvalidIds,
810                          Values(defaultParams().reportId("/"),
811                                 defaultParams().reportId("/Invalid"),
812                                 defaultParams().reportId("Invalid/"),
813                                 defaultParams().reportId("Invalid/Invalid/"),
814                                 defaultParams().reportId("Invalid?")));
815 
816 TEST_P(TestReportInvalidIds, failsToCreateReportWithInvalidName)
817 {
818     EXPECT_CALL(storageMock, store).Times(0);
819 
820     EXPECT_THROW(makeReport(GetParam()), sdbusplus::exception::SdBusError);
821 }
822 
823 class TestReportAllReportTypes :
824     public TestReport,
825     public WithParamInterface<ReportParams>
826 {
827   public:
828     void SetUp() override
829     {
830         sut = makeReport(GetParam());
831     }
832 };
833 
834 INSTANTIATE_TEST_SUITE_P(
835     _, TestReportAllReportTypes,
836     Values(defaultParams().reportingType(ReportingType::onRequest),
837            defaultParams().reportingType(ReportingType::onChange),
838            defaultParams()
839                .reportingType(ReportingType::periodic)
840                .interval(ReportManager::minInterval)));
841 
842 TEST_P(TestReportAllReportTypes, returnPropertValueOfReportType)
843 {
844     EXPECT_THAT(utils::toReportingType(
845                     getProperty<std::string>(sut->getPath(), "ReportingType")),
846                 Eq(GetParam().reportingType()));
847 }
848 
849 TEST_P(TestReportAllReportTypes, readingsAreUpdated)
850 {
851     clockFake.system.advance(10ms);
852 
853     messanger.send(messages::UpdateReportInd{{sut->getId()}});
854     const auto [timestamp, readings] =
855         getProperty<Readings>(sut->getPath(), "Readings");
856 
857     EXPECT_THAT(Milliseconds{timestamp}, Eq(systemTimestamp + 10ms));
858 }
859 
860 TEST_P(TestReportAllReportTypes, readingsAreNotUpdatedWhenReportIsDisabled)
861 {
862     clockFake.system.advance(10ms);
863 
864     setProperty(sut->getPath(), "Enabled", false);
865     messanger.send(messages::UpdateReportInd{{sut->getId()}});
866     const auto [timestamp, readings] =
867         getProperty<Readings>(sut->getPath(), "Readings");
868 
869     EXPECT_THAT(Milliseconds{timestamp}, Eq(0ms));
870 }
871 
872 TEST_P(TestReportAllReportTypes, readingsAreNotUpdatedWhenReportIdDiffers)
873 {
874     clockFake.system.advance(10ms);
875 
876     messanger.send(messages::UpdateReportInd{{sut->getId() + "x"s}});
877     const auto [timestamp, readings] =
878         getProperty<Readings>(sut->getPath(), "Readings");
879 
880     EXPECT_THAT(Milliseconds{timestamp}, Eq(0ms));
881 }
882 
883 class TestReportOnRequestType : public TestReport
884 {
885     void SetUp() override
886     {
887         sut =
888             makeReport(defaultParams().reportingType(ReportingType::onRequest));
889     }
890 };
891 
892 TEST_F(TestReportOnRequestType, updatesReadingTimestamp)
893 {
894     clockFake.system.advance(10ms);
895 
896     ASSERT_THAT(update(sut->getPath()), Eq(boost::system::errc::success));
897 
898     const auto [timestamp, readings] =
899         getProperty<Readings>(sut->getPath(), "Readings");
900 
901     EXPECT_THAT(Milliseconds{timestamp}, Eq(systemTimestamp + 10ms));
902 }
903 
904 TEST_F(TestReportOnRequestType, updatesReadingWhenUpdateIsCalled)
905 {
906     ASSERT_THAT(update(sut->getPath()), Eq(boost::system::errc::success));
907 
908     const auto [timestamp, readings] =
909         getProperty<Readings>(sut->getPath(), "Readings");
910 
911     EXPECT_THAT(readings,
912                 ElementsAre(std::make_tuple("a"s, "b"s, 17.1, 114u),
913                             std::make_tuple("aa"s, "bb"s, 42.0, 74u)));
914 }
915 
916 class TestReportNonOnRequestType :
917     public TestReport,
918     public WithParamInterface<ReportParams>
919 {
920     void SetUp() override
921     {
922         sut = makeReport(GetParam());
923     }
924 };
925 
926 INSTANTIATE_TEST_SUITE_P(
927     _, TestReportNonOnRequestType,
928     Values(defaultParams().reportingType(ReportingType::periodic),
929            defaultParams().reportingType(ReportingType::onChange)));
930 
931 TEST_P(TestReportNonOnRequestType, readingsAreNotUpdateOnUpdateCall)
932 {
933     ASSERT_THAT(update(sut->getPath()), Eq(boost::system::errc::success));
934 
935     EXPECT_THAT(getProperty<Readings>(sut->getPath(), "Readings"),
936                 Eq(Readings{}));
937 }
938 
939 class TestReportNonPeriodicReport :
940     public TestReport,
941     public WithParamInterface<ReportParams>
942 {
943   public:
944     void SetUp() override
945     {
946         sut = makeReport(GetParam());
947     }
948 };
949 
950 INSTANTIATE_TEST_SUITE_P(
951     _, TestReportNonPeriodicReport,
952     Values(defaultParams().reportingType(ReportingType::onRequest),
953            defaultParams().reportingType(ReportingType::onChange)));
954 
955 TEST_P(TestReportNonPeriodicReport, readingsAreNotUpdatedAfterIntervalExpires)
956 {
957     DbusEnvironment::sleepFor(ReportManager::minInterval + 1ms);
958 
959     EXPECT_THAT(getProperty<Readings>(sut->getPath(), "Readings"),
960                 Eq(Readings{}));
961 }
962 
963 class TestReportPeriodicReport : public TestReport
964 {
965     void SetUp() override
966     {
967         sut = makeReport(defaultParams()
968                              .reportingType(ReportingType::periodic)
969                              .interval(ReportManager::minInterval));
970     }
971 };
972 
973 TEST_F(TestReportPeriodicReport, readingTimestampIsUpdatedAfterIntervalExpires)
974 {
975     clockFake.system.advance(10ms);
976     DbusEnvironment::sleepFor(ReportManager::minInterval + 1ms);
977 
978     const auto [timestamp, readings] =
979         getProperty<Readings>(sut->getPath(), "Readings");
980 
981     EXPECT_THAT(Milliseconds{timestamp}, Eq(systemTimestamp + 10ms));
982 }
983 
984 TEST_F(TestReportPeriodicReport, readingsAreUpdatedAfterIntervalExpires)
985 {
986     DbusEnvironment::sleepFor(ReportManager::minInterval + 1ms);
987 
988     const auto [timestamp, readings] =
989         getProperty<Readings>(sut->getPath(), "Readings");
990 
991     EXPECT_THAT(readings,
992                 ElementsAre(std::make_tuple("a"s, "b"s, 17.1, 114u),
993                             std::make_tuple("aa"s, "bb"s, 42.0, 74u)));
994 }
995 
996 struct ReportUpdatesReportParams
997 {
998     ReportParams reportParams;
999     std::vector<ReadingData> expectedReadings;
1000     bool expectedEnabled;
1001 };
1002 
1003 class TestReportWithReportUpdatesAndLimit :
1004     public TestReport,
1005     public WithParamInterface<ReportUpdatesReportParams>
1006 {
1007   public:
1008     void SetUp() override
1009     {}
1010 
1011     void changeReport(ReportingType rt, Milliseconds interval)
1012     {
1013         setProperty<std::string>(sut->getPath(), "ReportingType",
1014                                  utils::enumToString(rt));
1015         setProperty<uint64_t>(sut->getPath(), "Interval", interval.count());
1016     }
1017 
1018     auto readings()
1019     {
1020         auto [timestamp, readings] =
1021             getProperty<Readings>(sut->getPath(), "Readings");
1022         return readings;
1023     }
1024 
1025     void updateReportFourTimes()
1026     {
1027         for (int i = 0; i < 4; i++)
1028         {
1029             messanger.send(messages::UpdateReportInd{{sut->getId()}});
1030         }
1031     }
1032 };
1033 
1034 INSTANTIATE_TEST_SUITE_P(
1035     _, TestReportWithReportUpdatesAndLimit,
1036     Values(
1037         ReportUpdatesReportParams{
1038             defaultParams()
1039                 .reportUpdates(ReportUpdates::appendWrapsWhenFull)
1040                 .appendLimit(5),
1041             std::vector<ReadingData>{{std::make_tuple("aa"s, "bb"s, 42.0, 74u),
1042                                       std::make_tuple("a"s, "b"s, 17.1, 114u),
1043                                       std::make_tuple("aa"s, "bb"s, 42.0, 74u),
1044                                       std::make_tuple("aa"s, "bb"s, 42.0, 74u),
1045                                       std::make_tuple("a"s, "b"s, 17.1, 114u)}},
1046             true},
1047         ReportUpdatesReportParams{
1048             defaultParams()
1049                 .reportUpdates(ReportUpdates::appendWrapsWhenFull)
1050                 .appendLimit(4),
1051             std::vector<ReadingData>{
1052                 {std::make_tuple("a"s, "b"s, 17.1, 114u),
1053                  std::make_tuple("aa"s, "bb"s, 42.0, 74u),
1054                  std::make_tuple("a"s, "b"s, 17.1, 114u),
1055                  std::make_tuple("aa"s, "bb"s, 42.0, 74u)}},
1056             true},
1057         ReportUpdatesReportParams{
1058             defaultParams()
1059                 .reportUpdates(ReportUpdates::appendWrapsWhenFull)
1060                 .appendLimit(0),
1061             std::vector<ReadingData>{}, true},
1062         ReportUpdatesReportParams{
1063             defaultParams()
1064                 .reportUpdates(ReportUpdates::appendStopsWhenFull)
1065                 .appendLimit(10),
1066             std::vector<ReadingData>{
1067                 {std::make_tuple("a"s, "b"s, 17.1, 114u),
1068                  std::make_tuple("aa"s, "bb"s, 42.0, 74u),
1069                  std::make_tuple("a"s, "b"s, 17.1, 114u),
1070                  std::make_tuple("aa"s, "bb"s, 42.0, 74u),
1071                  std::make_tuple("a"s, "b"s, 17.1, 114u),
1072                  std::make_tuple("aa"s, "bb"s, 42.0, 74u),
1073                  std::make_tuple("a"s, "b"s, 17.1, 114u),
1074                  std::make_tuple("aa"s, "bb"s, 42.0, 74u)}},
1075             true},
1076         ReportUpdatesReportParams{
1077             defaultParams()
1078                 .reportUpdates(ReportUpdates::appendStopsWhenFull)
1079                 .appendLimit(5),
1080             std::vector<ReadingData>{{std::make_tuple("a"s, "b"s, 17.1, 114u),
1081                                       std::make_tuple("aa"s, "bb"s, 42.0, 74u),
1082                                       std::make_tuple("a"s, "b"s, 17.1, 114u),
1083                                       std::make_tuple("aa"s, "bb"s, 42.0, 74u),
1084                                       std::make_tuple("a"s, "b"s, 17.1, 114u)}},
1085             false},
1086         ReportUpdatesReportParams{
1087             defaultParams()
1088                 .reportUpdates(ReportUpdates::appendStopsWhenFull)
1089                 .appendLimit(4),
1090             std::vector<ReadingData>{
1091                 {std::make_tuple("a"s, "b"s, 17.1, 114u),
1092                  std::make_tuple("aa"s, "bb"s, 42.0, 74u),
1093                  std::make_tuple("a"s, "b"s, 17.1, 114u),
1094                  std::make_tuple("aa"s, "bb"s, 42.0, 74u)}},
1095             false},
1096         ReportUpdatesReportParams{
1097             defaultParams()
1098                 .reportUpdates(ReportUpdates::appendStopsWhenFull)
1099                 .appendLimit(0),
1100             std::vector<ReadingData>{}, false},
1101         ReportUpdatesReportParams{
1102             defaultParams()
1103                 .reportUpdates(ReportUpdates::overwrite)
1104                 .appendLimit(500),
1105             std::vector<ReadingData>{
1106                 {std::make_tuple("a"s, "b"s, 17.1, 114u),
1107                  std::make_tuple("aa"s, "bb"s, 42.0, 74u)}},
1108             true},
1109         ReportUpdatesReportParams{
1110             defaultParams()
1111                 .reportUpdates(ReportUpdates::overwrite)
1112                 .appendLimit(1),
1113             std::vector<ReadingData>{
1114                 {std::make_tuple("a"s, "b"s, 17.1, 114u),
1115                  std::make_tuple("aa"s, "bb"s, 42.0, 74u)}},
1116             true},
1117         ReportUpdatesReportParams{
1118             defaultParams()
1119                 .reportUpdates(ReportUpdates::overwrite)
1120                 .appendLimit(0),
1121             std::vector<ReadingData>{
1122                 {std::make_tuple("a"s, "b"s, 17.1, 114u),
1123                  std::make_tuple("aa"s, "bb"s, 42.0, 74u)}},
1124             true},
1125         ReportUpdatesReportParams{
1126             defaultParams()
1127                 .reportUpdates(ReportUpdates::appendStopsWhenFull)
1128                 .appendLimit(std::numeric_limits<uint64_t>::max()),
1129             std::vector<ReadingData>{
1130                 {std::make_tuple("a"s, "b"s, 17.1, 114u),
1131                  std::make_tuple("aa"s, "bb"s, 42.0, 74u)}},
1132             false}));
1133 
1134 TEST_P(TestReportWithReportUpdatesAndLimit,
1135        readingsAreUpdatedAfterIntervalExpires)
1136 {
1137     sut = makeReport(ReportParams(GetParam().reportParams)
1138                          .reportingType(ReportingType::periodic)
1139                          .interval(std::chrono::hours(1000)));
1140 
1141     updateReportFourTimes();
1142 
1143     EXPECT_THAT(readings(), ElementsAreArray(GetParam().expectedReadings));
1144     EXPECT_THAT(getProperty<bool>(sut->getPath(), "Enabled"),
1145                 Eq(GetParam().expectedEnabled));
1146 }
1147 
1148 TEST_P(TestReportWithReportUpdatesAndLimit,
1149        appendLimitIsRespectedAfterChangingToPeriodic)
1150 {
1151     sut = makeReport(ReportParams(GetParam().reportParams)
1152                          .reportingType(ReportingType::onRequest)
1153                          .interval(std::chrono::hours(0)));
1154 
1155     changeReport(ReportingType::periodic, std::chrono::hours(1000));
1156     updateReportFourTimes();
1157 
1158     EXPECT_THAT(readings(), ElementsAreArray(GetParam().expectedReadings));
1159     EXPECT_THAT(getProperty<bool>(sut->getPath(), "Enabled"),
1160                 Eq(GetParam().expectedEnabled));
1161 }
1162 
1163 TEST_P(TestReportWithReportUpdatesAndLimit,
1164        appendLimitIsIgnoredAfterChangingToOnRequest)
1165 {
1166     sut = makeReport(ReportParams(GetParam().reportParams)
1167                          .reportingType(ReportingType::periodic)
1168                          .interval(std::chrono::hours(1000)));
1169 
1170     changeReport(ReportingType::onRequest, Milliseconds{0});
1171     updateReportFourTimes();
1172 
1173     EXPECT_THAT(readings(), SizeIs(2u));
1174     EXPECT_THAT(getProperty<bool>(sut->getPath(), "Enabled"), Eq(true));
1175 }
1176 
1177 class TestReportInitialization : public TestReport
1178 {
1179   public:
1180     void SetUp() override
1181     {
1182         initMetricMocks(defaultParams().metricParameters());
1183     }
1184 
1185     void monitorProc(sdbusplus::message_t& msg)
1186     {
1187         std::string iface;
1188         std::vector<std::pair<std::string, std::variant<Readings>>>
1189             changed_properties;
1190         std::vector<std::string> invalidated_properties;
1191 
1192         msg.read(iface, changed_properties, invalidated_properties);
1193 
1194         if (iface == Report::reportIfaceName)
1195         {
1196             for (const auto& [name, value] : changed_properties)
1197             {
1198                 if (name == "Readings")
1199                 {
1200                     readingsUpdated.Call();
1201                 }
1202             }
1203         }
1204     }
1205 
1206     void makeMonitor()
1207     {
1208         monitor = std::make_unique<sdbusplus::bus::match_t>(
1209             *DbusEnvironment::getBus(),
1210             sdbusplus::bus::match::rules::propertiesChanged(
1211                 sut->getPath(), Report::reportIfaceName),
1212             [this](auto& msg) { monitorProc(msg); });
1213     }
1214 
1215     std::unique_ptr<sdbusplus::bus::match_t> monitor;
1216     MockFunction<void()> readingsUpdated;
1217 };
1218 
1219 TEST_F(TestReportInitialization,
1220        registersForMetricUpdatesWhenOnChangeReportCreated)
1221 {
1222     std::vector<const interfaces::MetricListener*> args;
1223     for (auto& metric : metricMocks)
1224     {
1225         EXPECT_CALL(*metric, registerForUpdates(_))
1226             .WillOnce(Invoke([&args](const interfaces::MetricListener& report) {
1227                 args.emplace_back(&report);
1228             }));
1229         ;
1230     }
1231 
1232     sut = makeReport(defaultParams().reportingType(ReportingType::onChange));
1233 
1234     EXPECT_THAT(args, SizeIs(metricMocks.size()));
1235     for (const auto* reportPtr : args)
1236     {
1237         EXPECT_THAT(reportPtr, Eq(sut.get()));
1238     }
1239 }
1240 
1241 TEST_F(TestReportInitialization,
1242        deregistersForMetricUpdatesWhenOnChangeReportDestroyed)
1243 {
1244     sut = makeReport(defaultParams().reportingType(ReportingType::onChange));
1245 
1246     for (auto& metric : metricMocks)
1247     {
1248         EXPECT_CALL(*metric,
1249                     unregisterFromUpdates(Ref(
1250                         static_cast<interfaces::MetricListener&>(*sut.get()))));
1251     }
1252 
1253     sut = nullptr;
1254 }
1255 
1256 TEST_F(TestReportInitialization,
1257        metricsAreInitializedWhenEnabledReportConstructed)
1258 {
1259     for (auto& metric : metricMocks)
1260     {
1261         EXPECT_CALL(*metric, initialize());
1262     }
1263     sut = makeReport(defaultParams().enabled(true));
1264 }
1265 
1266 TEST_F(TestReportInitialization,
1267        metricsAreNotInitializedWhenDisabledReportConstructed)
1268 {
1269     for (auto& metric : metricMocks)
1270     {
1271         EXPECT_CALL(*metric, initialize()).Times(0);
1272     }
1273     sut = makeReport(defaultParams().enabled(false));
1274 }
1275 
1276 TEST_F(TestReportInitialization,
1277        emitReadingsUpdateIsTrueReadingsPropertiesChangedSingalEmits)
1278 {
1279     EXPECT_CALL(readingsUpdated, Call())
1280         .WillOnce(
1281             InvokeWithoutArgs(DbusEnvironment::setPromise("readingsUpdated")));
1282 
1283     const auto elapsed = DbusEnvironment::measureTime([this] {
1284         sut = makeReport(defaultParams()
1285                              .reportingType(ReportingType::periodic)
1286                              .reportActions({ReportAction::emitsReadingsUpdate})
1287                              .interval(ReportManager::minInterval));
1288         makeMonitor();
1289         EXPECT_TRUE(DbusEnvironment::waitForFuture("readingsUpdated"));
1290     });
1291 
1292     EXPECT_THAT(elapsed, AllOf(Ge(ReportManager::minInterval),
1293                                Lt(ReportManager::minInterval * 2)));
1294 }
1295 
1296 TEST_F(TestReportInitialization,
1297        emitReadingsUpdateIsFalseReadingsPropertiesChangesSigalDoesNotEmits)
1298 {
1299     EXPECT_CALL(readingsUpdated, Call()).Times(0);
1300 
1301     sut = makeReport(defaultParams()
1302                          .reportingType(ReportingType::periodic)
1303                          .reportActions({}));
1304     makeMonitor();
1305     DbusEnvironment::sleepFor(defaultParams().interval() * 2);
1306 }
1307 
1308 TEST_F(TestReportInitialization, appendLimitDeducedProperly)
1309 {
1310     sut = makeReport(
1311         defaultParams().appendLimit(std::numeric_limits<uint64_t>::max()));
1312     auto appendLimit = getProperty<uint64_t>(sut->getPath(), "AppendLimit");
1313     EXPECT_EQ(appendLimit, 2ull);
1314 }
1315 
1316 TEST_F(TestReportInitialization, appendLimitSetToUintMaxIsStoredCorrectly)
1317 {
1318     sut = makeReport(
1319         ReportParams().appendLimit(std::numeric_limits<uint64_t>::max()));
1320 
1321     ASSERT_THAT(storedConfiguration.at("AppendLimit"),
1322                 Eq(std::numeric_limits<uint64_t>::max()));
1323 }
1324 
1325 TEST_F(TestReportInitialization, triggerIdsPropertyIsInitialzed)
1326 {
1327     for (const auto& triggerId : {"trigger1", "trigger2"})
1328     {
1329         messanger.on_receive<messages::CollectTriggerIdReq>(
1330             [this, triggerId](const auto& msg) {
1331                 messanger.send(messages::CollectTriggerIdResp{triggerId});
1332             });
1333     }
1334 
1335     sut = makeReport(ReportParams());
1336 
1337     EXPECT_THAT(
1338         getProperty<std::vector<object_path>>(sut->getPath(), "Triggers"),
1339         UnorderedElementsAre(utils::constants::triggerDirPath / "trigger1",
1340                              utils::constants::triggerDirPath / "trigger2"));
1341 }
1342 
1343 TEST_F(TestReportInitialization,
1344        metricValuesAreNotStoredForReportUpdatesDifferentThanAppendStopsWhenFull)
1345 {
1346     sut = makeReport(ReportParams()
1347                          .reportingType(ReportingType::periodic)
1348                          .interval(1h)
1349                          .reportUpdates(ReportUpdates::appendWrapsWhenFull)
1350                          .readings(Readings{{}, {{}}}));
1351 
1352     ASSERT_THAT(storedConfiguration.find("MetricValues"),
1353                 Eq(storedConfiguration.end()));
1354 }
1355 
1356 TEST_F(TestReportInitialization, metricValuesAreNotStoredForOnRequestReport)
1357 {
1358     sut = makeReport(ReportParams()
1359                          .reportingType(ReportingType::onRequest)
1360                          .reportUpdates(ReportUpdates::appendStopsWhenFull)
1361                          .readings(Readings{{}, {{}}}));
1362 
1363     ASSERT_THAT(storedConfiguration.find("MetricValues"),
1364                 Eq(storedConfiguration.end()));
1365 }
1366 
1367 TEST_F(TestReportInitialization,
1368        metricValuesAreStoredForNonOnRequestReportWithAppendStopsWhenFull)
1369 {
1370     const auto readings = Readings{{}, {{}}};
1371 
1372     sut = makeReport(ReportParams()
1373                          .reportingType(ReportingType::periodic)
1374                          .interval(1h)
1375                          .reportUpdates(ReportUpdates::appendStopsWhenFull)
1376                          .readings(readings));
1377 
1378     ASSERT_THAT(storedConfiguration.at("MetricValues").get<LabeledReadings>(),
1379                 Eq(utils::toLabeledReadings(readings)));
1380 }
1381 
1382 class TestReportInitializationOnChangeReport : public TestReportInitialization
1383 {
1384   public:
1385     void SetUp() override
1386     {
1387         initMetricMocks(params.metricParameters());
1388     }
1389 
1390     ReportParams params = defaultOnChangeParams();
1391 };
1392 
1393 TEST_F(TestReportInitializationOnChangeReport,
1394        doesntUpdateReadingsWhenNotRequired)
1395 {
1396     EXPECT_CALL(*metricMocks[0], updateReadings(_)).Times(0);
1397 
1398     ON_CALL(*metricMocks[0], isTimerRequired()).WillByDefault(Return(false));
1399 
1400     sut = makeReport(params);
1401 
1402     DbusEnvironment::sleepFor(500ms);
1403 }
1404 
1405 TEST_F(TestReportInitializationOnChangeReport, updatesReadingsWhenRequired)
1406 {
1407     EXPECT_CALL(*metricMocks[0], updateReadings(_))
1408         .WillOnce(Return())
1409         .WillOnce(
1410             InvokeWithoutArgs(DbusEnvironment::setPromise("readingsUpdated")))
1411         .WillRepeatedly(Return());
1412 
1413     ON_CALL(*metricMocks[0], isTimerRequired()).WillByDefault(Return(true));
1414 
1415     sut = makeReport(params);
1416 
1417     DbusEnvironment::waitForFuture("readingsUpdated");
1418 }
1419