blob: ca556b0f7e74b4199b2256b5d7261415dae7e9e3 [file] [log] [blame]
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +02001#include "dbus_environment.hpp"
Wludzik, Jozefe2362792020-10-27 17:23:55 +01002#include "mocks/json_storage_mock.hpp"
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +02003#include "mocks/metric_mock.hpp"
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +02004#include "mocks/report_manager_mock.hpp"
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +02005#include "params/report_params.hpp"
Wludzik, Jozefe2362792020-10-27 17:23:55 +01006#include "printers.hpp"
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +02007#include "report.hpp"
8#include "report_manager.hpp"
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +02009#include "utils/conv_container.hpp"
Krzysztof Grobelnyf32f6fe2020-10-30 13:51:58 +010010#include "utils/set_exception.hpp"
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020011
12#include <sdbusplus/exception.hpp>
13
14using namespace testing;
15using namespace std::literals::string_literals;
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020016using namespace std::chrono_literals;
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020017
18class TestReport : public Test
19{
20 public:
Wludzik, Jozefe2362792020-10-27 17:23:55 +010021 ReportParams defaultParams;
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020022
23 std::unique_ptr<ReportManagerMock> reportManagerMock =
Wludzik, Jozefe2362792020-10-27 17:23:55 +010024 std::make_unique<NiceMock<ReportManagerMock>>();
25 testing::NiceMock<StorageMock> storageMock;
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020026 std::vector<std::shared_ptr<MetricMock>> metricMocks = {
27 std::make_shared<NiceMock<MetricMock>>(),
28 std::make_shared<NiceMock<MetricMock>>(),
29 std::make_shared<NiceMock<MetricMock>>()};
30 std::unique_ptr<Report> sut;
31
Wludzik, Jozefe2362792020-10-27 17:23:55 +010032 MockFunction<void()> checkPoint;
33
34 TestReport()
35 {
36 ON_CALL(*metricMocks[0], getReadings())
37 .WillByDefault(ReturnRefOfCopy(std::vector<MetricValue>(
38 {MetricValue{"a", "b", 17.1, 114},
39 MetricValue{"aaa", "bbb", 21.7, 100}})));
40 ON_CALL(*metricMocks[1], getReadings())
41 .WillByDefault(ReturnRefOfCopy(
42 std::vector<MetricValue>({MetricValue{"aa", "bb", 42.0, 74}})));
43
44 for (size_t i = 0; i < metricMocks.size(); ++i)
45 {
46 ON_CALL(*metricMocks[i], to_json())
47 .WillByDefault(
48 Return(nlohmann::json("metric"s + std::to_string(i))));
49 }
50 }
51
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020052 void SetUp() override
53 {
54 sut = makeReport(ReportParams());
55 }
56
Wludzik, Jozefe2362792020-10-27 17:23:55 +010057 static interfaces::JsonStorage::FilePath to_file_path(std::string name)
58 {
59 return interfaces::JsonStorage::FilePath(
60 std::to_string(std::hash<std::string>{}(name)));
61 }
62
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020063 std::unique_ptr<Report> makeReport(const ReportParams& params)
64 {
65 return std::make_unique<Report>(
66 DbusEnvironment::getIoc(), DbusEnvironment::getObjServer(),
67 params.reportName(), params.reportingType(),
Wludzik, Jozefe2362792020-10-27 17:23:55 +010068 params.emitReadingUpdate(), params.logToMetricReportCollection(),
69 params.interval(), params.readingParameters(), *reportManagerMock,
70 storageMock,
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020071 utils::convContainer<std::shared_ptr<interfaces::Metric>>(
72 metricMocks));
73 }
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020074
75 template <class T>
76 static T getProperty(const std::string& path, const std::string& property)
77 {
78 std::promise<T> propertyPromise;
79 sdbusplus::asio::getProperty<T>(
80 *DbusEnvironment::getBus(), DbusEnvironment::serviceName(), path,
81 Report::reportIfaceName, property,
Krzysztof Grobelnyf32f6fe2020-10-30 13:51:58 +010082 [&propertyPromise](boost::system::error_code) {
83 utils::setException(propertyPromise, "GetProperty failed");
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020084 },
85 [&propertyPromise](T t) { propertyPromise.set_value(t); });
Krzysztof Grobelnyf32f6fe2020-10-30 13:51:58 +010086 return DbusEnvironment::waitForFuture(propertyPromise.get_future());
87 }
88
89 boost::system::error_code call(const std::string& path,
90 const std::string& interface,
91 const std::string& method)
92 {
93 std::promise<boost::system::error_code> methodPromise;
94 DbusEnvironment::getBus()->async_method_call(
95 [&methodPromise](boost::system::error_code ec) {
96 methodPromise.set_value(ec);
97 },
98 DbusEnvironment::serviceName(), path, interface, method);
99 return DbusEnvironment::waitForFuture(methodPromise.get_future());
100 }
101
102 boost::system::error_code update(const std::string& path)
103 {
104 return call(path, Report::reportIfaceName, "Update");
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200105 }
106
107 template <class T>
108 static boost::system::error_code setProperty(const std::string& path,
109 const std::string& property,
110 const T& newValue)
111 {
112 std::promise<boost::system::error_code> setPromise;
113 sdbusplus::asio::setProperty(
114 *DbusEnvironment::getBus(), DbusEnvironment::serviceName(), path,
115 Report::reportIfaceName, property, std::move(newValue),
116 [&setPromise](boost::system::error_code ec) {
117 setPromise.set_value(ec);
118 },
119 [&setPromise]() {
120 setPromise.set_value(boost::system::error_code{});
121 });
Krzysztof Grobelnyf32f6fe2020-10-30 13:51:58 +0100122 return DbusEnvironment::waitForFuture(setPromise.get_future());
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200123 }
124
125 boost::system::error_code deleteReport(const std::string& path)
126 {
Krzysztof Grobelnyf32f6fe2020-10-30 13:51:58 +0100127 return call(path, Report::deleteIfaceName, "Delete");
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200128 }
129};
130
131TEST_F(TestReport, verifyIfPropertiesHaveValidValue)
132{
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200133 EXPECT_THAT(getProperty<uint64_t>(sut->getPath(), "Interval"),
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100134 Eq(defaultParams.interval().count()));
135 EXPECT_THAT(getProperty<bool>(sut->getPath(), "Persistency"), Eq(true));
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200136 EXPECT_THAT(getProperty<bool>(sut->getPath(), "EmitsReadingsUpdate"),
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100137 Eq(defaultParams.emitReadingUpdate()));
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200138 EXPECT_THAT(
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200139 getProperty<bool>(sut->getPath(), "LogToMetricReportsCollection"),
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100140 Eq(defaultParams.logToMetricReportCollection()));
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200141 EXPECT_THAT(
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200142 getProperty<ReadingParameters>(sut->getPath(), "ReadingParameters"),
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100143 Eq(defaultParams.readingParameters()));
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200144}
145
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200146TEST_F(TestReport, readingsAreInitialyEmpty)
147{
148 EXPECT_THAT(getProperty<Readings>(sut->getPath(), "Readings"),
149 Eq(Readings{}));
150}
151
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200152TEST_F(TestReport, setIntervalWithValidValue)
153{
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100154 uint64_t newValue = defaultParams.interval().count() + 1;
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200155 EXPECT_THAT(setProperty(sut->getPath(), "Interval", newValue).value(),
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200156 Eq(boost::system::errc::success));
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200157 EXPECT_THAT(getProperty<uint64_t>(sut->getPath(), "Interval"),
158 Eq(newValue));
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200159}
160
161TEST_F(TestReport, settingIntervalWithInvalidValueDoesNotChangeProperty)
162{
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100163 uint64_t newValue = defaultParams.interval().count() - 1;
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200164 EXPECT_THAT(setProperty(sut->getPath(), "Interval", newValue).value(),
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200165 Eq(boost::system::errc::success));
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200166 EXPECT_THAT(getProperty<uint64_t>(sut->getPath(), "Interval"),
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100167 Eq(defaultParams.interval().count()));
168}
169
170TEST_F(TestReport, settingPersistencyToFalseRemovesReportFromStorage)
171{
172 EXPECT_CALL(storageMock, remove(to_file_path(sut->getName())));
173
174 bool persistency = false;
175 EXPECT_THAT(setProperty(sut->getPath(), "Persistency", persistency).value(),
176 Eq(boost::system::errc::success));
177 EXPECT_THAT(getProperty<bool>(sut->getPath(), "Persistency"),
178 Eq(persistency));
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200179}
180
181TEST_F(TestReport, deleteReport)
182{
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200183 EXPECT_CALL(*reportManagerMock, removeReport(sut.get()));
184 auto ec = deleteReport(sut->getPath());
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200185 EXPECT_THAT(ec, Eq(boost::system::errc::success));
186}
187
188TEST_F(TestReport, deletingNonExistingReportReturnInvalidRequestDescriptor)
189{
190 auto ec = deleteReport(Report::reportDir + "NonExisting"s);
191 EXPECT_THAT(ec.value(), Eq(EBADR));
192}
193
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100194TEST_F(TestReport, deleteReportExpectThatFileIsRemoveFromStorage)
195{
196 EXPECT_CALL(storageMock, remove(to_file_path(sut->getName())));
197 auto ec = deleteReport(sut->getPath());
198 EXPECT_THAT(ec, Eq(boost::system::errc::success));
199}
200
201class TestReportStore :
202 public TestReport,
203 public WithParamInterface<std::pair<std::string, nlohmann::json>>
204{
205 public:
206 void SetUp() override
207 {}
208
209 nlohmann::json storedConfiguration;
210};
211
212INSTANTIATE_TEST_SUITE_P(
213 _, TestReportStore,
214 Values(std::make_pair("Version"s, nlohmann::json(1)),
215 std::make_pair("Name"s, nlohmann::json(ReportParams().reportName())),
216 std::make_pair("ReportingType",
217 nlohmann::json(ReportParams().reportingType())),
218 std::make_pair("EmitsReadingsUpdate",
219 nlohmann::json(ReportParams().emitReadingUpdate())),
220 std::make_pair(
221 "LogToMetricReportsCollection",
222 nlohmann::json(ReportParams().logToMetricReportCollection())),
223 std::make_pair("Interval",
224 nlohmann::json(ReportParams().interval().count())),
225 std::make_pair("ReadingParameters",
226 nlohmann::json({"metric0", "metric1", "metric2"}))));
227
228TEST_P(TestReportStore, settingPersistencyToTrueStoresReport)
229{
230 sut = makeReport(ReportParams());
231
232 {
233 InSequence seq;
234 EXPECT_CALL(storageMock, remove(to_file_path(sut->getName())));
235 EXPECT_CALL(checkPoint, Call());
236 EXPECT_CALL(storageMock, store(to_file_path(sut->getName()), _))
237 .WillOnce(SaveArg<1>(&storedConfiguration));
238 }
239
240 setProperty(sut->getPath(), "Persistency", false);
241 checkPoint.Call();
242 setProperty(sut->getPath(), "Persistency", true);
243
244 const auto& [key, value] = GetParam();
245
246 ASSERT_THAT(storedConfiguration.at(key), Eq(value));
247}
248
249TEST_P(TestReportStore, reportIsSavedToStorageAfterCreated)
250{
251 EXPECT_CALL(storageMock,
252 store(to_file_path(ReportParams().reportName()), _))
253 .WillOnce(SaveArg<1>(&storedConfiguration));
254
255 sut = makeReport(ReportParams());
256
257 const auto& [key, value] = GetParam();
258
259 ASSERT_THAT(storedConfiguration.at(key), Eq(value));
260}
261
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200262class TestReportValidNames :
263 public TestReport,
264 public WithParamInterface<ReportParams>
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200265{
266 public:
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200267 void SetUp() override
268 {}
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200269};
270
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200271INSTANTIATE_TEST_SUITE_P(
272 ValidNames, TestReportValidNames,
273 Values(ReportParams().reportName("Valid_1"),
274 ReportParams().reportName("Valid_1/Valid_2"),
275 ReportParams().reportName("Valid_1/Valid_2/Valid_3")));
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200276
277TEST_P(TestReportValidNames, reportCtorDoesNotThrowOnValidName)
278{
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200279 EXPECT_NO_THROW(makeReport(GetParam()));
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200280}
281
282class TestReportInvalidNames :
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200283 public TestReport,
284 public WithParamInterface<ReportParams>
285{
286 public:
287 void SetUp() override
288 {}
289};
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200290
291INSTANTIATE_TEST_SUITE_P(InvalidNames, TestReportInvalidNames,
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200292 Values(ReportParams().reportName("/"),
293 ReportParams().reportName("/Invalid"),
294 ReportParams().reportName("Invalid/"),
295 ReportParams().reportName("Invalid/Invalid/"),
296 ReportParams().reportName("Invalid?")));
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200297
298TEST_P(TestReportInvalidNames, reportCtorThrowOnInvalidName)
299{
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200300 EXPECT_THROW(makeReport(GetParam()), sdbusplus::exception::SdBusError);
301}
302
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100303TEST_F(TestReportInvalidNames, reportCtorThrowOnInvalidNameAndNoStoreIsCalled)
304{
305 EXPECT_CALL(storageMock, store).Times(0);
306 EXPECT_THROW(makeReport(ReportParams().reportName("/Invalid")),
307 sdbusplus::exception::SdBusError);
308}
309
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200310class TestReportAllReportTypes :
311 public TestReport,
312 public WithParamInterface<ReportParams>
313{
314 void SetUp() override
315 {
316 sut = makeReport(GetParam());
317 }
318};
319
320INSTANTIATE_TEST_SUITE_P(_, TestReportAllReportTypes,
321 Values(ReportParams().reportingType("OnRequest"),
322 ReportParams().reportingType("OnChange"),
323 ReportParams().reportingType("Periodic")));
324
325TEST_P(TestReportAllReportTypes, returnPropertValueOfReportType)
326{
327 EXPECT_THAT(getProperty<std::string>(sut->getPath(), "ReportingType"),
328 Eq(GetParam().reportingType()));
329}
330
Krzysztof Grobelnyf32f6fe2020-10-30 13:51:58 +0100331class TestReportOnRequestType : public TestReport
332{
333 void SetUp() override
334 {
335 sut = makeReport(ReportParams().reportingType("OnRequest"));
336 }
337};
338
339TEST_F(TestReportOnRequestType, updatesReadingTimestamp)
340{
341 const uint64_t expectedTime = std::time(0);
342
343 ASSERT_THAT(update(sut->getPath()), Eq(boost::system::errc::success));
344
345 const auto [timestamp, readings] =
346 getProperty<Readings>(sut->getPath(), "Readings");
347
348 EXPECT_THAT(timestamp, Ge(expectedTime));
349}
350
351TEST_F(TestReportOnRequestType, updatesReadingWhenUpdateIsCalled)
352{
353 ASSERT_THAT(update(sut->getPath()), Eq(boost::system::errc::success));
354
355 const auto [timestamp, readings] =
356 getProperty<Readings>(sut->getPath(), "Readings");
357
358 EXPECT_THAT(readings,
359 ElementsAre(std::make_tuple("a"s, "b"s, 17.1, 114u),
360 std::make_tuple("aaa"s, "bbb"s, 21.7, 100u),
361 std::make_tuple("aa"s, "bb"s, 42.0, 74u)));
362}
363
364class TestReportNonOnRequestType :
365 public TestReport,
366 public WithParamInterface<ReportParams>
367{
368 void SetUp() override
369 {
370 sut = makeReport(GetParam());
371 }
372};
373
374INSTANTIATE_TEST_SUITE_P(_, TestReportNonOnRequestType,
375 Values(ReportParams().reportingType("Periodic"),
376 ReportParams().reportingType("OnChange")));
377
378TEST_P(TestReportNonOnRequestType, readingsAreNotUpdateOnUpdateCall)
379{
380 ASSERT_THAT(update(sut->getPath()), Eq(boost::system::errc::success));
381
382 EXPECT_THAT(getProperty<Readings>(sut->getPath(), "Readings"),
383 Eq(Readings{}));
384}
385
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200386class TestReportNonPeriodicReport :
387 public TestReport,
388 public WithParamInterface<ReportParams>
389{
390 void SetUp() override
391 {
392 sut = makeReport(GetParam());
393 }
394};
395
396INSTANTIATE_TEST_SUITE_P(_, TestReportNonPeriodicReport,
397 Values(ReportParams().reportingType("OnRequest"),
398 ReportParams().reportingType("OnChange")));
399
400TEST_P(TestReportNonPeriodicReport, readingsAreNotUpdatedAfterIntervalExpires)
401{
402 DbusEnvironment::sleepFor(ReportManager::minInterval + 1ms);
403
404 EXPECT_THAT(getProperty<Readings>(sut->getPath(), "Readings"),
405 Eq(Readings{}));
406}
407
408class TestReportPeriodicReport : public TestReport
409{
410 void SetUp() override
411 {
412 sut = makeReport(ReportParams().reportingType("Periodic"));
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200413 }
414};
415
416TEST_F(TestReportPeriodicReport, readingTimestampIsUpdatedAfterIntervalExpires)
417{
418 const uint64_t expectedTime = std::time(0);
419 DbusEnvironment::sleepFor(ReportManager::minInterval + 1ms);
420
421 const auto [timestamp, readings] =
422 getProperty<Readings>(sut->getPath(), "Readings");
423
424 EXPECT_THAT(timestamp, Ge(expectedTime));
425}
426
427TEST_F(TestReportPeriodicReport, readingsAreUpdatedAfterIntervalExpires)
428{
429 DbusEnvironment::sleepFor(ReportManager::minInterval + 1ms);
430
431 const auto [timestamp, readings] =
432 getProperty<Readings>(sut->getPath(), "Readings");
433
434 EXPECT_THAT(readings,
435 ElementsAre(std::make_tuple("a"s, "b"s, 17.1, 114u),
436 std::make_tuple("aaa"s, "bbb"s, 21.7, 100u),
437 std::make_tuple("aa"s, "bb"s, 42.0, 74u)));
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200438}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100439
440class TestReportInitialization : public TestReport
441{
442 public:
443 void SetUp() override
444 {}
445
446 void monitorProc(sdbusplus::message::message& msg)
447 {
448 std::string iface;
449 std::vector<std::pair<std::string, std::variant<Readings>>>
450 changed_properties;
451 std::vector<std::string> invalidated_properties;
452
453 msg.read(iface, changed_properties, invalidated_properties);
454
455 if (iface == Report::reportIfaceName)
456 {
457 for (const auto& [name, value] : changed_properties)
458 {
459 if (name == "Readings")
460 {
461 readingsUpdated.Call();
462 }
463 }
464 }
465 }
466
467 void makeMonitor()
468 {
469 monitor = std::make_unique<sdbusplus::bus::match::match>(
470 *DbusEnvironment::getBus(),
471 sdbusplus::bus::match::rules::propertiesChanged(
472 sut->getPath(), Report::reportIfaceName),
473 [this](auto& msg) { monitorProc(msg); });
474 }
475
476 std::unique_ptr<sdbusplus::bus::match::match> monitor;
477 MockFunction<void()> readingsUpdated;
478};
479
Krzysztof Grobelny6ccfcbf2020-11-04 09:31:36 +0100480TEST_F(TestReportInitialization, metricsAreInitializedWhenConstructed)
481{
482 for (auto& metric : metricMocks)
483 {
484 EXPECT_CALL(*metric, initialize());
485 }
486
487 sut = makeReport(ReportParams());
488}
489
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100490TEST_F(TestReportInitialization, readingsPropertiesChangedSingalEmits)
491{
492 sut = makeReport(defaultParams.reportingType("Periodic"));
493 EXPECT_CALL(readingsUpdated, Call());
494 makeMonitor();
495 DbusEnvironment::sleepFor(defaultParams.interval() + 1ms);
496}