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