1 #include "dbus_environment.hpp" 2 #include "helpers.hpp" 3 #include "mocks/json_storage_mock.hpp" 4 #include "mocks/report_factory_mock.hpp" 5 #include "params/report_params.hpp" 6 #include "report.hpp" 7 #include "report_manager.hpp" 8 #include "utils/conversion.hpp" 9 #include "utils/set_exception.hpp" 10 #include "utils/transform.hpp" 11 12 using namespace testing; 13 using namespace std::string_literals; 14 using namespace std::chrono_literals; 15 16 class TestReportManager : public Test 17 { 18 public: 19 ReportParams reportParams; 20 21 std::unique_ptr<ReportFactoryMock> reportFactoryMockPtr = 22 std::make_unique<StrictMock<ReportFactoryMock>>(); 23 ReportFactoryMock& reportFactoryMock = *reportFactoryMockPtr; 24 25 std::unique_ptr<StorageMock> storageMockPtr = 26 std::make_unique<NiceMock<StorageMock>>(); 27 StorageMock& storageMock = *storageMockPtr; 28 29 std::unique_ptr<ReportMock> reportMockPtr = 30 std::make_unique<NiceMock<ReportMock>>(reportParams.reportName()); 31 ReportMock& reportMock = *reportMockPtr; 32 33 std::unique_ptr<ReportManager> sut; 34 35 MockFunction<void(std::string)> checkPoint; 36 37 void SetUp() override 38 { 39 EXPECT_CALL(reportFactoryMock, convertMetricParams(_, _)) 40 .Times(AnyNumber()); 41 42 sut = std::make_unique<ReportManager>(std::move(reportFactoryMockPtr), 43 std::move(storageMockPtr), 44 DbusEnvironment::getObjServer()); 45 } 46 47 void TearDown() override 48 { 49 DbusEnvironment::synchronizeIoc(); 50 } 51 52 std::pair<boost::system::error_code, std::string> 53 addReport(const ReportParams& params) 54 { 55 std::promise<std::pair<boost::system::error_code, std::string>> 56 addReportPromise; 57 DbusEnvironment::getBus()->async_method_call( 58 [&addReportPromise](boost::system::error_code ec, 59 const std::string& path) { 60 addReportPromise.set_value({ec, path}); 61 }, 62 DbusEnvironment::serviceName(), ReportManager::reportManagerPath, 63 ReportManager::reportManagerIfaceName, "AddReportFutureVersion", 64 params.reportName(), params.reportingType(), 65 params.emitReadingUpdate(), params.logToMetricReportCollection(), 66 params.interval().count(), 67 toReadingParameters(params.metricParameters())); 68 return DbusEnvironment::waitForFuture(addReportPromise.get_future()); 69 } 70 71 template <class T> 72 static T getProperty(std::string property) 73 { 74 auto propertyPromise = std::promise<T>(); 75 auto propertyFuture = propertyPromise.get_future(); 76 sdbusplus::asio::getProperty<T>( 77 *DbusEnvironment::getBus(), DbusEnvironment::serviceName(), 78 ReportManager::reportManagerPath, 79 ReportManager::reportManagerIfaceName, property, 80 [&propertyPromise](const boost::system::error_code& ec, T t) { 81 if (ec) 82 { 83 utils::setException(propertyPromise, "Get property failed"); 84 return; 85 } 86 propertyPromise.set_value(t); 87 }); 88 return DbusEnvironment::waitForFuture(std::move(propertyFuture)); 89 } 90 91 static std::string prepareReportNameWithLength(size_t length) 92 { 93 std::stringstream reportNameStream; 94 for (size_t i = 0; i < length; ++i) 95 { 96 reportNameStream << "z"; 97 } 98 return reportNameStream.str(); 99 } 100 }; 101 102 TEST_F(TestReportManager, minInterval) 103 { 104 EXPECT_THAT(getProperty<uint64_t>("MinInterval"), 105 Eq(ReportManager::minInterval.count())); 106 } 107 108 TEST_F(TestReportManager, maxReports) 109 { 110 EXPECT_THAT(getProperty<size_t>("MaxReports"), 111 Eq(ReportManager::maxReports)); 112 } 113 114 TEST_F(TestReportManager, addReport) 115 { 116 EXPECT_CALL(reportFactoryMock, convertMetricParams(_, _)); 117 reportFactoryMock.expectMake(reportParams, Ref(*sut), Ref(storageMock)) 118 .WillOnce(Return(ByMove(std::move(reportMockPtr)))); 119 120 auto [ec, path] = addReport(reportParams); 121 EXPECT_THAT(ec.value(), Eq(boost::system::errc::success)); 122 EXPECT_THAT(path, Eq(reportMock.getPath())); 123 } 124 125 TEST_F(TestReportManager, addReportWithMaxLengthName) 126 { 127 std::string reportName = 128 prepareReportNameWithLength(ReportManager::maxReportNameLength); 129 reportParams.reportName(reportName); 130 reportFactoryMock.expectMake(reportParams, Ref(*sut), Ref(storageMock)); 131 132 auto [ec, path] = addReport(reportParams); 133 134 EXPECT_THAT(ec.value(), Eq(boost::system::errc::success)); 135 EXPECT_THAT(path, Eq("/"s + reportName)); 136 } 137 138 TEST_F(TestReportManager, DISABLED_failToAddReportWithTooLongName) 139 { 140 reportFactoryMock.expectMake(std::nullopt, Ref(*sut), Ref(storageMock)) 141 .Times(0); 142 143 reportParams.reportName( 144 prepareReportNameWithLength(ReportManager::maxReportNameLength + 1)); 145 146 auto [ec, path] = addReport(reportParams); 147 148 EXPECT_THAT(ec.value(), Eq(boost::system::errc::invalid_argument)); 149 EXPECT_THAT(path, Eq(std::string())); 150 } 151 152 TEST_F(TestReportManager, DISABLED_failToAddReportTwice) 153 { 154 reportFactoryMock.expectMake(reportParams, Ref(*sut), Ref(storageMock)) 155 .WillOnce(Return(ByMove(std::move(reportMockPtr)))); 156 157 addReport(reportParams); 158 159 auto [ec, path] = addReport(reportParams); 160 161 EXPECT_THAT(ec.value(), Eq(boost::system::errc::file_exists)); 162 EXPECT_THAT(path, Eq(std::string())); 163 } 164 165 TEST_F(TestReportManager, DISABLED_failToAddReportWithInvalidInterval) 166 { 167 reportFactoryMock.expectMake(std::nullopt, Ref(*sut), Ref(storageMock)) 168 .Times(0); 169 170 reportParams.reportingType("Periodic"); 171 reportParams.interval(reportParams.interval() - 1ms); 172 173 auto [ec, path] = addReport(reportParams); 174 175 EXPECT_THAT(ec.value(), Eq(boost::system::errc::invalid_argument)); 176 EXPECT_THAT(path, Eq(std::string())); 177 } 178 179 TEST_F(TestReportManager, DISABLED_failToAddReportWithInvalidReportingType) 180 { 181 reportFactoryMock.expectMake(std::nullopt, Ref(*sut), Ref(storageMock)) 182 .Times(0); 183 184 reportParams.reportingType("Invalid"); 185 186 auto [ec, path] = addReport(reportParams); 187 188 EXPECT_THAT(ec.value(), Eq(boost::system::errc::invalid_argument)); 189 EXPECT_THAT(path, Eq(std::string())); 190 } 191 192 TEST_F(TestReportManager, DISABLED_failToAddReportWithMoreSensorsThanExpected) 193 { 194 reportFactoryMock.expectMake(std::nullopt, Ref(*sut), Ref(storageMock)) 195 .Times(0); 196 197 auto metricParams = reportParams.metricParameters(); 198 for (size_t i = 0; i < ReportManager::maxReadingParams + 1; i++) 199 { 200 metricParams.push_back(metricParams.front()); 201 } 202 reportParams.metricParameters(std::move(metricParams)); 203 204 auto [ec, path] = addReport(reportParams); 205 206 EXPECT_THAT(ec.value(), Eq(boost::system::errc::argument_list_too_long)); 207 EXPECT_THAT(path, Eq(std::string())); 208 } 209 210 TEST_F(TestReportManager, DISABLED_failToAddReportWhenMaxReportIsReached) 211 { 212 reportFactoryMock.expectMake(std::nullopt, Ref(*sut), Ref(storageMock)) 213 .Times(ReportManager::maxReports); 214 215 for (size_t i = 0; i < ReportManager::maxReports; i++) 216 { 217 reportParams.reportName(reportParams.reportName() + std::to_string(i)); 218 219 auto [ec, path] = addReport(reportParams); 220 EXPECT_THAT(ec.value(), Eq(boost::system::errc::success)); 221 } 222 223 reportParams.reportName(reportParams.reportName() + 224 std::to_string(ReportManager::maxReports)); 225 auto [ec, path] = addReport(reportParams); 226 227 EXPECT_THAT(ec.value(), Eq(boost::system::errc::too_many_files_open)); 228 EXPECT_THAT(path, Eq(std::string())); 229 } 230 231 TEST_F(TestReportManager, removeReport) 232 { 233 { 234 InSequence seq; 235 EXPECT_CALL(reportFactoryMock, convertMetricParams(_, _)); 236 reportFactoryMock.expectMake(reportParams, Ref(*sut), Ref(storageMock)) 237 .WillOnce(Return(ByMove(std::move(reportMockPtr)))); 238 EXPECT_CALL(reportMock, Die()); 239 EXPECT_CALL(checkPoint, Call("end")); 240 } 241 242 addReport(reportParams); 243 sut->removeReport(&reportMock); 244 checkPoint.Call("end"); 245 } 246 247 TEST_F(TestReportManager, removingReportThatIsNotInContainerHasNoEffect) 248 { 249 { 250 InSequence seq; 251 EXPECT_CALL(checkPoint, Call("end")); 252 EXPECT_CALL(reportMock, Die()); 253 } 254 255 sut->removeReport(&reportMock); 256 checkPoint.Call("end"); 257 } 258 259 TEST_F(TestReportManager, removingSameReportTwiceHasNoSideEffect) 260 { 261 { 262 InSequence seq; 263 EXPECT_CALL(reportFactoryMock, convertMetricParams(_, _)); 264 reportFactoryMock.expectMake(reportParams, Ref(*sut), Ref(storageMock)) 265 .WillOnce(Return(ByMove(std::move(reportMockPtr)))); 266 EXPECT_CALL(reportMock, Die()); 267 EXPECT_CALL(checkPoint, Call("end")); 268 } 269 270 addReport(reportParams); 271 sut->removeReport(&reportMock); 272 sut->removeReport(&reportMock); 273 checkPoint.Call("end"); 274 } 275 276 TEST_F(TestReportManager, updateReportCallsUpdateReadingsForExistReport) 277 { 278 reportFactoryMock.expectMake(reportParams, Ref(*sut), Ref(storageMock)) 279 .WillOnce(Return(ByMove(std::move(reportMockPtr)))); 280 EXPECT_CALL(reportMock, updateReadings()); 281 282 addReport(reportParams); 283 sut->updateReport(reportParams.reportName()); 284 } 285 286 TEST_F(TestReportManager, updateReportDoNothingIfReportDoesNotExist) 287 { 288 reportFactoryMock.expectMake(reportParams, Ref(*sut), Ref(storageMock)) 289 .WillOnce(Return(ByMove(std::move(reportMockPtr)))); 290 EXPECT_CALL(reportMock, updateReadings()).Times(0); 291 292 addReport(reportParams); 293 sut->updateReport("NotAReport"); 294 } 295 296 class TestReportManagerWithAggregationOperationType : 297 public TestReportManager, 298 public WithParamInterface<OperationType> 299 { 300 public: 301 OperationType operationType = GetParam(); 302 }; 303 304 INSTANTIATE_TEST_SUITE_P(_, TestReportManagerWithAggregationOperationType, 305 Values(OperationType::single, OperationType::max, 306 OperationType::min, OperationType::avg, 307 OperationType::sum)); 308 309 TEST_P(TestReportManagerWithAggregationOperationType, 310 addReportWithDifferentOperationTypes) 311 { 312 reportParams.metricParameters( 313 std::vector<LabeledMetricParameters>{{LabeledMetricParameters{ 314 {LabeledSensorParameters{"Service", 315 "/xyz/openbmc_project/sensors/power/p1"}}, 316 operationType, 317 "MetricId1", 318 "Metadata1", 319 CollectionTimeScope::point, 320 CollectionDuration(Milliseconds(0u))}}}); 321 322 reportFactoryMock.expectMake(reportParams, Ref(*sut), Ref(storageMock)) 323 .WillOnce(Return(ByMove(std::move(reportMockPtr)))); 324 325 auto [ec, path] = addReport(reportParams); 326 327 EXPECT_THAT(ec.value(), Eq(boost::system::errc::success)); 328 EXPECT_THAT(path, Eq("/"s + reportParams.reportName())); 329 } 330 331 class TestReportManagerStorage : public TestReportManager 332 { 333 public: 334 using FilePath = interfaces::JsonStorage::FilePath; 335 using DirectoryPath = interfaces::JsonStorage::DirectoryPath; 336 337 void SetUp() override 338 { 339 EXPECT_CALL(reportFactoryMock, convertMetricParams(_, _)).Times(0); 340 341 ON_CALL(storageMock, list()) 342 .WillByDefault(Return(std::vector<FilePath>{FilePath("report1")})); 343 ON_CALL(storageMock, load(FilePath("report1"))) 344 .WillByDefault(InvokeWithoutArgs([this] { return data; })); 345 } 346 347 void makeReportManager() 348 { 349 sut = std::make_unique<ReportManager>(std::move(reportFactoryMockPtr), 350 std::move(storageMockPtr), 351 DbusEnvironment::getObjServer()); 352 } 353 354 nlohmann::json data = nlohmann::json{ 355 {"Version", Report::reportVersion}, 356 {"Name", reportParams.reportName()}, 357 {"ReportingType", reportParams.reportingType()}, 358 {"EmitsReadingsUpdate", reportParams.emitReadingUpdate()}, 359 {"LogToMetricReportsCollection", 360 reportParams.logToMetricReportCollection()}, 361 {"Interval", reportParams.interval().count()}, 362 {"ReadingParameters", reportParams.metricParameters()}}; 363 }; 364 365 TEST_F(TestReportManagerStorage, reportManagerCtorAddReportFromStorage) 366 { 367 reportFactoryMock.expectMake(reportParams, _, Ref(storageMock)); 368 369 makeReportManager(); 370 } 371 372 TEST_F(TestReportManagerStorage, 373 reportManagerCtorRemoveFileIfVersionDoesNotMatch) 374 { 375 data["Version"] = Report::reportVersion - 1; 376 377 EXPECT_CALL(storageMock, remove(FilePath("report1"))); 378 379 makeReportManager(); 380 } 381 382 TEST_F(TestReportManagerStorage, 383 reportManagerCtorRemoveFileIfIntervalHasWrongType) 384 { 385 data["Interval"] = "1000"; 386 387 EXPECT_CALL(storageMock, remove(FilePath("report1"))); 388 389 makeReportManager(); 390 } 391