1 #include "dbus_environment.hpp"
2 #include "mocks/json_storage_mock.hpp"
3 #include "mocks/report_factory_mock.hpp"
4 #include "params/report_params.hpp"
5 #include "report.hpp"
6 #include "report_manager.hpp"
7 #include "utils/transform.hpp"
8 
9 using namespace testing;
10 using namespace std::chrono_literals;
11 
12 class TestReportManager : public Test
13 {
14   public:
15     ReportParams reportParams;
16 
17     std::unique_ptr<ReportFactoryMock> reportFactoryMockPtr =
18         std::make_unique<StrictMock<ReportFactoryMock>>();
19     ReportFactoryMock& reportFactoryMock = *reportFactoryMockPtr;
20 
21     std::unique_ptr<StorageMock> storageMockPtr =
22         std::make_unique<NiceMock<StorageMock>>();
23     StorageMock& storageMock = *storageMockPtr;
24 
25     std::unique_ptr<ReportManager> sut;
26 
27     MockFunction<void(std::string)> checkPoint;
28 
29     void SetUp() override
30     {
31         sut = std::make_unique<ReportManager>(std::move(reportFactoryMockPtr),
32                                               std::move(storageMockPtr),
33                                               DbusEnvironment::getObjServer());
34     }
35 
36     void TearDown() override
37     {
38         DbusEnvironment::synchronizeIoc();
39     }
40 
41     std::pair<boost::system::error_code, std::string>
42         addReport(const ReportParams& params)
43     {
44         std::promise<std::pair<boost::system::error_code, std::string>>
45             addReportPromise;
46         DbusEnvironment::getBus()->async_method_call(
47             [&addReportPromise](boost::system::error_code ec,
48                                 const std::string& path) {
49                 addReportPromise.set_value({ec, path});
50             },
51             DbusEnvironment::serviceName(), ReportManager::reportManagerPath,
52             ReportManager::reportManagerIfaceName, "AddReport",
53             params.reportName(), params.reportingType(),
54             params.emitReadingUpdate(), params.logToMetricReportCollection(),
55             static_cast<uint64_t>(params.interval().count()),
56             params.readingParameters());
57         return DbusEnvironment::waitForFuture(addReportPromise.get_future());
58     }
59 
60     template <class T>
61     static T getProperty(std::string property)
62     {
63         std::promise<T> propertyPromise;
64         sdbusplus::asio::getProperty<T>(
65             *DbusEnvironment::getBus(), DbusEnvironment::serviceName(),
66             ReportManager::reportManagerPath,
67             ReportManager::reportManagerIfaceName, property,
68             [&propertyPromise](boost::system::error_code ec) {
69                 EXPECT_THAT(static_cast<bool>(ec), ::testing::Eq(false));
70                 propertyPromise.set_value(T{});
71             },
72             [&propertyPromise](T t) { propertyPromise.set_value(t); });
73         return DbusEnvironment::waitForFuture(propertyPromise.get_future());
74     }
75 };
76 
77 TEST_F(TestReportManager, minInterval)
78 {
79     EXPECT_THAT(getProperty<uint64_t>("MinInterval"),
80                 Eq(static_cast<uint64_t>(ReportManager::minInterval.count())));
81 }
82 
83 TEST_F(TestReportManager, maxReports)
84 {
85     EXPECT_THAT(getProperty<uint32_t>("MaxReports"),
86                 Eq(ReportManager::maxReports));
87 }
88 
89 TEST_F(TestReportManager, addReport)
90 {
91     auto reportMockPtr =
92         std::make_unique<NiceMock<ReportMock>>(reportParams.reportName());
93     auto& reportMock = *reportMockPtr;
94 
95     EXPECT_CALL(reportFactoryMock,
96                 make(_, reportParams.reportName(), reportParams.reportingType(),
97                      reportParams.emitReadingUpdate(),
98                      reportParams.logToMetricReportCollection(),
99                      reportParams.interval(), reportParams.readingParameters(),
100                      Ref(*sut), Ref(storageMock)))
101         .WillOnce(Return(ByMove(std::move(reportMockPtr))));
102 
103     auto [ec, path] = addReport(reportParams);
104     EXPECT_THAT(ec.value(), Eq(boost::system::errc::success));
105     EXPECT_THAT(path, Eq(reportMock.getPath()));
106 }
107 
108 TEST_F(TestReportManager, DISABLED_failToAddReportTwice)
109 {
110     EXPECT_CALL(reportFactoryMock, make(_, _, _, _, _, _, _, _, _));
111 
112     addReport(reportParams);
113 
114     auto [ec, path] = addReport(reportParams);
115     EXPECT_THAT(ec.value(), Eq(boost::system::errc::file_exists));
116     EXPECT_THAT(path, Eq(std::string()));
117 }
118 
119 TEST_F(TestReportManager, DISABLED_failToAddReportWithInvalidInterval)
120 {
121     EXPECT_CALL(reportFactoryMock, make).Times(0);
122 
123     reportParams.interval(reportParams.interval() - 1ms);
124 
125     auto [ec, path] = addReport(reportParams);
126     EXPECT_THAT(ec.value(), Eq(boost::system::errc::invalid_argument));
127     EXPECT_THAT(path, Eq(std::string()));
128 }
129 
130 TEST_F(TestReportManager, DISABLED_failToAddReportWhenMaxReportIsReached)
131 {
132     EXPECT_CALL(reportFactoryMock, make(_, _, _, _, _, _, _, _, _))
133         .Times(ReportManager::maxReports);
134 
135     for (size_t i = 0; i < ReportManager::maxReports; i++)
136     {
137         reportParams.reportName(reportParams.reportName() + std::to_string(i));
138 
139         auto [ec, path] = addReport(reportParams);
140         EXPECT_THAT(ec.value(), Eq(boost::system::errc::success));
141     }
142 
143     reportParams.reportName(reportParams.reportName() +
144                             std::to_string(ReportManager::maxReports));
145     auto [ec, path] = addReport(reportParams);
146     EXPECT_THAT(ec.value(), Eq(boost::system::errc::too_many_files_open));
147     EXPECT_THAT(path, Eq(std::string()));
148 }
149 
150 TEST_F(TestReportManager, removeReport)
151 {
152     auto reportMockPtr =
153         std::make_unique<NiceMock<ReportMock>>(reportParams.reportName());
154     auto& reportMock = *reportMockPtr;
155 
156     {
157         InSequence seq;
158         EXPECT_CALL(reportFactoryMock, make(_, _, _, _, _, _, _, _, _))
159             .WillOnce(Return(ByMove(std::move(reportMockPtr))));
160         EXPECT_CALL(reportMock, Die());
161         EXPECT_CALL(checkPoint, Call("end"));
162     }
163 
164     addReport(reportParams);
165     sut->removeReport(&reportMock);
166     checkPoint.Call("end");
167 }
168 
169 TEST_F(TestReportManager, removingReportThatIsNotInContainerHasNoEffect)
170 {
171     auto reportMockPtr =
172         std::make_unique<NiceMock<ReportMock>>(reportParams.reportName());
173     auto& reportMock = *reportMockPtr;
174 
175     {
176         InSequence seq;
177         EXPECT_CALL(checkPoint, Call("end"));
178         EXPECT_CALL(reportMock, Die());
179     }
180 
181     sut->removeReport(&reportMock);
182     checkPoint.Call("end");
183 }
184 
185 TEST_F(TestReportManager, removingSameReportTwiceHasNoSideEffect)
186 {
187     auto reportMockPtr =
188         std::make_unique<NiceMock<ReportMock>>(reportParams.reportName());
189     auto& reportMock = *reportMockPtr;
190 
191     {
192         InSequence seq;
193         EXPECT_CALL(reportFactoryMock,
194                     make(_, reportParams.reportName(), _, _, _, _, _, _, _))
195             .WillOnce(Return(ByMove(std::move(reportMockPtr))));
196         EXPECT_CALL(reportMock, Die());
197         EXPECT_CALL(checkPoint, Call("end"));
198     }
199 
200     addReport(reportParams);
201     sut->removeReport(&reportMock);
202     sut->removeReport(&reportMock);
203     checkPoint.Call("end");
204 }
205 
206 class TestReportManagerStorage : public TestReportManager
207 {
208   public:
209     using FilePath = interfaces::JsonStorage::FilePath;
210     using DirectoryPath = interfaces::JsonStorage::DirectoryPath;
211 
212     void SetUp() override
213     {
214         ON_CALL(storageMock, list())
215             .WillByDefault(Return(std::vector<FilePath>{FilePath("report1")}));
216         ON_CALL(storageMock, load(FilePath("report1")))
217             .WillByDefault(Return(data));
218     }
219 
220     void makeReportManager()
221     {
222         sut = std::make_unique<ReportManager>(std::move(reportFactoryMockPtr),
223                                               std::move(storageMockPtr),
224                                               DbusEnvironment::getObjServer());
225     }
226 
227     nlohmann::json data = nlohmann::json{
228         {"Version", Report::reportVersion},
229         {"Name", reportParams.reportName()},
230         {"ReportingType", reportParams.reportingType()},
231         {"EmitsReadingsUpdate", reportParams.emitReadingUpdate()},
232         {"LogToMetricReportsCollection",
233          reportParams.logToMetricReportCollection()},
234         {"Interval", reportParams.interval().count()},
235         {"ReadingParameters",
236          utils::transform(reportParams.readingParameters(),
237                           [](const auto& item) {
238                               return LabeledReadingParameter::to_json(item);
239                           })}};
240 };
241 
242 TEST_F(TestReportManagerStorage, reportManagerCtorAddReportFromStorage)
243 {
244     EXPECT_CALL(reportFactoryMock,
245                 make(_, reportParams.reportName(), reportParams.reportingType(),
246                      reportParams.emitReadingUpdate(),
247                      reportParams.logToMetricReportCollection(),
248                      reportParams.interval(), reportParams.readingParameters(),
249                      _, Ref(storageMock)));
250 
251     makeReportManager();
252 }
253 
254 TEST_F(TestReportManagerStorage,
255        reportManagerCtorRemoveFileIfVersionDoesNotMatch)
256 {
257     data["Version"] = Report::reportVersion - 1;
258 
259     ON_CALL(storageMock, load(FilePath("report1"))).WillByDefault(Return(data));
260     EXPECT_CALL(storageMock, remove(FilePath("report1")));
261 
262     makeReportManager();
263 }
264 
265 TEST_F(TestReportManagerStorage,
266        reportManagerCtorRemoveFileIfIntervalHasWrongType)
267 {
268     data["Interval"] = "1000";
269 
270     ON_CALL(storageMock, load(FilePath("report1"))).WillByDefault(Return(data));
271     EXPECT_CALL(storageMock, remove(FilePath("report1")));
272 
273     makeReportManager();
274 }
275