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