1 #include "dbus_environment.hpp" 2 #include "helpers.hpp" 3 #include "mocks/sensor_mock.hpp" 4 #include "mocks/trigger_action_mock.hpp" 5 #include "numeric_threshold.hpp" 6 #include "utils/conv_container.hpp" 7 8 #include <gmock/gmock.h> 9 10 using namespace testing; 11 using namespace std::chrono_literals; 12 13 class TestNumericThreshold : 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<NumericThreshold> sut; 24 25 void makeThreshold(Milliseconds dwellTime, numeric::Direction direction, 26 double thresholdValue) 27 { 28 std::vector<std::unique_ptr<interfaces::TriggerAction>> actions; 29 actions.push_back(std::move(actionMockPtr)); 30 31 sut = std::make_shared<NumericThreshold>( 32 DbusEnvironment::getIoc(), 33 utils::convContainer<std::shared_ptr<interfaces::Sensor>>( 34 sensorMocks), 35 sensorNames, std::move(actions), dwellTime, direction, 36 thresholdValue); 37 } 38 39 void SetUp() override 40 { 41 makeThreshold(0ms, numeric::Direction::increasing, 90.0); 42 } 43 }; 44 45 TEST_F(TestNumericThreshold, initializeThresholdExpectAllSensorsAreRegistered) 46 { 47 for (auto& sensor : sensorMocks) 48 { 49 EXPECT_CALL(*sensor, 50 registerForUpdates(Truly([sut = sut.get()](const auto& x) { 51 return x.lock().get() == sut; 52 }))); 53 } 54 55 sut->initialize(); 56 } 57 58 TEST_F(TestNumericThreshold, thresholdIsNotInitializeExpectNoActionCommit) 59 { 60 EXPECT_CALL(actionMock, commit(_, _, _)).Times(0); 61 } 62 63 struct NumericParams 64 { 65 NumericParams& Direction(numeric::Direction val) 66 { 67 direction = val; 68 return *this; 69 } 70 71 NumericParams& 72 Updates(std::vector<std::tuple<size_t, Milliseconds, double>> val) 73 { 74 updates = std::move(val); 75 return *this; 76 } 77 78 NumericParams& 79 Expected(std::vector<std::tuple<size_t, Milliseconds, double>> val) 80 { 81 expected = std::move(val); 82 return *this; 83 } 84 85 friend void PrintTo(const NumericParams& o, std::ostream* os) 86 { 87 *os << "{ Direction: " << static_cast<int>(o.direction) 88 << ", Updates: "; 89 for (const auto& [index, timestamp, value] : o.updates) 90 { 91 *os << "{ SensorIndex: " << index 92 << ", Timestamp: " << timestamp.count() << ", Value: " << value 93 << " }, "; 94 } 95 *os << "Expected: "; 96 for (const auto& [index, timestamp, value] : o.expected) 97 { 98 *os << "{ SensorIndex: " << index 99 << ", Timestamp: " << timestamp.count() << ", Value: " << value 100 << " }, "; 101 } 102 *os << " }"; 103 } 104 105 numeric::Direction direction; 106 std::vector<std::tuple<size_t, Milliseconds, double>> updates; 107 std::vector<std::tuple<size_t, Milliseconds, double>> expected; 108 }; 109 110 class TestNumericThresholdNoDwellTime : 111 public TestNumericThreshold, 112 public WithParamInterface<NumericParams> 113 { 114 public: 115 void SetUp() override 116 { 117 makeThreshold(0ms, GetParam().direction, 90.0); 118 } 119 }; 120 121 INSTANTIATE_TEST_SUITE_P(_, TestNumericThresholdNoDwellTime, 122 Values(NumericParams() 123 .Direction(numeric::Direction::increasing) 124 .Updates({{0, 1ms, 80.0}, {0, 2ms, 89.0}}) 125 .Expected({}), 126 NumericParams() 127 .Direction(numeric::Direction::increasing) 128 .Updates({{0, 1ms, 80.0}, {0, 2ms, 91.0}}) 129 .Expected({{0, 2ms, 91.0}}), 130 NumericParams() 131 .Direction(numeric::Direction::increasing) 132 .Updates({{0, 1ms, 80.0}, 133 {0, 2ms, 99.0}, 134 {0, 3ms, 80.0}, 135 {0, 4ms, 98.0}}) 136 .Expected({{0, 2ms, 99.0}, {0, 4ms, 98.0}}), 137 NumericParams() 138 .Direction(numeric::Direction::increasing) 139 .Updates({{0, 1ms, 80.0}, 140 {0, 2ms, 99.0}, 141 {1, 3ms, 100.0}, 142 {1, 4ms, 98.0}}) 143 .Expected({{0, 2ms, 99.0}}), 144 NumericParams() 145 .Direction(numeric::Direction::decreasing) 146 .Updates({{0, 1ms, 100.0}, {0, 2ms, 91.0}}) 147 .Expected({}), 148 NumericParams() 149 .Direction(numeric::Direction::decreasing) 150 .Updates({{0, 1ms, 100.0}, {0, 2ms, 80.0}}) 151 .Expected({{0, 2ms, 80.0}}), 152 NumericParams() 153 .Direction(numeric::Direction::decreasing) 154 .Updates({{0, 1ms, 100.0}, 155 {0, 2ms, 80.0}, 156 {0, 3ms, 99.0}, 157 {0, 4ms, 85.0}}) 158 .Expected({{0, 2ms, 80.0}, {0, 4ms, 85.0}}), 159 NumericParams() 160 .Direction(numeric::Direction::decreasing) 161 .Updates({{0, 1ms, 100.0}, 162 {0, 2ms, 80.0}, 163 {1, 3ms, 99.0}, 164 {1, 4ms, 88.0}}) 165 .Expected({{0, 2ms, 80.0}, {1, 4ms, 88.0}}), 166 NumericParams() 167 .Direction(numeric::Direction::either) 168 .Updates({{0, 1ms, 98.0}, {0, 2ms, 91.0}}) 169 .Expected({}), 170 NumericParams() 171 .Direction(numeric::Direction::either) 172 .Updates({{0, 1ms, 100.0}, 173 {0, 2ms, 80.0}, 174 {0, 3ms, 85.0}, 175 {0, 4ms, 91.0}}) 176 .Expected({{0, 2ms, 80.0}, {0, 4ms, 91.0}}), 177 NumericParams() 178 .Direction(numeric::Direction::either) 179 .Updates({{0, 1ms, 100.0}, 180 {1, 2ms, 80.0}, 181 {0, 3ms, 85.0}, 182 {1, 4ms, 91.0}}) 183 .Expected({{0, 3ms, 85.0}, 184 {1, 4ms, 91.0}}))); 185 186 TEST_P(TestNumericThresholdNoDwellTime, senorsIsUpdatedMultipleTimes) 187 { 188 InSequence seq; 189 for (const auto& [index, timestamp, value] : GetParam().expected) 190 { 191 EXPECT_CALL(actionMock, commit(sensorNames[index], timestamp, value)); 192 } 193 194 sut->initialize(); 195 for (const auto& [index, timestamp, value] : GetParam().updates) 196 { 197 sut->sensorUpdated(*sensorMocks[index], timestamp, value); 198 } 199 } 200 201 class TestNumericThresholdWithDwellTime : 202 public TestNumericThreshold, 203 public WithParamInterface<NumericParams> 204 { 205 public: 206 void SetUp() override 207 { 208 makeThreshold(2ms, GetParam().direction, 90.0); 209 } 210 211 void sleep() 212 { 213 DbusEnvironment::sleepFor(4ms); 214 } 215 }; 216 217 INSTANTIATE_TEST_SUITE_P(_, TestNumericThresholdWithDwellTime, 218 Values(NumericParams() 219 .Direction(numeric::Direction::increasing) 220 .Updates({{0, 1ms, 80.0}, {0, 2ms, 89.0}}) 221 .Expected({}), 222 NumericParams() 223 .Direction(numeric::Direction::increasing) 224 .Updates({{0, 1ms, 80.0}, {0, 2ms, 91.0}}) 225 .Expected({{0, 2ms, 91.0}}), 226 NumericParams() 227 .Direction(numeric::Direction::increasing) 228 .Updates({{0, 1ms, 80.0}, 229 {0, 2ms, 99.0}, 230 {0, 3ms, 80.0}, 231 {0, 4ms, 98.0}}) 232 .Expected({{0, 2ms, 99.0}, {0, 4ms, 98.0}}), 233 NumericParams() 234 .Direction(numeric::Direction::increasing) 235 .Updates({{0, 1ms, 80.0}, 236 {1, 2ms, 99.0}, 237 {0, 3ms, 100.0}, 238 {1, 4ms, 86.0}}) 239 .Expected({{0, 3ms, 100.0}}), 240 NumericParams() 241 .Direction(numeric::Direction::decreasing) 242 .Updates({{0, 1ms, 100.0}, {0, 2ms, 91.0}}) 243 .Expected({}), 244 NumericParams() 245 .Direction(numeric::Direction::decreasing) 246 .Updates({{0, 1ms, 100.0}, {0, 2ms, 80.0}}) 247 .Expected({{0, 2ms, 80.0}}), 248 NumericParams() 249 .Direction(numeric::Direction::decreasing) 250 .Updates({{0, 1ms, 100.0}, 251 {0, 2ms, 80.0}, 252 {0, 3ms, 99.0}, 253 {0, 4ms, 85.0}}) 254 .Expected({{0, 2ms, 80.0}, {0, 4ms, 85.0}}), 255 NumericParams() 256 .Direction(numeric::Direction::decreasing) 257 .Updates({{0, 1ms, 100.0}, 258 {0, 2ms, 80.0}, 259 {1, 3ms, 99.0}, 260 {1, 4ms, 88.0}}) 261 .Expected({{0, 2ms, 80.0}, {1, 4ms, 88.0}}), 262 NumericParams() 263 .Direction(numeric::Direction::either) 264 .Updates({{0, 1ms, 98.0}, {0, 2ms, 91.0}}) 265 .Expected({}), 266 NumericParams() 267 .Direction(numeric::Direction::either) 268 .Updates({{0, 1ms, 100.0}, 269 {0, 2ms, 80.0}, 270 {0, 3ms, 85.0}, 271 {0, 4ms, 91.0}}) 272 .Expected({{0, 2ms, 80.0}, {0, 4ms, 91.0}}), 273 NumericParams() 274 .Direction(numeric::Direction::either) 275 .Updates({{0, 1ms, 100.0}, 276 {1, 2ms, 80.0}, 277 {0, 3ms, 85.0}, 278 {1, 4ms, 91.0}}) 279 .Expected({{0, 3ms, 85.0}, 280 {1, 4ms, 91.0}}))); 281 282 TEST_P(TestNumericThresholdWithDwellTime, 283 senorsIsUpdatedMultipleTimesSleepAfterEveryUpdate) 284 { 285 InSequence seq; 286 for (const auto& [index, timestamp, value] : GetParam().expected) 287 { 288 EXPECT_CALL(actionMock, commit(sensorNames[index], timestamp, value)); 289 } 290 291 sut->initialize(); 292 for (const auto& [index, timestamp, value] : GetParam().updates) 293 { 294 sut->sensorUpdated(*sensorMocks[index], timestamp, value); 295 sleep(); 296 } 297 } 298 299 class TestNumericThresholdWithDwellTime2 : 300 public TestNumericThreshold, 301 public WithParamInterface<NumericParams> 302 { 303 public: 304 void SetUp() override 305 { 306 makeThreshold(2ms, GetParam().direction, 90.0); 307 } 308 309 void sleep() 310 { 311 DbusEnvironment::sleepFor(4ms); 312 } 313 }; 314 315 INSTANTIATE_TEST_SUITE_P(_, TestNumericThresholdWithDwellTime2, 316 Values(NumericParams() 317 .Direction(numeric::Direction::increasing) 318 .Updates({{0, 1ms, 80.0}, {0, 2ms, 89.0}}) 319 .Expected({}), 320 NumericParams() 321 .Direction(numeric::Direction::increasing) 322 .Updates({{0, 1ms, 80.0}, {0, 2ms, 91.0}}) 323 .Expected({{0, 2ms, 91.0}}), 324 NumericParams() 325 .Direction(numeric::Direction::increasing) 326 .Updates({{0, 1ms, 80.0}, 327 {0, 2ms, 99.0}, 328 {0, 3ms, 80.0}, 329 {0, 4ms, 98.0}}) 330 .Expected({{0, 4ms, 98.0}}), 331 NumericParams() 332 .Direction(numeric::Direction::increasing) 333 .Updates({{0, 1ms, 80.0}, 334 {1, 2ms, 99.0}, 335 {0, 3ms, 100.0}, 336 {1, 4ms, 98.0}}) 337 .Expected({{0, 3ms, 100.0}}), 338 NumericParams() 339 .Direction(numeric::Direction::decreasing) 340 .Updates({{0, 1ms, 100.0}, {0, 2ms, 91.0}}) 341 .Expected({}), 342 NumericParams() 343 .Direction(numeric::Direction::decreasing) 344 .Updates({{0, 1ms, 100.0}, {0, 2ms, 80.0}}) 345 .Expected({{0, 2ms, 80.0}}), 346 NumericParams() 347 .Direction(numeric::Direction::decreasing) 348 .Updates({{0, 1ms, 100.0}, 349 {0, 2ms, 80.0}, 350 {0, 3ms, 99.0}, 351 {0, 4ms, 85.0}}) 352 .Expected({{0, 4ms, 85.0}}), 353 NumericParams() 354 .Direction(numeric::Direction::decreasing) 355 .Updates({{0, 1ms, 100.0}, 356 {0, 2ms, 80.0}, 357 {1, 3ms, 99.0}, 358 {1, 4ms, 88.0}}) 359 .Expected({{0, 2ms, 80.0}, {1, 4ms, 88.0}}), 360 NumericParams() 361 .Direction(numeric::Direction::either) 362 .Updates({{0, 1ms, 98.0}, {0, 2ms, 91.0}}) 363 .Expected({}), 364 NumericParams() 365 .Direction(numeric::Direction::either) 366 .Updates({{0, 1ms, 100.0}, 367 {0, 2ms, 80.0}, 368 {0, 3ms, 85.0}, 369 {0, 4ms, 91.0}}) 370 .Expected({{0, 4ms, 91.0}}), 371 NumericParams() 372 .Direction(numeric::Direction::either) 373 .Updates({{0, 1ms, 100.0}, 374 {1, 2ms, 80.0}, 375 {0, 3ms, 85.0}, 376 {1, 4ms, 91.0}}) 377 .Expected({{0, 3ms, 85.0}, 378 {1, 4ms, 91.0}}))); 379 380 TEST_P(TestNumericThresholdWithDwellTime2, 381 senorsIsUpdatedMultipleTimesSleepAfterLastUpdate) 382 { 383 InSequence seq; 384 for (const auto& [index, timestamp, value] : GetParam().expected) 385 { 386 EXPECT_CALL(actionMock, commit(sensorNames[index], timestamp, value)); 387 } 388 389 sut->initialize(); 390 for (const auto& [index, timestamp, value] : GetParam().updates) 391 { 392 sut->sensorUpdated(*sensorMocks[index], timestamp, value); 393 } 394 sleep(); 395 } 396