xref: /openbmc/telemetry/tests/src/test_trigger_manager.cpp (revision 2001301a0f2ce71797cf171305a1d0eb0d288fe6)
1 #include "dbus_environment.hpp"
2 #include "helpers.hpp"
3 #include "mocks/json_storage_mock.hpp"
4 #include "mocks/trigger_factory_mock.hpp"
5 #include "mocks/trigger_mock.hpp"
6 #include "params/trigger_params.hpp"
7 #include "trigger.hpp"
8 #include "trigger_manager.hpp"
9 #include "utils/conversion_trigger.hpp"
10 #include "utils/transform.hpp"
11 
12 using namespace testing;
13 
14 class TestTriggerManager : public Test
15 {
16   public:
17     std::pair<boost::system::error_code, std::string>
18         addTrigger(const TriggerParams& params)
19     {
20         const auto sensorInfos =
21             utils::fromLabeledSensorsInfo(params.sensors());
22 
23         std::promise<std::pair<boost::system::error_code, std::string>>
24             addTriggerPromise;
25         DbusEnvironment::getBus()->async_method_call(
26             [&addTriggerPromise](boost::system::error_code ec,
27                                  const std::string& path) {
28                 addTriggerPromise.set_value({ec, path});
29             },
30             DbusEnvironment::serviceName(), TriggerManager::triggerManagerPath,
31             TriggerManager::triggerManagerIfaceName, "AddTrigger",
32             params.name(), params.triggerActions(), sensorInfos,
33             params.reportNames(),
34             std::visit(utils::FromLabeledThresholdParamConversion(),
35                        params.thresholdParams()));
36         return DbusEnvironment::waitForFuture(addTriggerPromise.get_future());
37     }
38 
39     std::unique_ptr<TriggerManager> makeTriggerManager()
40     {
41         return std::make_unique<TriggerManager>(
42             std::move(triggerFactoryMockPtr), std::move(storageMockPtr),
43             DbusEnvironment::getObjServer());
44     }
45 
46     void SetUp() override
47     {
48         sut = makeTriggerManager();
49     }
50 
51     std::unique_ptr<StorageMock> storageMockPtr =
52         std::make_unique<NiceMock<StorageMock>>();
53     StorageMock& storageMock = *storageMockPtr;
54     std::unique_ptr<TriggerFactoryMock> triggerFactoryMockPtr =
55         std::make_unique<NiceMock<TriggerFactoryMock>>();
56     TriggerFactoryMock& triggerFactoryMock = *triggerFactoryMockPtr;
57     std::unique_ptr<TriggerMock> triggerMockPtr =
58         std::make_unique<NiceMock<TriggerMock>>(TriggerParams().name());
59     TriggerMock& triggerMock = *triggerMockPtr;
60     std::unique_ptr<TriggerManager> sut;
61     MockFunction<void(std::string)> checkPoint;
62 };
63 
64 TEST_F(TestTriggerManager, addTrigger)
65 {
66     triggerFactoryMock.expectMake(TriggerParams(), Ref(*sut), Ref(storageMock))
67         .WillOnce(Return(ByMove(std::move(triggerMockPtr))));
68 
69     auto [ec, path] = addTrigger(TriggerParams());
70     EXPECT_THAT(ec.value(), Eq(boost::system::errc::success));
71     EXPECT_THAT(path, Eq(triggerMock.getPath()));
72 }
73 
74 TEST_F(TestTriggerManager, addTriggerWithDiscreteThresholds)
75 {
76     TriggerParams triggerParamsDiscrete;
77     auto thresholds = std::vector<discrete::LabeledThresholdParam>{
78         {"discrete_threshold1", discrete::Severity::ok, 10, "11.0"},
79         {"discrete_threshold2", discrete::Severity::warning, 10, "12.0"},
80         {"discrete_threshold3", discrete::Severity::critical, 10, "13.0"}};
81 
82     triggerParamsDiscrete.thresholdParams(thresholds);
83 
84     auto [ec, path] = addTrigger(triggerParamsDiscrete);
85     EXPECT_THAT(ec.value(), Eq(boost::system::errc::success));
86     EXPECT_THAT(path, Eq(triggerMock.getPath()));
87 }
88 
89 TEST_F(TestTriggerManager, addDiscreteTriggerWithoutThresholds)
90 {
91     TriggerParams triggerParamsDiscrete;
92     auto thresholds = std::vector<discrete::LabeledThresholdParam>();
93 
94     triggerParamsDiscrete.thresholdParams(thresholds);
95 
96     auto [ec, path] = addTrigger(triggerParamsDiscrete);
97     EXPECT_THAT(ec.value(), Eq(boost::system::errc::success));
98     EXPECT_THAT(path, Eq(triggerMock.getPath()));
99 }
100 
101 TEST_F(TestTriggerManager, DISABLED_failToAddTriggerTwice)
102 {
103     triggerFactoryMock.expectMake(TriggerParams(), Ref(*sut), Ref(storageMock))
104         .WillOnce(Return(ByMove(std::move(triggerMockPtr))));
105 
106     addTrigger(TriggerParams());
107 
108     auto [ec, path] = addTrigger(TriggerParams());
109     EXPECT_THAT(ec.value(), Eq(boost::system::errc::file_exists));
110     EXPECT_THAT(path, Eq(std::string()));
111 }
112 
113 TEST_F(TestTriggerManager, DISABLED_failToAddTriggerWhenMaxTriggerIsReached)
114 {
115     auto triggerParams = TriggerParams();
116 
117     triggerFactoryMock.expectMake(std::nullopt, Ref(*sut), Ref(storageMock))
118         .Times(TriggerManager::maxTriggers);
119 
120     for (size_t i = 0; i < TriggerManager::maxTriggers; i++)
121     {
122         triggerParams.name(TriggerParams().name() + std::to_string(i));
123 
124         auto [ec, path] = addTrigger(triggerParams);
125         EXPECT_THAT(ec.value(), Eq(boost::system::errc::success));
126     }
127 
128     triggerParams.name(TriggerParams().name() +
129                        std::to_string(TriggerManager::maxTriggers));
130     auto [ec, path] = addTrigger(triggerParams);
131     EXPECT_THAT(ec.value(), Eq(boost::system::errc::too_many_files_open));
132     EXPECT_THAT(path, Eq(std::string()));
133 }
134 
135 TEST_F(TestTriggerManager, removeTrigger)
136 {
137     {
138         InSequence seq;
139         triggerFactoryMock
140             .expectMake(TriggerParams(), Ref(*sut), Ref(storageMock))
141             .WillOnce(Return(ByMove(std::move(triggerMockPtr))));
142         EXPECT_CALL(triggerMock, Die());
143         EXPECT_CALL(checkPoint, Call("end"));
144     }
145 
146     addTrigger(TriggerParams());
147     sut->removeTrigger(&triggerMock);
148     checkPoint.Call("end");
149 }
150 
151 TEST_F(TestTriggerManager, removingTriggerThatIsNotInContainerHasNoEffect)
152 {
153     {
154         InSequence seq;
155         EXPECT_CALL(checkPoint, Call("end"));
156         EXPECT_CALL(triggerMock, Die());
157     }
158 
159     sut->removeTrigger(&triggerMock);
160     checkPoint.Call("end");
161 }
162 
163 TEST_F(TestTriggerManager, removingSameTriggerTwiceHasNoSideEffect)
164 {
165     {
166         InSequence seq;
167         triggerFactoryMock
168             .expectMake(TriggerParams(), Ref(*sut), Ref(storageMock))
169             .WillOnce(Return(ByMove(std::move(triggerMockPtr))));
170         EXPECT_CALL(triggerMock, Die());
171         EXPECT_CALL(checkPoint, Call("end"));
172     }
173 
174     addTrigger(TriggerParams());
175     sut->removeTrigger(&triggerMock);
176     sut->removeTrigger(&triggerMock);
177     checkPoint.Call("end");
178 }
179 
180 class TestTriggerManagerStorage : public TestTriggerManager
181 {
182   public:
183     using FilePath = interfaces::JsonStorage::FilePath;
184     using DirectoryPath = interfaces::JsonStorage::DirectoryPath;
185 
186     void SetUp() override
187     {
188         ON_CALL(storageMock, list())
189             .WillByDefault(Return(std::vector<FilePath>{
190                 {FilePath("trigger1")}, {FilePath("trigger2")}}));
191 
192         ON_CALL(storageMock, load(FilePath("trigger1")))
193             .WillByDefault(InvokeWithoutArgs([this] { return data1; }));
194 
195         data2["Name"] = "Trigger2";
196         ON_CALL(storageMock, load(FilePath("trigger2")))
197             .WillByDefault(InvokeWithoutArgs([this] { return data2; }));
198     }
199 
200     nlohmann::json data1 = nlohmann::json{
201         {"Version", Trigger::triggerVersion},
202         {"Name", TriggerParams().name()},
203         {"ThresholdParamsDiscriminator",
204          TriggerParams().thresholdParams().index()},
205         {"TriggerActions", TriggerParams().triggerActions()},
206         {"ThresholdParams", utils::labeledThresholdParamsToJson(
207                                 TriggerParams().thresholdParams())},
208         {"ReportNames", TriggerParams().reportNames()},
209         {"Sensors", TriggerParams().sensors()}};
210 
211     nlohmann::json data2 = data1;
212 };
213 
214 TEST_F(TestTriggerManagerStorage, triggerManagerCtorAddTriggerFromStorage)
215 {
216     triggerFactoryMock.expectMake(TriggerParams(), _, Ref(storageMock));
217     triggerFactoryMock.expectMake(TriggerParams().name("Trigger2"), _,
218                                   Ref(storageMock));
219     EXPECT_CALL(storageMock, remove(_)).Times(0);
220 
221     sut = makeTriggerManager();
222 }
223 
224 TEST_F(TestTriggerManagerStorage,
225        triggerManagerCtorRemoveDiscreteTriggerFromStorage)
226 {
227     LabeledTriggerThresholdParams thresholdParams =
228         std::vector<discrete::LabeledThresholdParam>{
229             {"userId1", discrete::Severity::warning, 15, "10.0"},
230             {"userId2", discrete::Severity::critical, 5, "20.0"}};
231 
232     data1["ThresholdParamsDiscriminator"] = thresholdParams.index();
233 
234     data1["ThresholdParams"] =
235         utils::labeledThresholdParamsToJson(thresholdParams);
236 
237     EXPECT_CALL(storageMock, remove(FilePath("trigger1"))).Times(0);
238 
239     sut = makeTriggerManager();
240 }
241 
242 TEST_F(TestTriggerManagerStorage,
243        triggerManagerCtorRemoveDiscreteTriggerFromStorage2)
244 {
245     data1["IsDiscrete"] = true;
246 
247     EXPECT_CALL(storageMock, remove(FilePath("trigger1"))).Times(0);
248 
249     sut = makeTriggerManager();
250 }
251 
252 TEST_F(TestTriggerManagerStorage,
253        triggerManagerCtorAddProperRemoveInvalidTriggerFromStorage)
254 {
255     data1["Version"] = Trigger::triggerVersion - 1;
256 
257     triggerFactoryMock.expectMake(TriggerParams().name("Trigger2"), _,
258                                   Ref(storageMock));
259     EXPECT_CALL(storageMock, remove(FilePath("trigger1")));
260 
261     sut = makeTriggerManager();
262 }
263