blob: 2b31767e5e902e7f8e215a295b1be1694348474b [file] [log] [blame]
Szymon Dompkef763c9e2021-03-12 09:19:22 +01001#include "dbus_environment.hpp"
2#include "discrete_threshold.hpp"
3#include "helpers.hpp"
4#include "mocks/sensor_mock.hpp"
5#include "mocks/trigger_action_mock.hpp"
6#include "utils/conv_container.hpp"
7
8#include <gmock/gmock.h>
9
10using namespace testing;
11using namespace std::chrono_literals;
12
13class TestDiscreteThreshold : public Test
14{
15 public:
16 std::vector<std::shared_ptr<SensorMock>> sensorMocks = {
17 std::make_shared<NiceMock<SensorMock>>(),
18 std::make_shared<NiceMock<SensorMock>>()};
19 std::vector<std::string> sensorNames = {"Sensor1", "Sensor2"};
20 std::unique_ptr<TriggerActionMock> actionMockPtr =
21 std::make_unique<StrictMock<TriggerActionMock>>();
22 TriggerActionMock& actionMock = *actionMockPtr;
23 std::shared_ptr<DiscreteThreshold> sut;
24
25 std::shared_ptr<DiscreteThreshold>
26 makeThreshold(std::chrono::milliseconds dwellTime,
27 double thresholdValue)
28 {
29 std::vector<std::unique_ptr<interfaces::TriggerAction>> actions;
30 actions.push_back(std::move(actionMockPtr));
31
32 return std::make_shared<DiscreteThreshold>(
33 DbusEnvironment::getIoc(),
34 utils::convContainer<std::shared_ptr<interfaces::Sensor>>(
35 sensorMocks),
36 sensorNames, std::move(actions), dwellTime, thresholdValue,
37 "treshold_name");
38 }
39
40 void SetUp() override
41 {
42 sut = makeThreshold(0ms, 90.0);
43 }
44};
45
46TEST_F(TestDiscreteThreshold, initializeThresholdExpectAllSensorsAreRegistered)
47{
48 for (auto& sensor : sensorMocks)
49 {
50 EXPECT_CALL(*sensor,
51 registerForUpdates(Truly([sut = sut.get()](const auto& x) {
52 return x.lock().get() == sut;
53 })));
54 }
55
56 sut->initialize();
57}
58
59TEST_F(TestDiscreteThreshold, thresholdIsNotInitializeExpectNoActionCommit)
60{
61 EXPECT_CALL(actionMock, commit(_, _, _)).Times(0);
62}
63
64struct DiscreteParams
65{
66 struct UpdateParams
67 {
68 size_t sensor;
69 uint64_t timestamp;
70 double value;
71 std::chrono::milliseconds sleepAfter;
72
73 UpdateParams(size_t sensor, uint64_t timestamp, double value,
74 std::chrono::milliseconds sleepAfter = 0ms) :
75 sensor(sensor),
76 timestamp(timestamp), value(value), sleepAfter(sleepAfter)
77 {}
78 };
79
80 struct ExpectedParams
81 {
82 size_t sensor;
83 uint64_t timestamp;
84 double value;
85 std::chrono::milliseconds waitMin;
86
87 ExpectedParams(size_t sensor, uint64_t timestamp, double value,
88 std::chrono::milliseconds waitMin = 0ms) :
89 sensor(sensor),
90 timestamp(timestamp), value(value), waitMin(waitMin)
91 {}
92 };
93
94 DiscreteParams& Updates(std::vector<UpdateParams> val)
95 {
96 updates = std::move(val);
97 return *this;
98 }
99
100 DiscreteParams& Expected(std::vector<ExpectedParams> val)
101 {
102 expected = std::move(val);
103 return *this;
104 }
105
106 DiscreteParams& ThresholdValue(double val)
107 {
108 thresholdValue = val;
109 return *this;
110 }
111
112 DiscreteParams& DwellTime(std::chrono::milliseconds val)
113 {
114 dwellTime = std::move(val);
115 return *this;
116 }
117
118 friend void PrintTo(const DiscreteParams& o, std::ostream* os)
119 {
120 *os << "{ DwellTime: " << o.dwellTime.count() << "ms ";
121 *os << ", ThresholdValue: " << o.thresholdValue;
122 *os << ", Updates: ";
123 for (const auto& [index, timestamp, value, sleepAfter] : o.updates)
124 {
125 *os << "{ SensorIndex: " << index << ", Timestamp: " << timestamp
126 << ", Value: " << value
127 << ", SleepAfter: " << sleepAfter.count() << "ms }, ";
128 }
129 *os << "Expected: ";
130 for (const auto& [index, timestamp, value, waitMin] : o.expected)
131 {
132 *os << "{ SensorIndex: " << index << ", Timestamp: " << timestamp
133 << ", Value: " << value << ", waitMin: " << waitMin.count()
134 << "ms }, ";
135 }
136 *os << " }";
137 }
138
139 std::vector<UpdateParams> updates;
140 std::vector<ExpectedParams> expected;
141 double thresholdValue = 0.0;
142 std::chrono::milliseconds dwellTime = 0ms;
143};
144
145class TestDiscreteThresholdCommon :
146 public TestDiscreteThreshold,
147 public WithParamInterface<DiscreteParams>
148{
149 public:
150 void sleep(std::chrono::milliseconds duration)
151 {
152 if (duration != 0ms)
153 {
154 DbusEnvironment::sleepFor(duration);
155 }
156 }
157
158 void testBodySensorIsUpdatedMultipleTimes()
159 {
160 std::vector<std::chrono::time_point<std::chrono::high_resolution_clock>>
161 timestamps(sensorMocks.size());
162
163 sut->initialize();
164
165 InSequence seq;
166
167 for (const auto& [index, timestamp, value, waitMin] :
168 GetParam().expected)
169 {
170 EXPECT_CALL(actionMock,
171 commit(sensorNames[index], timestamp, value))
172 .WillOnce(DoAll(
173 InvokeWithoutArgs([idx = index, &timestamps] {
174 timestamps[idx] =
175 std::chrono::high_resolution_clock::now();
176 }),
177 InvokeWithoutArgs(DbusEnvironment::setPromise("commit"))));
178 }
179
180 auto start = std::chrono::high_resolution_clock::now();
181
182 for (const auto& [index, timestamp, value, sleepAfter] :
183 GetParam().updates)
184 {
185 sut->sensorUpdated(*sensorMocks[index], timestamp, value);
186 sleep(sleepAfter);
187 }
188
189 EXPECT_THAT(DbusEnvironment::waitForFutures("commit"), true);
190 for (const auto& [index, timestamp, value, waitMin] :
191 GetParam().expected)
192 {
193 EXPECT_THAT(timestamps[index] - start, Ge(waitMin));
194 }
195 }
196};
197
198class TestDiscreteThresholdNoDwellTime : public TestDiscreteThresholdCommon
199{
200 public:
201 void SetUp() override
202 {
203 sut = makeThreshold(0ms, GetParam().thresholdValue);
204 }
205};
206
207INSTANTIATE_TEST_SUITE_P(
208 _, TestDiscreteThresholdNoDwellTime,
209 Values(
210 DiscreteParams()
211 .ThresholdValue(90.0)
212 .Updates({{0, 1, 80.0}, {0, 2, 89.0}})
213 .Expected({}),
214 DiscreteParams()
215 .ThresholdValue(90.0)
216 .Updates({{0, 1, 80.0}, {0, 2, 90.0}, {0, 3, 80.0}, {0, 4, 90.0}})
217 .Expected({{0, 2, 90.0}, {0, 4, 90.0}}),
218 DiscreteParams()
219 .ThresholdValue(90.0)
220 .Updates({{0, 1, 90.0}, {0, 2, 99.0}, {1, 3, 100.0}, {1, 4, 90.0}})
221 .Expected({{0, 1, 90.0}, {1, 4, 90.0}})));
222
223TEST_P(TestDiscreteThresholdNoDwellTime, senorsIsUpdatedMultipleTimes)
224{
225 testBodySensorIsUpdatedMultipleTimes();
226}
227
228class TestDiscreteThresholdWithDwellTime : public TestDiscreteThresholdCommon
229{
230 public:
231 void SetUp() override
232 {
233 sut = makeThreshold(GetParam().dwellTime, GetParam().thresholdValue);
234 }
235};
236
237INSTANTIATE_TEST_SUITE_P(
238 _, TestDiscreteThresholdWithDwellTime,
239 Values(DiscreteParams()
240 .DwellTime(200ms)
241 .ThresholdValue(90.0)
242 .Updates({{0, 1, 90.0, 100ms}, {0, 2, 91.0}, {0, 3, 90.0}})
243 .Expected({{0, 3, 90.0, 300ms}}),
244 DiscreteParams()
245 .DwellTime(100ms)
246 .ThresholdValue(90.0)
247 .Updates({{0, 1, 90.0, 100ms}})
248 .Expected({{0, 1, 90.0, 100ms}}),
249 DiscreteParams()
250 .DwellTime(1000ms)
251 .ThresholdValue(90.0)
252 .Updates({{0, 1, 90.0, 700ms},
253 {0, 1, 91.0, 100ms},
254 {0, 1, 90.0, 300ms},
255 {0, 1, 91.0, 100ms}})
256 .Expected({}),
257 DiscreteParams()
258 .DwellTime(200ms)
259 .ThresholdValue(90.0)
260 .Updates({{0, 1, 90.0},
261 {1, 2, 89.0, 100ms},
262 {1, 3, 90.0, 100ms},
263 {1, 4, 89.0, 100ms},
264 {1, 5, 90.0, 300ms},
265 {1, 6, 89.0, 100ms}})
266 .Expected({{0, 1, 90, 200ms}, {1, 5, 90, 500ms}})));
267
268TEST_P(TestDiscreteThresholdWithDwellTime, senorsIsUpdatedMultipleTimes)
269{
270 testBodySensorIsUpdatedMultipleTimes();
271}