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