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