blob: 43a36c089fc7e971411662e1844593c78d9e4e97 [file] [log] [blame]
Szymon Dompkef763c9e2021-03-12 09:19:22 +01001#include "dbus_environment.hpp"
2#include "discrete_threshold.hpp"
3#include "helpers.hpp"
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +02004#include "mocks/clock_mock.hpp"
Szymon Dompkef763c9e2021-03-12 09:19:22 +01005#include "mocks/sensor_mock.hpp"
6#include "mocks/trigger_action_mock.hpp"
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +01007#include "types/duration_types.hpp"
Szymon Dompkef763c9e2021-03-12 09:19:22 +01008#include "utils/conv_container.hpp"
9
10#include <gmock/gmock.h>
11
12using namespace testing;
13using namespace std::chrono_literals;
14
15class TestDiscreteThreshold : public Test
16{
17 public:
18 std::vector<std::shared_ptr<SensorMock>> sensorMocks = {
19 std::make_shared<NiceMock<SensorMock>>(),
20 std::make_shared<NiceMock<SensorMock>>()};
21 std::vector<std::string> sensorNames = {"Sensor1", "Sensor2"};
22 std::unique_ptr<TriggerActionMock> actionMockPtr =
23 std::make_unique<StrictMock<TriggerActionMock>>();
24 TriggerActionMock& actionMock = *actionMockPtr;
25 std::shared_ptr<DiscreteThreshold> sut;
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +020026 std::string triggerId = "MyTrigger";
27 std::unique_ptr<NiceMock<ClockMock>> clockMockPtr =
28 std::make_unique<NiceMock<ClockMock>>();
Szymon Dompkef763c9e2021-03-12 09:19:22 +010029
Szymon Dompke94f71c52021-12-10 07:16:33 +010030 std::shared_ptr<DiscreteThreshold>
Szymon Dompkeaa572362022-03-23 16:31:24 +010031 makeThreshold(Milliseconds dwellTime, std::string thresholdValue,
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +020032 discrete::Severity severity = discrete::Severity::ok,
33 std::string thresholdName = "treshold name")
Szymon Dompkef763c9e2021-03-12 09:19:22 +010034 {
35 std::vector<std::unique_ptr<interfaces::TriggerAction>> actions;
36 actions.push_back(std::move(actionMockPtr));
37
38 return std::make_shared<DiscreteThreshold>(
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +020039 DbusEnvironment::getIoc(), triggerId,
Szymon Dompkef763c9e2021-03-12 09:19:22 +010040 utils::convContainer<std::shared_ptr<interfaces::Sensor>>(
41 sensorMocks),
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +020042 std::move(actions), dwellTime, thresholdValue, thresholdName,
43 severity, std::move(clockMockPtr));
Szymon Dompkef763c9e2021-03-12 09:19:22 +010044 }
45
46 void SetUp() override
47 {
Szymon Dompke94f71c52021-12-10 07:16:33 +010048 for (size_t idx = 0; idx < sensorMocks.size(); idx++)
49 {
50 ON_CALL(*sensorMocks.at(idx), getName())
51 .WillByDefault(Return(sensorNames[idx]));
52 }
53
Szymon Dompkeaa572362022-03-23 16:31:24 +010054 sut = makeThreshold(0ms, "90.0", discrete::Severity::critical);
Szymon Dompkef763c9e2021-03-12 09:19:22 +010055 }
56};
57
58TEST_F(TestDiscreteThreshold, initializeThresholdExpectAllSensorsAreRegistered)
59{
60 for (auto& sensor : sensorMocks)
61 {
62 EXPECT_CALL(*sensor,
63 registerForUpdates(Truly([sut = sut.get()](const auto& x) {
Patrick Williamsc7935fa2023-10-20 11:19:30 -050064 return x.lock().get() == sut;
65 })));
Szymon Dompkef763c9e2021-03-12 09:19:22 +010066 }
67
68 sut->initialize();
69}
70
71TEST_F(TestDiscreteThreshold, thresholdIsNotInitializeExpectNoActionCommit)
72{
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +020073 EXPECT_CALL(actionMock, commit(_, _, _, _, _)).Times(0);
Szymon Dompkef763c9e2021-03-12 09:19:22 +010074}
75
Szymon Dompkeaa572362022-03-23 16:31:24 +010076class TestDiscreteThresholdValues :
77 public TestDiscreteThreshold,
78 public WithParamInterface<std::string>
79{};
80
81INSTANTIATE_TEST_SUITE_P(_, TestDiscreteThresholdValues,
82 Values("90", ".90", "90.123", "0.0"));
83
84TEST_P(TestDiscreteThresholdValues, thresholdValueIsNumericAndStoredCorrectly)
Szymon Dompke94f71c52021-12-10 07:16:33 +010085{
Szymon Dompkeaa572362022-03-23 16:31:24 +010086 sut = makeThreshold(0ms, GetParam(), discrete::Severity::critical);
Szymon Dompke94f71c52021-12-10 07:16:33 +010087 LabeledThresholdParam expected = discrete::LabeledThresholdParam(
Szymon Dompkeaa572362022-03-23 16:31:24 +010088 "treshold name", discrete::Severity::critical, 0, GetParam());
Szymon Dompke94f71c52021-12-10 07:16:33 +010089 EXPECT_EQ(sut->getThresholdParam(), expected);
90}
91
Szymon Dompkeaa572362022-03-23 16:31:24 +010092class TestBadDiscreteThresholdValues :
93 public TestDiscreteThreshold,
94 public WithParamInterface<std::string>
95{};
96
97INSTANTIATE_TEST_SUITE_P(_, TestBadDiscreteThresholdValues,
98 Values("90ad", "ab.90", "x90", "On", "Off", ""));
99
100TEST_P(TestBadDiscreteThresholdValues, throwsWhenNotNumericValues)
101{
102 EXPECT_THROW(makeThreshold(0ms, GetParam()), std::invalid_argument);
103}
104
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +0200105class TestDiscreteThresholdInit : public TestDiscreteThreshold
106{
Patrick Williams3a1c2972023-05-10 07:51:04 -0500107 void SetUp() override {}
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +0200108};
109
110TEST_F(TestDiscreteThresholdInit, nonEmptyNameIsNotChanged)
111{
112 auto sut = makeThreshold(0ms, "12.3", discrete::Severity::ok, "non-empty");
113 EXPECT_THAT(
114 std::get<discrete::LabeledThresholdParam>(sut->getThresholdParam())
115 .at_label<utils::tstring::UserId>(),
116 Eq("non-empty"));
117}
118
119TEST_F(TestDiscreteThresholdInit, emptyNameIsChanged)
120{
121 auto sut = makeThreshold(0ms, "12.3", discrete::Severity::ok, "");
122 EXPECT_THAT(
123 std::get<discrete::LabeledThresholdParam>(sut->getThresholdParam())
124 .at_label<utils::tstring::UserId>(),
125 Not(Eq("")));
126}
127
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100128struct DiscreteParams
129{
130 struct UpdateParams
131 {
132 size_t sensor;
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100133 double value;
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000134 Milliseconds sleepAfter;
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100135
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +0200136 UpdateParams(size_t sensor, double value,
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000137 Milliseconds sleepAfter = 0ms) :
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100138 sensor(sensor),
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +0200139 value(value), sleepAfter(sleepAfter)
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100140 {}
141 };
142
143 struct ExpectedParams
144 {
145 size_t sensor;
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100146 double value;
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000147 Milliseconds waitMin;
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100148
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +0200149 ExpectedParams(size_t sensor, double value,
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000150 Milliseconds waitMin = 0ms) :
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100151 sensor(sensor),
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +0200152 value(value), waitMin(waitMin)
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100153 {}
154 };
155
156 DiscreteParams& Updates(std::vector<UpdateParams> val)
157 {
158 updates = std::move(val);
159 return *this;
160 }
161
162 DiscreteParams& Expected(std::vector<ExpectedParams> val)
163 {
164 expected = std::move(val);
165 return *this;
166 }
167
Szymon Dompkeaa572362022-03-23 16:31:24 +0100168 DiscreteParams& ThresholdValue(std::string val)
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100169 {
Szymon Dompkeaa572362022-03-23 16:31:24 +0100170 thresholdValue = std::move(val);
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100171 return *this;
172 }
173
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000174 DiscreteParams& DwellTime(Milliseconds val)
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100175 {
176 dwellTime = std::move(val);
177 return *this;
178 }
179
180 friend void PrintTo(const DiscreteParams& o, std::ostream* os)
181 {
182 *os << "{ DwellTime: " << o.dwellTime.count() << "ms ";
183 *os << ", ThresholdValue: " << o.thresholdValue;
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +0200184 *os << ", Updates: [ ";
185 for (const auto& [index, value, sleepAfter] : o.updates)
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100186 {
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +0200187 *os << "{ SensorIndex: " << index << ", Value: " << value
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100188 << ", SleepAfter: " << sleepAfter.count() << "ms }, ";
189 }
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +0200190 *os << " ] Expected: [ ";
191 for (const auto& [index, value, waitMin] : o.expected)
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100192 {
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +0200193 *os << "{ SensorIndex: " << index << ", Value: " << value
Krzysztof Grobelny51f0fd52021-12-28 16:32:08 +0100194 << ", waitMin: " << waitMin.count() << "ms }, ";
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100195 }
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +0200196 *os << " ] }";
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100197 }
198
199 std::vector<UpdateParams> updates;
200 std::vector<ExpectedParams> expected;
Szymon Dompkeaa572362022-03-23 16:31:24 +0100201 std::string thresholdValue = "0.0";
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000202 Milliseconds dwellTime = 0ms;
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100203};
204
205class TestDiscreteThresholdCommon :
206 public TestDiscreteThreshold,
207 public WithParamInterface<DiscreteParams>
208{
209 public:
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +0000210 void sleep(Milliseconds duration)
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100211 {
212 if (duration != 0ms)
213 {
214 DbusEnvironment::sleepFor(duration);
215 }
216 }
217
218 void testBodySensorIsUpdatedMultipleTimes()
219 {
220 std::vector<std::chrono::time_point<std::chrono::high_resolution_clock>>
221 timestamps(sensorMocks.size());
222
223 sut->initialize();
224
225 InSequence seq;
226
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +0200227 for (const auto& [index, value, waitMin] : GetParam().expected)
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100228 {
229 EXPECT_CALL(actionMock,
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +0200230 commit(triggerId, Optional(StrEq("treshold name")),
231 sensorNames[index], _,
232 TriggerValue(GetParam().thresholdValue)))
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100233 .WillOnce(DoAll(
234 InvokeWithoutArgs([idx = index, &timestamps] {
Patrick Williamsc7935fa2023-10-20 11:19:30 -0500235 timestamps[idx] = std::chrono::high_resolution_clock::now();
236 }),
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100237 InvokeWithoutArgs(DbusEnvironment::setPromise("commit"))));
238 }
239
240 auto start = std::chrono::high_resolution_clock::now();
241
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +0200242 for (const auto& [index, value, sleepAfter] : GetParam().updates)
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100243 {
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +0200244 sut->sensorUpdated(*sensorMocks[index], 42ms, value);
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100245 sleep(sleepAfter);
246 }
247
248 EXPECT_THAT(DbusEnvironment::waitForFutures("commit"), true);
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +0200249 for (const auto& [index, value, waitMin] : GetParam().expected)
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100250 {
251 EXPECT_THAT(timestamps[index] - start, Ge(waitMin));
252 }
253 }
254};
255
256class TestDiscreteThresholdNoDwellTime : public TestDiscreteThresholdCommon
257{
258 public:
259 void SetUp() override
260 {
Szymon Dompke94f71c52021-12-10 07:16:33 +0100261 for (size_t idx = 0; idx < sensorMocks.size(); idx++)
262 {
263 ON_CALL(*sensorMocks.at(idx), getName())
264 .WillByDefault(Return(sensorNames[idx]));
265 }
266
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100267 sut = makeThreshold(0ms, GetParam().thresholdValue);
268 }
269};
270
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +0200271INSTANTIATE_TEST_SUITE_P(
272 _, TestDiscreteThresholdNoDwellTime,
273 Values(DiscreteParams()
274 .ThresholdValue("90.0")
275 .Updates({{0, 80.0}, {0, 89.0}})
276 .Expected({}),
277 DiscreteParams()
278 .ThresholdValue("90.0")
279 .Updates({{0, 80.0}, {0, 90.0}, {0, 80.0}, {0, 90.0}})
280 .Expected({{0, 90.0}, {0, 90.0}}),
281 DiscreteParams()
282 .ThresholdValue("90.0")
283 .Updates({{0, 90.0}, {0, 99.0}, {1, 100.0}, {1, 90.0}})
284 .Expected({{0, 90.0}, {1, 90.0}})));
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100285
286TEST_P(TestDiscreteThresholdNoDwellTime, senorsIsUpdatedMultipleTimes)
287{
288 testBodySensorIsUpdatedMultipleTimes();
289}
290
291class TestDiscreteThresholdWithDwellTime : public TestDiscreteThresholdCommon
292{
293 public:
294 void SetUp() override
295 {
Szymon Dompke94f71c52021-12-10 07:16:33 +0100296 for (size_t idx = 0; idx < sensorMocks.size(); idx++)
297 {
298 ON_CALL(*sensorMocks.at(idx), getName())
299 .WillByDefault(Return(sensorNames[idx]));
300 }
301
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100302 sut = makeThreshold(GetParam().dwellTime, GetParam().thresholdValue);
303 }
304};
305
306INSTANTIATE_TEST_SUITE_P(
307 _, TestDiscreteThresholdWithDwellTime,
308 Values(DiscreteParams()
309 .DwellTime(200ms)
Szymon Dompkeaa572362022-03-23 16:31:24 +0100310 .ThresholdValue("90.0")
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +0200311 .Updates({{0, 90.0, 100ms}, {0, 91.0}, {0, 90.0}})
312 .Expected({{0, 90.0, 300ms}}),
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100313 DiscreteParams()
314 .DwellTime(100ms)
Szymon Dompkeaa572362022-03-23 16:31:24 +0100315 .ThresholdValue("90.0")
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +0200316 .Updates({{0, 90.0, 100ms}})
317 .Expected({{0, 90.0, 100ms}}),
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100318 DiscreteParams()
319 .DwellTime(1000ms)
Szymon Dompkeaa572362022-03-23 16:31:24 +0100320 .ThresholdValue("90.0")
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +0200321 .Updates({{0, 90.0, 700ms},
322 {0, 91.0, 100ms},
323 {0, 90.0, 300ms},
324 {0, 91.0, 100ms}})
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100325 .Expected({}),
326 DiscreteParams()
327 .DwellTime(200ms)
Szymon Dompkeaa572362022-03-23 16:31:24 +0100328 .ThresholdValue("90.0")
Szymon Dompkeb7b7e1b2022-05-19 10:15:48 +0200329 .Updates({{0, 90.0},
330 {1, 89.0, 100ms},
331 {1, 90.0, 100ms},
332 {1, 89.0, 100ms},
333 {1, 90.0, 300ms},
334 {1, 89.0, 100ms}})
335 .Expected({{0, 90, 200ms}, {1, 90, 500ms}})));
Szymon Dompkef763c9e2021-03-12 09:19:22 +0100336
337TEST_P(TestDiscreteThresholdWithDwellTime, senorsIsUpdatedMultipleTimes)
338{
339 testBodySensorIsUpdatedMultipleTimes();
340}