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, uint64_t, double>> val) 73 { 74 updates = std::move(val); 75 return *this; 76 } 77 78 NumericParams& 79 Expected(std::vector<std::tuple<size_t, uint64_t, 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 << ", Timestamp: " << timestamp 92 << ", Value: " << value << " }, "; 93 } 94 *os << "Expected: "; 95 for (const auto& [index, timestamp, value] : o.expected) 96 { 97 *os << "{ SensorIndex: " << index << ", Timestamp: " << timestamp 98 << ", Value: " << value << " }, "; 99 } 100 *os << " }"; 101 } 102 103 numeric::Direction direction; 104 std::vector<std::tuple<size_t, uint64_t, double>> updates; 105 std::vector<std::tuple<size_t, uint64_t, double>> expected; 106 }; 107 108 class TestNumericThresholdNoDwellTime : 109 public TestNumericThreshold, 110 public WithParamInterface<NumericParams> 111 { 112 public: 113 void SetUp() override 114 { 115 makeThreshold(0ms, GetParam().direction, 90.0); 116 } 117 }; 118 119 INSTANTIATE_TEST_SUITE_P( 120 _, TestNumericThresholdNoDwellTime, 121 Values( 122 NumericParams() 123 .Direction(numeric::Direction::increasing) 124 .Updates({{0, 1, 80.0}, {0, 2, 89.0}}) 125 .Expected({}), 126 NumericParams() 127 .Direction(numeric::Direction::increasing) 128 .Updates({{0, 1, 80.0}, {0, 2, 91.0}}) 129 .Expected({{0, 2, 91.0}}), 130 NumericParams() 131 .Direction(numeric::Direction::increasing) 132 .Updates({{0, 1, 80.0}, {0, 2, 99.0}, {0, 3, 80.0}, {0, 4, 98.0}}) 133 .Expected({{0, 2, 99.0}, {0, 4, 98.0}}), 134 NumericParams() 135 .Direction(numeric::Direction::increasing) 136 .Updates({{0, 1, 80.0}, {0, 2, 99.0}, {1, 3, 100.0}, {1, 4, 98.0}}) 137 .Expected({{0, 2, 99.0}}), 138 NumericParams() 139 .Direction(numeric::Direction::decreasing) 140 .Updates({{0, 1, 100.0}, {0, 2, 91.0}}) 141 .Expected({}), 142 NumericParams() 143 .Direction(numeric::Direction::decreasing) 144 .Updates({{0, 1, 100.0}, {0, 2, 80.0}}) 145 .Expected({{0, 2, 80.0}}), 146 NumericParams() 147 .Direction(numeric::Direction::decreasing) 148 .Updates({{0, 1, 100.0}, {0, 2, 80.0}, {0, 3, 99.0}, {0, 4, 85.0}}) 149 .Expected({{0, 2, 80.0}, {0, 4, 85.0}}), 150 NumericParams() 151 .Direction(numeric::Direction::decreasing) 152 .Updates({{0, 1, 100.0}, {0, 2, 80.0}, {1, 3, 99.0}, {1, 4, 88.0}}) 153 .Expected({{0, 2, 80.0}, {1, 4, 88.0}}), 154 NumericParams() 155 .Direction(numeric::Direction::either) 156 .Updates({{0, 1, 98.0}, {0, 2, 91.0}}) 157 .Expected({}), 158 NumericParams() 159 .Direction(numeric::Direction::either) 160 .Updates({{0, 1, 100.0}, {0, 2, 80.0}, {0, 3, 85.0}, {0, 4, 91.0}}) 161 .Expected({{0, 2, 80.0}, {0, 4, 91.0}}), 162 NumericParams() 163 .Direction(numeric::Direction::either) 164 .Updates({{0, 1, 100.0}, {1, 2, 80.0}, {0, 3, 85.0}, {1, 4, 91.0}}) 165 .Expected({{0, 3, 85.0}, {1, 4, 91.0}}))); 166 167 TEST_P(TestNumericThresholdNoDwellTime, senorsIsUpdatedMultipleTimes) 168 { 169 InSequence seq; 170 for (const auto& [index, timestamp, value] : GetParam().expected) 171 { 172 EXPECT_CALL(actionMock, commit(sensorNames[index], timestamp, value)); 173 } 174 175 sut->initialize(); 176 for (const auto& [index, timestamp, value] : GetParam().updates) 177 { 178 sut->sensorUpdated(*sensorMocks[index], timestamp, value); 179 } 180 } 181 182 class TestNumericThresholdWithDwellTime : 183 public TestNumericThreshold, 184 public WithParamInterface<NumericParams> 185 { 186 public: 187 void SetUp() override 188 { 189 makeThreshold(2ms, GetParam().direction, 90.0); 190 } 191 192 void sleep() 193 { 194 DbusEnvironment::sleepFor(4ms); 195 } 196 }; 197 198 INSTANTIATE_TEST_SUITE_P( 199 _, TestNumericThresholdWithDwellTime, 200 Values( 201 NumericParams() 202 .Direction(numeric::Direction::increasing) 203 .Updates({{0, 1, 80.0}, {0, 2, 89.0}}) 204 .Expected({}), 205 NumericParams() 206 .Direction(numeric::Direction::increasing) 207 .Updates({{0, 1, 80.0}, {0, 2, 91.0}}) 208 .Expected({{0, 2, 91.0}}), 209 NumericParams() 210 .Direction(numeric::Direction::increasing) 211 .Updates({{0, 1, 80.0}, {0, 2, 99.0}, {0, 3, 80.0}, {0, 4, 98.0}}) 212 .Expected({{0, 2, 99.0}, {0, 4, 98.0}}), 213 NumericParams() 214 .Direction(numeric::Direction::increasing) 215 .Updates({{0, 1, 80.0}, {1, 2, 99.0}, {0, 3, 100.0}, {1, 4, 86.0}}) 216 .Expected({{0, 3, 100.0}}), 217 NumericParams() 218 .Direction(numeric::Direction::decreasing) 219 .Updates({{0, 1, 100.0}, {0, 2, 91.0}}) 220 .Expected({}), 221 NumericParams() 222 .Direction(numeric::Direction::decreasing) 223 .Updates({{0, 1, 100.0}, {0, 2, 80.0}}) 224 .Expected({{0, 2, 80.0}}), 225 NumericParams() 226 .Direction(numeric::Direction::decreasing) 227 .Updates({{0, 1, 100.0}, {0, 2, 80.0}, {0, 3, 99.0}, {0, 4, 85.0}}) 228 .Expected({{0, 2, 80.0}, {0, 4, 85.0}}), 229 NumericParams() 230 .Direction(numeric::Direction::decreasing) 231 .Updates({{0, 1, 100.0}, {0, 2, 80.0}, {1, 3, 99.0}, {1, 4, 88.0}}) 232 .Expected({{0, 2, 80.0}, {1, 4, 88.0}}), 233 NumericParams() 234 .Direction(numeric::Direction::either) 235 .Updates({{0, 1, 98.0}, {0, 2, 91.0}}) 236 .Expected({}), 237 NumericParams() 238 .Direction(numeric::Direction::either) 239 .Updates({{0, 1, 100.0}, {0, 2, 80.0}, {0, 3, 85.0}, {0, 4, 91.0}}) 240 .Expected({{0, 2, 80.0}, {0, 4, 91.0}}), 241 NumericParams() 242 .Direction(numeric::Direction::either) 243 .Updates({{0, 1, 100.0}, {1, 2, 80.0}, {0, 3, 85.0}, {1, 4, 91.0}}) 244 .Expected({{0, 3, 85.0}, {1, 4, 91.0}}))); 245 246 TEST_P(TestNumericThresholdWithDwellTime, 247 senorsIsUpdatedMultipleTimesSleepAfterEveryUpdate) 248 { 249 InSequence seq; 250 for (const auto& [index, timestamp, value] : GetParam().expected) 251 { 252 EXPECT_CALL(actionMock, commit(sensorNames[index], timestamp, value)); 253 } 254 255 sut->initialize(); 256 for (const auto& [index, timestamp, value] : GetParam().updates) 257 { 258 sut->sensorUpdated(*sensorMocks[index], timestamp, value); 259 sleep(); 260 } 261 } 262 263 class TestNumericThresholdWithDwellTime2 : 264 public TestNumericThreshold, 265 public WithParamInterface<NumericParams> 266 { 267 public: 268 void SetUp() override 269 { 270 makeThreshold(2ms, GetParam().direction, 90.0); 271 } 272 273 void sleep() 274 { 275 DbusEnvironment::sleepFor(4ms); 276 } 277 }; 278 279 INSTANTIATE_TEST_SUITE_P( 280 _, TestNumericThresholdWithDwellTime2, 281 Values( 282 NumericParams() 283 .Direction(numeric::Direction::increasing) 284 .Updates({{0, 1, 80.0}, {0, 2, 89.0}}) 285 .Expected({}), 286 NumericParams() 287 .Direction(numeric::Direction::increasing) 288 .Updates({{0, 1, 80.0}, {0, 2, 91.0}}) 289 .Expected({{0, 2, 91.0}}), 290 NumericParams() 291 .Direction(numeric::Direction::increasing) 292 .Updates({{0, 1, 80.0}, {0, 2, 99.0}, {0, 3, 80.0}, {0, 4, 98.0}}) 293 .Expected({{0, 4, 98.0}}), 294 NumericParams() 295 .Direction(numeric::Direction::increasing) 296 .Updates({{0, 1, 80.0}, {1, 2, 99.0}, {0, 3, 100.0}, {1, 4, 98.0}}) 297 .Expected({{0, 3, 100.0}}), 298 NumericParams() 299 .Direction(numeric::Direction::decreasing) 300 .Updates({{0, 1, 100.0}, {0, 2, 91.0}}) 301 .Expected({}), 302 NumericParams() 303 .Direction(numeric::Direction::decreasing) 304 .Updates({{0, 1, 100.0}, {0, 2, 80.0}}) 305 .Expected({{0, 2, 80.0}}), 306 NumericParams() 307 .Direction(numeric::Direction::decreasing) 308 .Updates({{0, 1, 100.0}, {0, 2, 80.0}, {0, 3, 99.0}, {0, 4, 85.0}}) 309 .Expected({{0, 4, 85.0}}), 310 NumericParams() 311 .Direction(numeric::Direction::decreasing) 312 .Updates({{0, 1, 100.0}, {0, 2, 80.0}, {1, 3, 99.0}, {1, 4, 88.0}}) 313 .Expected({{0, 2, 80.0}, {1, 4, 88.0}}), 314 NumericParams() 315 .Direction(numeric::Direction::either) 316 .Updates({{0, 1, 98.0}, {0, 2, 91.0}}) 317 .Expected({}), 318 NumericParams() 319 .Direction(numeric::Direction::either) 320 .Updates({{0, 1, 100.0}, {0, 2, 80.0}, {0, 3, 85.0}, {0, 4, 91.0}}) 321 .Expected({{0, 4, 91.0}}), 322 NumericParams() 323 .Direction(numeric::Direction::either) 324 .Updates({{0, 1, 100.0}, {1, 2, 80.0}, {0, 3, 85.0}, {1, 4, 91.0}}) 325 .Expected({{0, 3, 85.0}, {1, 4, 91.0}}))); 326 327 TEST_P(TestNumericThresholdWithDwellTime2, 328 senorsIsUpdatedMultipleTimesSleepAfterLastUpdate) 329 { 330 InSequence seq; 331 for (const auto& [index, timestamp, value] : GetParam().expected) 332 { 333 EXPECT_CALL(actionMock, commit(sensorNames[index], timestamp, value)); 334 } 335 336 sut->initialize(); 337 for (const auto& [index, timestamp, value] : GetParam().updates) 338 { 339 sut->sensorUpdated(*sensorMocks[index], timestamp, value); 340 } 341 sleep(); 342 } 343