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