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