blob: b53d3595feae6f04d8f53efc3c111c608b781c53 [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"
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020010
11#include <sdbusplus/exception.hpp>
12
13using namespace testing;
14using namespace std::literals::string_literals;
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020015using namespace std::chrono_literals;
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020016
17class TestReport : public Test
18{
19 public:
Wludzik, Jozefe2362792020-10-27 17:23:55 +010020 ReportParams defaultParams;
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020021
22 std::unique_ptr<ReportManagerMock> reportManagerMock =
Wludzik, Jozefe2362792020-10-27 17:23:55 +010023 std::make_unique<NiceMock<ReportManagerMock>>();
24 testing::NiceMock<StorageMock> storageMock;
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020025 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
Wludzik, Jozefe2362792020-10-27 17:23:55 +010031 MockFunction<void()> checkPoint;
32
33 TestReport()
34 {
35 ON_CALL(*metricMocks[0], getReadings())
36 .WillByDefault(ReturnRefOfCopy(std::vector<MetricValue>(
37 {MetricValue{"a", "b", 17.1, 114},
38 MetricValue{"aaa", "bbb", 21.7, 100}})));
39 ON_CALL(*metricMocks[1], getReadings())
40 .WillByDefault(ReturnRefOfCopy(
41 std::vector<MetricValue>({MetricValue{"aa", "bb", 42.0, 74}})));
42
43 for (size_t i = 0; i < metricMocks.size(); ++i)
44 {
45 ON_CALL(*metricMocks[i], to_json())
46 .WillByDefault(
47 Return(nlohmann::json("metric"s + std::to_string(i))));
48 }
49 }
50
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020051 void SetUp() override
52 {
53 sut = makeReport(ReportParams());
54 }
55
Wludzik, Jozefe2362792020-10-27 17:23:55 +010056 static interfaces::JsonStorage::FilePath to_file_path(std::string name)
57 {
58 return interfaces::JsonStorage::FilePath(
59 std::to_string(std::hash<std::string>{}(name)));
60 }
61
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020062 std::unique_ptr<Report> makeReport(const ReportParams& params)
63 {
64 return std::make_unique<Report>(
65 DbusEnvironment::getIoc(), DbusEnvironment::getObjServer(),
66 params.reportName(), params.reportingType(),
Wludzik, Jozefe2362792020-10-27 17:23:55 +010067 params.emitReadingUpdate(), params.logToMetricReportCollection(),
68 params.interval(), params.readingParameters(), *reportManagerMock,
69 storageMock,
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +020070 utils::convContainer<std::shared_ptr<interfaces::Metric>>(
71 metricMocks));
72 }
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +020073
74 template <class T>
75 static T getProperty(const std::string& path, const std::string& property)
76 {
77 std::promise<T> propertyPromise;
78 sdbusplus::asio::getProperty<T>(
79 *DbusEnvironment::getBus(), DbusEnvironment::serviceName(), path,
80 Report::reportIfaceName, property,
81 [&propertyPromise](boost::system::error_code ec) {
82 EXPECT_THAT(static_cast<bool>(ec), ::testing::Eq(false));
83 propertyPromise.set_value(T{});
84 },
85 [&propertyPromise](T t) { propertyPromise.set_value(t); });
86 return DbusEnvironment::waitForFuture(propertyPromise.get_future())
87 .value_or(T{});
88 }
89
90 template <class T>
91 static boost::system::error_code setProperty(const std::string& path,
92 const std::string& property,
93 const T& newValue)
94 {
95 std::promise<boost::system::error_code> setPromise;
96 sdbusplus::asio::setProperty(
97 *DbusEnvironment::getBus(), DbusEnvironment::serviceName(), path,
98 Report::reportIfaceName, property, std::move(newValue),
99 [&setPromise](boost::system::error_code ec) {
100 setPromise.set_value(ec);
101 },
102 [&setPromise]() {
103 setPromise.set_value(boost::system::error_code{});
104 });
105 return DbusEnvironment::waitForFuture(setPromise.get_future())
106 .value_or(boost::system::error_code{});
107 }
108
109 boost::system::error_code deleteReport(const std::string& path)
110 {
111 std::promise<boost::system::error_code> deleteReportPromise;
112 DbusEnvironment::getBus()->async_method_call(
113 [&deleteReportPromise](boost::system::error_code ec) {
114 deleteReportPromise.set_value(ec);
115 },
116 DbusEnvironment::serviceName(), path, Report::deleteIfaceName,
117 "Delete");
118 return DbusEnvironment::waitForFuture(deleteReportPromise.get_future())
119 .value_or(boost::system::error_code{});
120 }
121};
122
123TEST_F(TestReport, verifyIfPropertiesHaveValidValue)
124{
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200125 EXPECT_THAT(getProperty<uint64_t>(sut->getPath(), "Interval"),
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100126 Eq(defaultParams.interval().count()));
127 EXPECT_THAT(getProperty<bool>(sut->getPath(), "Persistency"), Eq(true));
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200128 EXPECT_THAT(getProperty<bool>(sut->getPath(), "EmitsReadingsUpdate"),
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100129 Eq(defaultParams.emitReadingUpdate()));
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200130 EXPECT_THAT(
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200131 getProperty<bool>(sut->getPath(), "LogToMetricReportsCollection"),
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100132 Eq(defaultParams.logToMetricReportCollection()));
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200133 EXPECT_THAT(
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200134 getProperty<ReadingParameters>(sut->getPath(), "ReadingParameters"),
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100135 Eq(defaultParams.readingParameters()));
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200136}
137
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200138TEST_F(TestReport, readingsAreInitialyEmpty)
139{
140 EXPECT_THAT(getProperty<Readings>(sut->getPath(), "Readings"),
141 Eq(Readings{}));
142}
143
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200144TEST_F(TestReport, setIntervalWithValidValue)
145{
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100146 uint64_t newValue = defaultParams.interval().count() + 1;
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200147 EXPECT_THAT(setProperty(sut->getPath(), "Interval", newValue).value(),
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200148 Eq(boost::system::errc::success));
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200149 EXPECT_THAT(getProperty<uint64_t>(sut->getPath(), "Interval"),
150 Eq(newValue));
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200151}
152
153TEST_F(TestReport, settingIntervalWithInvalidValueDoesNotChangeProperty)
154{
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100155 uint64_t newValue = defaultParams.interval().count() - 1;
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200156 EXPECT_THAT(setProperty(sut->getPath(), "Interval", newValue).value(),
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200157 Eq(boost::system::errc::success));
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200158 EXPECT_THAT(getProperty<uint64_t>(sut->getPath(), "Interval"),
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100159 Eq(defaultParams.interval().count()));
160}
161
162TEST_F(TestReport, settingPersistencyToFalseRemovesReportFromStorage)
163{
164 EXPECT_CALL(storageMock, remove(to_file_path(sut->getName())));
165
166 bool persistency = false;
167 EXPECT_THAT(setProperty(sut->getPath(), "Persistency", persistency).value(),
168 Eq(boost::system::errc::success));
169 EXPECT_THAT(getProperty<bool>(sut->getPath(), "Persistency"),
170 Eq(persistency));
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200171}
172
173TEST_F(TestReport, deleteReport)
174{
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200175 EXPECT_CALL(*reportManagerMock, removeReport(sut.get()));
176 auto ec = deleteReport(sut->getPath());
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200177 EXPECT_THAT(ec, Eq(boost::system::errc::success));
178}
179
180TEST_F(TestReport, deletingNonExistingReportReturnInvalidRequestDescriptor)
181{
182 auto ec = deleteReport(Report::reportDir + "NonExisting"s);
183 EXPECT_THAT(ec.value(), Eq(EBADR));
184}
185
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100186TEST_F(TestReport, deleteReportExpectThatFileIsRemoveFromStorage)
187{
188 EXPECT_CALL(storageMock, remove(to_file_path(sut->getName())));
189 auto ec = deleteReport(sut->getPath());
190 EXPECT_THAT(ec, Eq(boost::system::errc::success));
191}
192
193class TestReportStore :
194 public TestReport,
195 public WithParamInterface<std::pair<std::string, nlohmann::json>>
196{
197 public:
198 void SetUp() override
199 {}
200
201 nlohmann::json storedConfiguration;
202};
203
204INSTANTIATE_TEST_SUITE_P(
205 _, TestReportStore,
206 Values(std::make_pair("Version"s, nlohmann::json(1)),
207 std::make_pair("Name"s, nlohmann::json(ReportParams().reportName())),
208 std::make_pair("ReportingType",
209 nlohmann::json(ReportParams().reportingType())),
210 std::make_pair("EmitsReadingsUpdate",
211 nlohmann::json(ReportParams().emitReadingUpdate())),
212 std::make_pair(
213 "LogToMetricReportsCollection",
214 nlohmann::json(ReportParams().logToMetricReportCollection())),
215 std::make_pair("Interval",
216 nlohmann::json(ReportParams().interval().count())),
217 std::make_pair("ReadingParameters",
218 nlohmann::json({"metric0", "metric1", "metric2"}))));
219
220TEST_P(TestReportStore, settingPersistencyToTrueStoresReport)
221{
222 sut = makeReport(ReportParams());
223
224 {
225 InSequence seq;
226 EXPECT_CALL(storageMock, remove(to_file_path(sut->getName())));
227 EXPECT_CALL(checkPoint, Call());
228 EXPECT_CALL(storageMock, store(to_file_path(sut->getName()), _))
229 .WillOnce(SaveArg<1>(&storedConfiguration));
230 }
231
232 setProperty(sut->getPath(), "Persistency", false);
233 checkPoint.Call();
234 setProperty(sut->getPath(), "Persistency", true);
235
236 const auto& [key, value] = GetParam();
237
238 ASSERT_THAT(storedConfiguration.at(key), Eq(value));
239}
240
241TEST_P(TestReportStore, reportIsSavedToStorageAfterCreated)
242{
243 EXPECT_CALL(storageMock,
244 store(to_file_path(ReportParams().reportName()), _))
245 .WillOnce(SaveArg<1>(&storedConfiguration));
246
247 sut = makeReport(ReportParams());
248
249 const auto& [key, value] = GetParam();
250
251 ASSERT_THAT(storedConfiguration.at(key), Eq(value));
252}
253
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200254class TestReportValidNames :
255 public TestReport,
256 public WithParamInterface<ReportParams>
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200257{
258 public:
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200259 void SetUp() override
260 {}
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200261};
262
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200263INSTANTIATE_TEST_SUITE_P(
264 ValidNames, TestReportValidNames,
265 Values(ReportParams().reportName("Valid_1"),
266 ReportParams().reportName("Valid_1/Valid_2"),
267 ReportParams().reportName("Valid_1/Valid_2/Valid_3")));
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200268
269TEST_P(TestReportValidNames, reportCtorDoesNotThrowOnValidName)
270{
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200271 EXPECT_NO_THROW(makeReport(GetParam()));
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200272}
273
274class TestReportInvalidNames :
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200275 public TestReport,
276 public WithParamInterface<ReportParams>
277{
278 public:
279 void SetUp() override
280 {}
281};
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200282
283INSTANTIATE_TEST_SUITE_P(InvalidNames, TestReportInvalidNames,
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200284 Values(ReportParams().reportName("/"),
285 ReportParams().reportName("/Invalid"),
286 ReportParams().reportName("Invalid/"),
287 ReportParams().reportName("Invalid/Invalid/"),
288 ReportParams().reportName("Invalid?")));
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200289
290TEST_P(TestReportInvalidNames, reportCtorThrowOnInvalidName)
291{
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200292 EXPECT_THROW(makeReport(GetParam()), sdbusplus::exception::SdBusError);
293}
294
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100295TEST_F(TestReportInvalidNames, reportCtorThrowOnInvalidNameAndNoStoreIsCalled)
296{
297 EXPECT_CALL(storageMock, store).Times(0);
298 EXPECT_THROW(makeReport(ReportParams().reportName("/Invalid")),
299 sdbusplus::exception::SdBusError);
300}
301
Krzysztof Grobelnyc8e3a642020-10-23 12:29:16 +0200302class TestReportAllReportTypes :
303 public TestReport,
304 public WithParamInterface<ReportParams>
305{
306 void SetUp() override
307 {
308 sut = makeReport(GetParam());
309 }
310};
311
312INSTANTIATE_TEST_SUITE_P(_, TestReportAllReportTypes,
313 Values(ReportParams().reportingType("OnRequest"),
314 ReportParams().reportingType("OnChange"),
315 ReportParams().reportingType("Periodic")));
316
317TEST_P(TestReportAllReportTypes, returnPropertValueOfReportType)
318{
319 EXPECT_THAT(getProperty<std::string>(sut->getPath(), "ReportingType"),
320 Eq(GetParam().reportingType()));
321}
322
323class TestReportNonPeriodicReport :
324 public TestReport,
325 public WithParamInterface<ReportParams>
326{
327 void SetUp() override
328 {
329 sut = makeReport(GetParam());
330 }
331};
332
333INSTANTIATE_TEST_SUITE_P(_, TestReportNonPeriodicReport,
334 Values(ReportParams().reportingType("OnRequest"),
335 ReportParams().reportingType("OnChange")));
336
337TEST_P(TestReportNonPeriodicReport, readingsAreNotUpdatedAfterIntervalExpires)
338{
339 DbusEnvironment::sleepFor(ReportManager::minInterval + 1ms);
340
341 EXPECT_THAT(getProperty<Readings>(sut->getPath(), "Readings"),
342 Eq(Readings{}));
343}
344
345class TestReportPeriodicReport : public TestReport
346{
347 void SetUp() override
348 {
349 sut = makeReport(ReportParams().reportingType("Periodic"));
350
351 ASSERT_THAT(metricMocks, SizeIs(Ge(2)));
352 ON_CALL(*metricMocks[0], getReadings())
353 .WillByDefault(ReturnRefOfCopy(std::vector<MetricValue>(
354 {MetricValue{"a", "b", 17.1, 114},
355 MetricValue{"aaa", "bbb", 21.7, 100}})));
356 ON_CALL(*metricMocks[1], getReadings())
357 .WillByDefault(ReturnRefOfCopy(
358 std::vector<MetricValue>({MetricValue{"aa", "bb", 42.0, 74}})));
359 }
360};
361
362TEST_F(TestReportPeriodicReport, readingTimestampIsUpdatedAfterIntervalExpires)
363{
364 const uint64_t expectedTime = std::time(0);
365 DbusEnvironment::sleepFor(ReportManager::minInterval + 1ms);
366
367 const auto [timestamp, readings] =
368 getProperty<Readings>(sut->getPath(), "Readings");
369
370 EXPECT_THAT(timestamp, Ge(expectedTime));
371}
372
373TEST_F(TestReportPeriodicReport, readingsAreUpdatedAfterIntervalExpires)
374{
375 DbusEnvironment::sleepFor(ReportManager::minInterval + 1ms);
376
377 const auto [timestamp, readings] =
378 getProperty<Readings>(sut->getPath(), "Readings");
379
380 EXPECT_THAT(readings,
381 ElementsAre(std::make_tuple("a"s, "b"s, 17.1, 114u),
382 std::make_tuple("aaa"s, "bbb"s, 21.7, 100u),
383 std::make_tuple("aa"s, "bb"s, 42.0, 74u)));
Wludzik, Jozef2f9f9b82020-10-13 09:07:45 +0200384}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100385
386class TestReportInitialization : public TestReport
387{
388 public:
389 void SetUp() override
390 {}
391
392 void monitorProc(sdbusplus::message::message& msg)
393 {
394 std::string iface;
395 std::vector<std::pair<std::string, std::variant<Readings>>>
396 changed_properties;
397 std::vector<std::string> invalidated_properties;
398
399 msg.read(iface, changed_properties, invalidated_properties);
400
401 if (iface == Report::reportIfaceName)
402 {
403 for (const auto& [name, value] : changed_properties)
404 {
405 if (name == "Readings")
406 {
407 readingsUpdated.Call();
408 }
409 }
410 }
411 }
412
413 void makeMonitor()
414 {
415 monitor = std::make_unique<sdbusplus::bus::match::match>(
416 *DbusEnvironment::getBus(),
417 sdbusplus::bus::match::rules::propertiesChanged(
418 sut->getPath(), Report::reportIfaceName),
419 [this](auto& msg) { monitorProc(msg); });
420 }
421
422 std::unique_ptr<sdbusplus::bus::match::match> monitor;
423 MockFunction<void()> readingsUpdated;
424};
425
426TEST_F(TestReportInitialization, readingsPropertiesChangedSingalEmits)
427{
428 sut = makeReport(defaultParams.reportingType("Periodic"));
429 EXPECT_CALL(readingsUpdated, Call());
430 makeMonitor();
431 DbusEnvironment::sleepFor(defaultParams.interval() + 1ms);
432}