#include "dbus_environment.hpp" #include "helpers.hpp" #include "mocks/sensor_mock.hpp" #include "mocks/trigger_action_mock.hpp" #include "numeric_threshold.hpp" #include "utils/conv_container.hpp" #include using namespace testing; using namespace std::chrono_literals; class TestNumericThreshold : public Test { public: std::vector> sensorMocks = { std::make_shared>(), std::make_shared>()}; std::vector sensorNames = {"Sensor1", "Sensor2"}; std::unique_ptr actionMockPtr = std::make_unique>(); TriggerActionMock& actionMock = *actionMockPtr; std::shared_ptr sut; void makeThreshold(Milliseconds dwellTime, numeric::Direction direction, double thresholdValue, numeric::Type type = numeric::Type::lowerWarning) { std::vector> actions; actions.push_back(std::move(actionMockPtr)); sut = std::make_shared( DbusEnvironment::getIoc(), utils::convContainer>( sensorMocks), std::move(actions), dwellTime, direction, thresholdValue, type); } void SetUp() override { for (size_t idx = 0; idx < sensorMocks.size(); idx++) { ON_CALL(*sensorMocks.at(idx), getName()) .WillByDefault(Return(sensorNames[idx])); } makeThreshold(0ms, numeric::Direction::increasing, 90.0, numeric::Type::upperCritical); } }; TEST_F(TestNumericThreshold, initializeThresholdExpectAllSensorsAreRegistered) { for (auto& sensor : sensorMocks) { EXPECT_CALL(*sensor, registerForUpdates(Truly([sut = sut.get()](const auto& x) { return x.lock().get() == sut; }))); } sut->initialize(); } TEST_F(TestNumericThreshold, thresholdIsNotInitializeExpectNoActionCommit) { EXPECT_CALL(actionMock, commit(_, _, _)).Times(0); } TEST_F(TestNumericThreshold, getLabeledParamsReturnsCorrectly) { LabeledThresholdParam expected = numeric::LabeledThresholdParam( numeric::Type::upperCritical, 0, numeric::Direction::increasing, 90.0); EXPECT_EQ(sut->getThresholdParam(), expected); } struct NumericParams { NumericParams& Direction(numeric::Direction val) { direction = val; return *this; } NumericParams& Updates(std::vector> val) { updates = std::move(val); return *this; } NumericParams& Expected(std::vector> val) { expected = std::move(val); return *this; } friend void PrintTo(const NumericParams& o, std::ostream* os) { *os << "{ Direction: " << static_cast(o.direction) << ", Updates: "; for (const auto& [index, timestamp, value] : o.updates) { *os << "{ SensorIndex: " << index << ", Timestamp: " << timestamp.count() << ", Value: " << value << " }, "; } *os << "Expected: "; for (const auto& [index, timestamp, value] : o.expected) { *os << "{ SensorIndex: " << index << ", Timestamp: " << timestamp.count() << ", Value: " << value << " }, "; } *os << " }"; } numeric::Direction direction; std::vector> updates; std::vector> expected; }; class TestNumericThresholdNoDwellTime : public TestNumericThreshold, public WithParamInterface { public: void SetUp() override { for (size_t idx = 0; idx < sensorMocks.size(); idx++) { ON_CALL(*sensorMocks.at(idx), getName()) .WillByDefault(Return(sensorNames[idx])); } makeThreshold(0ms, GetParam().direction, 90.0); } }; INSTANTIATE_TEST_SUITE_P(_, TestNumericThresholdNoDwellTime, Values(NumericParams() .Direction(numeric::Direction::increasing) .Updates({{0, 1ms, 80.0}, {0, 2ms, 89.0}}) .Expected({}), NumericParams() .Direction(numeric::Direction::increasing) .Updates({{0, 1ms, 80.0}, {0, 2ms, 91.0}}) .Expected({{0, 2ms, 91.0}}), NumericParams() .Direction(numeric::Direction::increasing) .Updates({{0, 1ms, 80.0}, {0, 2ms, 99.0}, {0, 3ms, 80.0}, {0, 4ms, 98.0}}) .Expected({{0, 2ms, 99.0}, {0, 4ms, 98.0}}), NumericParams() .Direction(numeric::Direction::increasing) .Updates({{0, 1ms, 80.0}, {0, 2ms, 99.0}, {1, 3ms, 100.0}, {1, 4ms, 98.0}}) .Expected({{0, 2ms, 99.0}}), NumericParams() .Direction(numeric::Direction::decreasing) .Updates({{0, 1ms, 100.0}, {0, 2ms, 91.0}}) .Expected({}), NumericParams() .Direction(numeric::Direction::decreasing) .Updates({{0, 1ms, 100.0}, {0, 2ms, 80.0}}) .Expected({{0, 2ms, 80.0}}), NumericParams() .Direction(numeric::Direction::decreasing) .Updates({{0, 1ms, 100.0}, {0, 2ms, 80.0}, {0, 3ms, 99.0}, {0, 4ms, 85.0}}) .Expected({{0, 2ms, 80.0}, {0, 4ms, 85.0}}), NumericParams() .Direction(numeric::Direction::decreasing) .Updates({{0, 1ms, 100.0}, {0, 2ms, 80.0}, {1, 3ms, 99.0}, {1, 4ms, 88.0}}) .Expected({{0, 2ms, 80.0}, {1, 4ms, 88.0}}), NumericParams() .Direction(numeric::Direction::either) .Updates({{0, 1ms, 98.0}, {0, 2ms, 91.0}}) .Expected({}), NumericParams() .Direction(numeric::Direction::either) .Updates({{0, 1ms, 100.0}, {0, 2ms, 80.0}, {0, 3ms, 85.0}, {0, 4ms, 91.0}}) .Expected({{0, 2ms, 80.0}, {0, 4ms, 91.0}}), NumericParams() .Direction(numeric::Direction::either) .Updates({{0, 1ms, 100.0}, {1, 2ms, 80.0}, {0, 3ms, 85.0}, {1, 4ms, 91.0}}) .Expected({{0, 3ms, 85.0}, {1, 4ms, 91.0}}))); TEST_P(TestNumericThresholdNoDwellTime, senorsIsUpdatedMultipleTimes) { InSequence seq; for (const auto& [index, timestamp, value] : GetParam().expected) { EXPECT_CALL(actionMock, commit(sensorNames[index], timestamp, value)); } sut->initialize(); for (const auto& [index, timestamp, value] : GetParam().updates) { sut->sensorUpdated(*sensorMocks[index], timestamp, value); } } class TestNumericThresholdWithDwellTime : public TestNumericThreshold, public WithParamInterface { public: void SetUp() override { for (size_t idx = 0; idx < sensorMocks.size(); idx++) { ON_CALL(*sensorMocks.at(idx), getName()) .WillByDefault(Return(sensorNames[idx])); } makeThreshold(2ms, GetParam().direction, 90.0); } void sleep() { DbusEnvironment::sleepFor(4ms); } }; INSTANTIATE_TEST_SUITE_P(_, TestNumericThresholdWithDwellTime, Values(NumericParams() .Direction(numeric::Direction::increasing) .Updates({{0, 1ms, 80.0}, {0, 2ms, 89.0}}) .Expected({}), NumericParams() .Direction(numeric::Direction::increasing) .Updates({{0, 1ms, 80.0}, {0, 2ms, 91.0}}) .Expected({{0, 2ms, 91.0}}), NumericParams() .Direction(numeric::Direction::increasing) .Updates({{0, 1ms, 80.0}, {0, 2ms, 99.0}, {0, 3ms, 80.0}, {0, 4ms, 98.0}}) .Expected({{0, 2ms, 99.0}, {0, 4ms, 98.0}}), NumericParams() .Direction(numeric::Direction::increasing) .Updates({{0, 1ms, 80.0}, {1, 2ms, 99.0}, {0, 3ms, 100.0}, {1, 4ms, 86.0}}) .Expected({{0, 3ms, 100.0}}), NumericParams() .Direction(numeric::Direction::decreasing) .Updates({{0, 1ms, 100.0}, {0, 2ms, 91.0}}) .Expected({}), NumericParams() .Direction(numeric::Direction::decreasing) .Updates({{0, 1ms, 100.0}, {0, 2ms, 80.0}}) .Expected({{0, 2ms, 80.0}}), NumericParams() .Direction(numeric::Direction::decreasing) .Updates({{0, 1ms, 100.0}, {0, 2ms, 80.0}, {0, 3ms, 99.0}, {0, 4ms, 85.0}}) .Expected({{0, 2ms, 80.0}, {0, 4ms, 85.0}}), NumericParams() .Direction(numeric::Direction::decreasing) .Updates({{0, 1ms, 100.0}, {0, 2ms, 80.0}, {1, 3ms, 99.0}, {1, 4ms, 88.0}}) .Expected({{0, 2ms, 80.0}, {1, 4ms, 88.0}}), NumericParams() .Direction(numeric::Direction::either) .Updates({{0, 1ms, 98.0}, {0, 2ms, 91.0}}) .Expected({}), NumericParams() .Direction(numeric::Direction::either) .Updates({{0, 1ms, 100.0}, {0, 2ms, 80.0}, {0, 3ms, 85.0}, {0, 4ms, 91.0}}) .Expected({{0, 2ms, 80.0}, {0, 4ms, 91.0}}), NumericParams() .Direction(numeric::Direction::either) .Updates({{0, 1ms, 100.0}, {1, 2ms, 80.0}, {0, 3ms, 85.0}, {1, 4ms, 91.0}}) .Expected({{0, 3ms, 85.0}, {1, 4ms, 91.0}}))); TEST_P(TestNumericThresholdWithDwellTime, senorsIsUpdatedMultipleTimesSleepAfterEveryUpdate) { InSequence seq; for (const auto& [index, timestamp, value] : GetParam().expected) { EXPECT_CALL(actionMock, commit(sensorNames[index], timestamp, value)); } sut->initialize(); for (const auto& [index, timestamp, value] : GetParam().updates) { sut->sensorUpdated(*sensorMocks[index], timestamp, value); sleep(); } } class TestNumericThresholdWithDwellTime2 : public TestNumericThreshold, public WithParamInterface { public: void SetUp() override { for (size_t idx = 0; idx < sensorMocks.size(); idx++) { ON_CALL(*sensorMocks.at(idx), getName()) .WillByDefault(Return(sensorNames[idx])); } makeThreshold(2ms, GetParam().direction, 90.0); } void sleep() { DbusEnvironment::sleepFor(4ms); } }; INSTANTIATE_TEST_SUITE_P(_, TestNumericThresholdWithDwellTime2, Values(NumericParams() .Direction(numeric::Direction::increasing) .Updates({{0, 1ms, 80.0}, {0, 2ms, 89.0}}) .Expected({}), NumericParams() .Direction(numeric::Direction::increasing) .Updates({{0, 1ms, 80.0}, {0, 2ms, 91.0}}) .Expected({{0, 2ms, 91.0}}), NumericParams() .Direction(numeric::Direction::increasing) .Updates({{0, 1ms, 80.0}, {0, 2ms, 99.0}, {0, 3ms, 80.0}, {0, 4ms, 98.0}}) .Expected({{0, 4ms, 98.0}}), NumericParams() .Direction(numeric::Direction::increasing) .Updates({{0, 1ms, 80.0}, {1, 2ms, 99.0}, {0, 3ms, 100.0}, {1, 4ms, 98.0}}) .Expected({{0, 3ms, 100.0}}), NumericParams() .Direction(numeric::Direction::decreasing) .Updates({{0, 1ms, 100.0}, {0, 2ms, 91.0}}) .Expected({}), NumericParams() .Direction(numeric::Direction::decreasing) .Updates({{0, 1ms, 100.0}, {0, 2ms, 80.0}}) .Expected({{0, 2ms, 80.0}}), NumericParams() .Direction(numeric::Direction::decreasing) .Updates({{0, 1ms, 100.0}, {0, 2ms, 80.0}, {0, 3ms, 99.0}, {0, 4ms, 85.0}}) .Expected({{0, 4ms, 85.0}}), NumericParams() .Direction(numeric::Direction::decreasing) .Updates({{0, 1ms, 100.0}, {0, 2ms, 80.0}, {1, 3ms, 99.0}, {1, 4ms, 88.0}}) .Expected({{0, 2ms, 80.0}, {1, 4ms, 88.0}}), NumericParams() .Direction(numeric::Direction::either) .Updates({{0, 1ms, 98.0}, {0, 2ms, 91.0}}) .Expected({}), NumericParams() .Direction(numeric::Direction::either) .Updates({{0, 1ms, 100.0}, {0, 2ms, 80.0}, {0, 3ms, 85.0}, {0, 4ms, 91.0}}) .Expected({{0, 4ms, 91.0}}), NumericParams() .Direction(numeric::Direction::either) .Updates({{0, 1ms, 100.0}, {1, 2ms, 80.0}, {0, 3ms, 85.0}, {1, 4ms, 91.0}}) .Expected({{0, 3ms, 85.0}, {1, 4ms, 91.0}}))); TEST_P(TestNumericThresholdWithDwellTime2, senorsIsUpdatedMultipleTimesSleepAfterLastUpdate) { InSequence seq; for (const auto& [index, timestamp, value] : GetParam().expected) { EXPECT_CALL(actionMock, commit(sensorNames[index], timestamp, value)); } sut->initialize(); for (const auto& [index, timestamp, value] : GetParam().updates) { sut->sensorUpdated(*sensorMocks[index], timestamp, value); } sleep(); }