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