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