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