1 #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 "types/duration_types.hpp" 7 #include "utils/conv_container.hpp" 8 9 #include <gmock/gmock.h> 10 11 using namespace testing; 12 using namespace std::chrono_literals; 13 14 class TestDiscreteThreshold : public Test 15 { 16 public: 17 std::vector<std::shared_ptr<SensorMock>> sensorMocks = { 18 std::make_shared<NiceMock<SensorMock>>(), 19 std::make_shared<NiceMock<SensorMock>>()}; 20 std::vector<std::string> sensorNames = {"Sensor1", "Sensor2"}; 21 std::unique_ptr<TriggerActionMock> actionMockPtr = 22 std::make_unique<StrictMock<TriggerActionMock>>(); 23 TriggerActionMock& actionMock = *actionMockPtr; 24 std::shared_ptr<DiscreteThreshold> sut; 25 26 std::shared_ptr<DiscreteThreshold> makeThreshold(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 46 TEST_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 59 TEST_F(TestDiscreteThreshold, thresholdIsNotInitializeExpectNoActionCommit) 60 { 61 EXPECT_CALL(actionMock, commit(_, _, _)).Times(0); 62 } 63 64 struct DiscreteParams 65 { 66 struct UpdateParams 67 { 68 size_t sensor; 69 Milliseconds timestamp; 70 double value; 71 Milliseconds sleepAfter; 72 73 UpdateParams(size_t sensor, Milliseconds timestamp, double value, 74 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 Milliseconds timestamp; 84 double value; 85 Milliseconds waitMin; 86 87 ExpectedParams(size_t sensor, Milliseconds timestamp, double value, 88 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(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 126 << ", Timestamp: " << timestamp.count() << ", 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 133 << ", Timestamp: " << timestamp.count() << ", Value: " << value 134 << ", waitMin: " << waitMin.count() << "ms }, "; 135 } 136 *os << " }"; 137 } 138 139 std::vector<UpdateParams> updates; 140 std::vector<ExpectedParams> expected; 141 double thresholdValue = 0.0; 142 Milliseconds dwellTime = 0ms; 143 }; 144 145 class TestDiscreteThresholdCommon : 146 public TestDiscreteThreshold, 147 public WithParamInterface<DiscreteParams> 148 { 149 public: 150 void sleep(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, ×tamps] { 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 198 class TestDiscreteThresholdNoDwellTime : public TestDiscreteThresholdCommon 199 { 200 public: 201 void SetUp() override 202 { 203 sut = makeThreshold(0ms, GetParam().thresholdValue); 204 } 205 }; 206 207 INSTANTIATE_TEST_SUITE_P(_, TestDiscreteThresholdNoDwellTime, 208 Values(DiscreteParams() 209 .ThresholdValue(90.0) 210 .Updates({{0, 1ms, 80.0}, {0, 2ms, 89.0}}) 211 .Expected({}), 212 DiscreteParams() 213 .ThresholdValue(90.0) 214 .Updates({{0, 1ms, 80.0}, 215 {0, 2ms, 90.0}, 216 {0, 3ms, 80.0}, 217 {0, 4ms, 90.0}}) 218 .Expected({{0, 2ms, 90.0}, {0, 4ms, 90.0}}), 219 DiscreteParams() 220 .ThresholdValue(90.0) 221 .Updates({{0, 1ms, 90.0}, 222 {0, 2ms, 99.0}, 223 {1, 3ms, 100.0}, 224 {1, 4ms, 90.0}}) 225 .Expected({{0, 1ms, 90.0}, 226 {1, 4ms, 90.0}}))); 227 228 TEST_P(TestDiscreteThresholdNoDwellTime, senorsIsUpdatedMultipleTimes) 229 { 230 testBodySensorIsUpdatedMultipleTimes(); 231 } 232 233 class TestDiscreteThresholdWithDwellTime : public TestDiscreteThresholdCommon 234 { 235 public: 236 void SetUp() override 237 { 238 sut = makeThreshold(GetParam().dwellTime, GetParam().thresholdValue); 239 } 240 }; 241 242 INSTANTIATE_TEST_SUITE_P( 243 _, TestDiscreteThresholdWithDwellTime, 244 Values(DiscreteParams() 245 .DwellTime(200ms) 246 .ThresholdValue(90.0) 247 .Updates({{0, 1ms, 90.0, 100ms}, {0, 2ms, 91.0}, {0, 3ms, 90.0}}) 248 .Expected({{0, 3ms, 90.0, 300ms}}), 249 DiscreteParams() 250 .DwellTime(100ms) 251 .ThresholdValue(90.0) 252 .Updates({{0, 1ms, 90.0, 100ms}}) 253 .Expected({{0, 1ms, 90.0, 100ms}}), 254 DiscreteParams() 255 .DwellTime(1000ms) 256 .ThresholdValue(90.0) 257 .Updates({{0, 1ms, 90.0, 700ms}, 258 {0, 1ms, 91.0, 100ms}, 259 {0, 1ms, 90.0, 300ms}, 260 {0, 1ms, 91.0, 100ms}}) 261 .Expected({}), 262 DiscreteParams() 263 .DwellTime(200ms) 264 .ThresholdValue(90.0) 265 .Updates({{0, 1ms, 90.0}, 266 {1, 2ms, 89.0, 100ms}, 267 {1, 3ms, 90.0, 100ms}, 268 {1, 4ms, 89.0, 100ms}, 269 {1, 5ms, 90.0, 300ms}, 270 {1, 6ms, 89.0, 100ms}}) 271 .Expected({{0, 1ms, 90, 200ms}, {1, 5ms, 90, 500ms}}))); 272 273 TEST_P(TestDiscreteThresholdWithDwellTime, senorsIsUpdatedMultipleTimes) 274 { 275 testBodySensorIsUpdatedMultipleTimes(); 276 } 277