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