1 #include "dbus_environment.hpp" 2 #include "mocks/metric_mock.hpp" 3 #include "mocks/report_manager_mock.hpp" 4 #include "params/report_params.hpp" 5 #include "report.hpp" 6 #include "report_manager.hpp" 7 #include "utils/conv_container.hpp" 8 9 #include <sdbusplus/exception.hpp> 10 11 using namespace testing; 12 using namespace std::literals::string_literals; 13 using namespace std::chrono_literals; 14 15 class TestReport : public Test 16 { 17 public: 18 bool defaultEmitReadingSignal = true; 19 bool defaultLogToMetricReportCollection = true; 20 uint64_t defaultInterval = ReportManager::minInterval.count(); 21 ReadingParameters defaultReadingParams = {}; 22 23 std::unique_ptr<ReportManagerMock> reportManagerMock = 24 std::make_unique<StrictMock<ReportManagerMock>>(); 25 std::vector<std::shared_ptr<MetricMock>> metricMocks = { 26 std::make_shared<NiceMock<MetricMock>>(), 27 std::make_shared<NiceMock<MetricMock>>(), 28 std::make_shared<NiceMock<MetricMock>>()}; 29 std::unique_ptr<Report> sut; 30 31 void SetUp() override 32 { 33 sut = makeReport(ReportParams()); 34 } 35 36 std::unique_ptr<Report> makeReport(const ReportParams& params) 37 { 38 return std::make_unique<Report>( 39 DbusEnvironment::getIoc(), DbusEnvironment::getObjServer(), 40 params.reportName(), params.reportingType(), 41 defaultEmitReadingSignal, defaultLogToMetricReportCollection, 42 std::chrono::milliseconds(defaultInterval), defaultReadingParams, 43 *reportManagerMock, 44 utils::convContainer<std::shared_ptr<interfaces::Metric>>( 45 metricMocks)); 46 } 47 48 template <class T> 49 static T getProperty(const std::string& path, const std::string& property) 50 { 51 std::promise<T> propertyPromise; 52 sdbusplus::asio::getProperty<T>( 53 *DbusEnvironment::getBus(), DbusEnvironment::serviceName(), path, 54 Report::reportIfaceName, property, 55 [&propertyPromise](boost::system::error_code ec) { 56 EXPECT_THAT(static_cast<bool>(ec), ::testing::Eq(false)); 57 propertyPromise.set_value(T{}); 58 }, 59 [&propertyPromise](T t) { propertyPromise.set_value(t); }); 60 return DbusEnvironment::waitForFuture(propertyPromise.get_future()) 61 .value_or(T{}); 62 } 63 64 template <class T> 65 static boost::system::error_code setProperty(const std::string& path, 66 const std::string& property, 67 const T& newValue) 68 { 69 std::promise<boost::system::error_code> setPromise; 70 sdbusplus::asio::setProperty( 71 *DbusEnvironment::getBus(), DbusEnvironment::serviceName(), path, 72 Report::reportIfaceName, property, std::move(newValue), 73 [&setPromise](boost::system::error_code ec) { 74 setPromise.set_value(ec); 75 }, 76 [&setPromise]() { 77 setPromise.set_value(boost::system::error_code{}); 78 }); 79 return DbusEnvironment::waitForFuture(setPromise.get_future()) 80 .value_or(boost::system::error_code{}); 81 } 82 83 boost::system::error_code deleteReport(const std::string& path) 84 { 85 std::promise<boost::system::error_code> deleteReportPromise; 86 DbusEnvironment::getBus()->async_method_call( 87 [&deleteReportPromise](boost::system::error_code ec) { 88 deleteReportPromise.set_value(ec); 89 }, 90 DbusEnvironment::serviceName(), path, Report::deleteIfaceName, 91 "Delete"); 92 return DbusEnvironment::waitForFuture(deleteReportPromise.get_future()) 93 .value_or(boost::system::error_code{}); 94 } 95 }; 96 97 TEST_F(TestReport, verifyIfPropertiesHaveValidValue) 98 { 99 EXPECT_THAT(getProperty<uint64_t>(sut->getPath(), "Interval"), 100 Eq(defaultInterval)); 101 EXPECT_THAT(getProperty<bool>(sut->getPath(), "Persistency"), Eq(false)); 102 EXPECT_THAT(getProperty<bool>(sut->getPath(), "EmitsReadingsUpdate"), 103 Eq(defaultEmitReadingSignal)); 104 EXPECT_THAT( 105 getProperty<bool>(sut->getPath(), "LogToMetricReportsCollection"), 106 Eq(defaultLogToMetricReportCollection)); 107 EXPECT_THAT( 108 getProperty<ReadingParameters>(sut->getPath(), "ReadingParameters"), 109 Eq(defaultReadingParams)); 110 } 111 112 TEST_F(TestReport, readingsAreInitialyEmpty) 113 { 114 EXPECT_THAT(getProperty<Readings>(sut->getPath(), "Readings"), 115 Eq(Readings{})); 116 } 117 118 TEST_F(TestReport, setIntervalWithValidValue) 119 { 120 uint64_t newValue = defaultInterval + 1; 121 EXPECT_THAT(setProperty(sut->getPath(), "Interval", newValue).value(), 122 Eq(boost::system::errc::success)); 123 EXPECT_THAT(getProperty<uint64_t>(sut->getPath(), "Interval"), 124 Eq(newValue)); 125 } 126 127 TEST_F(TestReport, settingIntervalWithInvalidValueDoesNotChangeProperty) 128 { 129 uint64_t newValue = defaultInterval - 1; 130 EXPECT_THAT(setProperty(sut->getPath(), "Interval", newValue).value(), 131 Eq(boost::system::errc::success)); 132 EXPECT_THAT(getProperty<uint64_t>(sut->getPath(), "Interval"), 133 Eq(defaultInterval)); 134 } 135 136 TEST_F(TestReport, deleteReport) 137 { 138 EXPECT_CALL(*reportManagerMock, removeReport(sut.get())); 139 auto ec = deleteReport(sut->getPath()); 140 EXPECT_THAT(ec, Eq(boost::system::errc::success)); 141 } 142 143 TEST_F(TestReport, deletingNonExistingReportReturnInvalidRequestDescriptor) 144 { 145 auto ec = deleteReport(Report::reportDir + "NonExisting"s); 146 EXPECT_THAT(ec.value(), Eq(EBADR)); 147 } 148 149 class TestReportValidNames : 150 public TestReport, 151 public WithParamInterface<ReportParams> 152 { 153 public: 154 void SetUp() override 155 {} 156 }; 157 158 INSTANTIATE_TEST_SUITE_P( 159 ValidNames, TestReportValidNames, 160 Values(ReportParams().reportName("Valid_1"), 161 ReportParams().reportName("Valid_1/Valid_2"), 162 ReportParams().reportName("Valid_1/Valid_2/Valid_3"))); 163 164 TEST_P(TestReportValidNames, reportCtorDoesNotThrowOnValidName) 165 { 166 EXPECT_NO_THROW(makeReport(GetParam())); 167 } 168 169 class TestReportInvalidNames : 170 public TestReport, 171 public WithParamInterface<ReportParams> 172 { 173 public: 174 void SetUp() override 175 {} 176 }; 177 178 INSTANTIATE_TEST_SUITE_P(InvalidNames, TestReportInvalidNames, 179 Values(ReportParams().reportName("/"), 180 ReportParams().reportName("/Invalid"), 181 ReportParams().reportName("Invalid/"), 182 ReportParams().reportName("Invalid/Invalid/"), 183 ReportParams().reportName("Invalid?"))); 184 185 TEST_P(TestReportInvalidNames, reportCtorThrowOnInvalidName) 186 { 187 EXPECT_THROW(makeReport(GetParam()), sdbusplus::exception::SdBusError); 188 } 189 190 class TestReportAllReportTypes : 191 public TestReport, 192 public WithParamInterface<ReportParams> 193 { 194 void SetUp() override 195 { 196 sut = makeReport(GetParam()); 197 } 198 }; 199 200 INSTANTIATE_TEST_SUITE_P(_, TestReportAllReportTypes, 201 Values(ReportParams().reportingType("OnRequest"), 202 ReportParams().reportingType("OnChange"), 203 ReportParams().reportingType("Periodic"))); 204 205 TEST_P(TestReportAllReportTypes, returnPropertValueOfReportType) 206 { 207 EXPECT_THAT(getProperty<std::string>(sut->getPath(), "ReportingType"), 208 Eq(GetParam().reportingType())); 209 } 210 211 class TestReportNonPeriodicReport : 212 public TestReport, 213 public WithParamInterface<ReportParams> 214 { 215 void SetUp() override 216 { 217 sut = makeReport(GetParam()); 218 } 219 }; 220 221 INSTANTIATE_TEST_SUITE_P(_, TestReportNonPeriodicReport, 222 Values(ReportParams().reportingType("OnRequest"), 223 ReportParams().reportingType("OnChange"))); 224 225 TEST_P(TestReportNonPeriodicReport, readingsAreNotUpdatedAfterIntervalExpires) 226 { 227 DbusEnvironment::sleepFor(ReportManager::minInterval + 1ms); 228 229 EXPECT_THAT(getProperty<Readings>(sut->getPath(), "Readings"), 230 Eq(Readings{})); 231 } 232 233 class TestReportPeriodicReport : public TestReport 234 { 235 void SetUp() override 236 { 237 sut = makeReport(ReportParams().reportingType("Periodic")); 238 239 ASSERT_THAT(metricMocks, SizeIs(Ge(2))); 240 ON_CALL(*metricMocks[0], getReadings()) 241 .WillByDefault(ReturnRefOfCopy(std::vector<MetricValue>( 242 {MetricValue{"a", "b", 17.1, 114}, 243 MetricValue{"aaa", "bbb", 21.7, 100}}))); 244 ON_CALL(*metricMocks[1], getReadings()) 245 .WillByDefault(ReturnRefOfCopy( 246 std::vector<MetricValue>({MetricValue{"aa", "bb", 42.0, 74}}))); 247 } 248 }; 249 250 TEST_F(TestReportPeriodicReport, readingTimestampIsUpdatedAfterIntervalExpires) 251 { 252 const uint64_t expectedTime = std::time(0); 253 DbusEnvironment::sleepFor(ReportManager::minInterval + 1ms); 254 255 const auto [timestamp, readings] = 256 getProperty<Readings>(sut->getPath(), "Readings"); 257 258 EXPECT_THAT(timestamp, Ge(expectedTime)); 259 } 260 261 TEST_F(TestReportPeriodicReport, readingsAreUpdatedAfterIntervalExpires) 262 { 263 DbusEnvironment::sleepFor(ReportManager::minInterval + 1ms); 264 265 const auto [timestamp, readings] = 266 getProperty<Readings>(sut->getPath(), "Readings"); 267 268 EXPECT_THAT(readings, 269 ElementsAre(std::make_tuple("a"s, "b"s, 17.1, 114u), 270 std::make_tuple("aaa"s, "bbb"s, 21.7, 100u), 271 std::make_tuple("aa"s, "bb"s, 42.0, 74u))); 272 } 273