[BH-691] Alarms handling Handle alarms in service-time
14 files changed, 551 insertions(+), 30 deletions(-) M module-db/Interface/AlarmEventRecord.cpp M module-db/Interface/AlarmEventRecord.hpp M module-db/Interface/EventRecord.cpp M module-db/Interface/EventRecord.hpp M module-db/tests/EventRecord_tests.cpp M module-services/service-time/AlarmMessageHandler.cpp M module-services/service-time/AlarmMessageHandler.hpp M module-services/service-time/AlarmOperations.cpp M module-services/service-time/AlarmOperations.hpp M module-services/service-time/AlarmRepository.hpp M module-services/service-time/ServiceTime.cpp M module-services/service-time/ServiceTime.hpp M module-services/service-time/include/service-time/AlarmServiceAPI.hpp M module-services/service-time/tests/tests-AlarmOperations.cpp
M module-db/Interface/AlarmEventRecord.cpp => module-db/Interface/AlarmEventRecord.cpp +5 -0
@@ 173,3 173,8 @@ std::vector<AlarmEventRecord> generateRecordsVector(const std::vector<AlarmEvent } return recordVector; } std::shared_ptr<EventRecord> AlarmEventRecord::getCopy() { return std::make_shared<AlarmEventRecord>(*this); }
M module-db/Interface/AlarmEventRecord.hpp => module-db/Interface/AlarmEventRecord.hpp +2 -1
@@ 45,8 45,9 @@ struct AlarmEventRecord : public EventRecord bool enabled, uint32_t snoozeDuration); AlarmEventRecord(const AlarmEventsTableRow &aeRow); explicit AlarmEventRecord(const AlarmEventsTableRow &aeRow); std::shared_ptr<EventRecord> getCopy() override; auto isValid() const -> bool; };
M module-db/Interface/EventRecord.cpp => module-db/Interface/EventRecord.cpp +6 -1
@@ 62,9 62,14 @@ std::vector<SingleEventRecord> EventRecord::generateSingleEvents(TimePoint from, return singleEvents; } std::shared_ptr<EventRecord> EventRecord::getCopy() { return std::make_shared<EventRecord>(*this); } SingleEventRecord EventRecord::getNextSingleEvent(TimePoint from) { auto parentEvent = std::make_shared<EventRecord>(this); auto parentEvent = getCopy(); if (rruleText.empty()) { if (startDate < from) {
M module-db/Interface/EventRecord.hpp => module-db/Interface/EventRecord.hpp +4 -0
@@ 44,11 44,15 @@ struct EventRecord : public Record, public EventInfo uint32_t duration, bool isAllDay, const std::string &rruleText); virtual ~EventRecord(){}; explicit EventRecord(EventRecord *record); auto generateSingleEvents(TimePoint from, TimePoint to, uint32_t count) -> std::vector<SingleEventRecord>; auto getNextSingleEvent(TimePoint from) -> SingleEventRecord; auto isValid() const -> bool; virtual std::shared_ptr<EventRecord> getCopy(); }; struct SingleEventRecord : public Record, public EventInfo
M module-db/tests/EventRecord_tests.cpp => module-db/tests/EventRecord_tests.cpp +20 -0
@@ 3,6 3,7 @@ #include "common.hpp" #include <Interface/AlarmEventRecord.hpp> #include <Interface/EventRecord.hpp> #include <time/dateCommon.hpp> @@ 117,4 118,23 @@ TEST_CASE("EventRecord tests") REQUIRE(event.startDate == TimePointFromString("2021-03-01 12:00:00")); REQUIRE(event.endDate == TimePointFromString("2021-03-01 13:00:00")); } SECTION("Generate next AlarmEvent daily") { AlarmEventRecord eventRecord( 1, testName, testEventStart, testDuration, testIsAllDay, "FREQ=DAILY", "", true, 15); auto event = eventRecord.getNextSingleEvent(TimePointFromString("2000-01-01 00:00:00")); REQUIRE(event.name == eventRecord.name); REQUIRE(event.startDate == eventRecord.startDate); REQUIRE(event.endDate == TimePointFromString("2020-01-11 13:00:00")); REQUIRE(event.duration == eventRecord.duration); REQUIRE(event.isAllDay == eventRecord.isAllDay); REQUIRE(event.parent != nullptr); auto parent = std::dynamic_pointer_cast<AlarmEventRecord>(event.parent); REQUIRE(parent->ID == eventRecord.ID); REQUIRE(parent->musicTone == eventRecord.musicTone); REQUIRE(parent->enabled == eventRecord.enabled); REQUIRE(parent->snoozeDuration == eventRecord.snoozeDuration); } }
M module-services/service-time/AlarmMessageHandler.cpp => module-services/service-time/AlarmMessageHandler.cpp +11 -0
@@ 77,6 77,17 @@ namespace alarms }); } auto AlarmMessageHandler::handleMinuteUpdated() -> void { alarmOperations->minuteUpdated(TimePointNow()); } auto AlarmMessageHandler::addAlarmExecutionHandler(const alarms::AlarmType type, const std::shared_ptr<alarms::AlarmHandler> handler) -> void { alarmOperations->addAlarmExecutionHandler(type, handler); } template <class RequestType, class ResponseType, class CallbackParamType> auto AlarmMessageHandler::handleWithCallback( RequestType *request,
M module-services/service-time/AlarmMessageHandler.hpp => module-services/service-time/AlarmMessageHandler.hpp +4 -0
@@ 29,6 29,10 @@ namespace alarms -> std::shared_ptr<AlarmsGetInRangeResponseMessage>; auto handleGetNextSingleEvents(AlarmGetNextSingleEventsRequestMessage *request) -> std::shared_ptr<AlarmGetNextSingleEventsResponseMessage>; auto handleMinuteUpdated() -> void; auto addAlarmExecutionHandler(const alarms::AlarmType type, const std::shared_ptr<alarms::AlarmHandler> handler) -> void; private: stm::ServiceTime *service = nullptr;
M module-services/service-time/AlarmOperations.cpp => module-services/service-time/AlarmOperations.cpp +98 -5
@@ 3,10 3,22 @@ #include "AlarmOperations.hpp" #include <module-db/Interface/AlarmEventRecord.hpp> #include <module-db/Interface/EventRecord.hpp> namespace alarms { AlarmOperations::AlarmOperations(std::unique_ptr<AbstractAlarmEventsRepository> &&alarmEventsRepo) : alarmEventsRepo{std::move(alarmEventsRepo)} {}; AlarmOperations::AlarmOperations(std::unique_ptr<AbstractAlarmEventsRepository> &&alarmEventsRepo, GetCurrentTime getCurrentTimeCallback) : alarmEventsRepo{std::move(alarmEventsRepo)}, getCurrentTimeCallback{getCurrentTimeCallback} {}; void AlarmOperations::updateEventsCache(TimePoint now) { OnGetNextSingleProcessed callback = [&](std::vector<SingleEventRecord> singleEvents) { nextSingleEvents = std::move(singleEvents); }; getNextSingleEvents(now, callback); } void AlarmOperations::getAlarm(const std::uint32_t alarmId, OnGetAlarmProcessed callback) { @@ 16,18 28,44 @@ namespace alarms void AlarmOperations::addAlarm(AlarmEventRecord record, OnAddAlarmProcessed callback) { OnAddAlarmEventCallback repoCallback = [callback](bool success) { callback(success); }; OnAddAlarmEventCallback repoCallback = [&, callback, record](bool success) mutable { checkAndUpdateCache(record); callback(success); }; alarmEventsRepo->addAlarmEvent(record, repoCallback); } void AlarmOperations::updateAlarm(AlarmEventRecord record, OnUpdateAlarmProcessed callback) { OnUpdateAlarmEventCallback repoCallback = [callback](bool success) { callback(success); }; OnUpdateAlarmEventCallback repoCallback = [&, callback, record](bool success) mutable { auto found = std::find_if(nextSingleEvents.begin(), nextSingleEvents.end(), [recordId = record.ID](const SingleEventRecord &e) { return e.parent->ID == recordId; }); if (found != std::end(nextSingleEvents)) { updateEventsCache(getCurrentTime()); } else { checkAndUpdateCache(record); } callback(success); }; alarmEventsRepo->updateAlarmEvent(record, repoCallback); } void AlarmOperations::removeAlarm(const std::uint32_t alarmId, OnRemoveAlarmProcessed callback) { OnRemoveAlarmEventCallback repoCallback = [callback](bool success) { callback(success); }; OnRemoveAlarmEventCallback repoCallback = [&, callback, alarmId](bool success) { auto found = std::find_if(nextSingleEvents.begin(), nextSingleEvents.end(), [alarmId](const SingleEventRecord &e) { return e.parent->ID == alarmId; }); if (found != std::end(nextSingleEvents) && nextSingleEvents.size() == 1) { updateEventsCache(getCurrentTime()); } callback(success); }; alarmEventsRepo->removeAlarmEvent(alarmId, repoCallback); } @@ 104,4 142,59 @@ namespace alarms } handledCallback(outEvents); } void AlarmOperations::checkAndUpdateCache(AlarmEventRecord record) { auto nearestNewSingleEvent = record.getNextSingleEvent(getCurrentTime()); if (nearestNewSingleEvent.EventInfo::isValid() && nearestNewSingleEvent.startDate > getCurrentTime()) { auto alarmEvent = std::dynamic_pointer_cast<AlarmEventRecord>(nearestNewSingleEvent.parent); if (record.enabled && (nextSingleEvents.empty() || nearestNewSingleEvent.startDate <= nextSingleEvents.front().startDate)) { updateEventsCache(getCurrentTime()); } } } auto AlarmOperations::minuteUpdated(TimePoint now) -> void { if (nextSingleEvents.empty() || nextSingleEvents.front().startDate > now) { return; } executeAlarm(nextSingleEvents.front()); } void AlarmOperations::addAlarmExecutionHandler(const alarms::AlarmType type, const std::shared_ptr<alarms::AlarmHandler> handler) { alarmHandlerFactory.addHandler(type, handler); } void AlarmOperations::executeAlarm(const SingleEventRecord &singleAlarmEvent) { alarms::AlarmType alarmType = alarms::AlarmType::None; if (typeid(*(singleAlarmEvent.parent)) == typeid(AlarmEventRecord)) { alarmType = alarms::AlarmType::Clock; } auto alarmEventPtr = std::dynamic_pointer_cast<AlarmEventRecord>(singleAlarmEvent.parent); if (alarmEventPtr) { auto handler = alarmHandlerFactory.getHandler(alarmType); if (handler) { handler->handle(*alarmEventPtr); } } else { LOG_WARN("Parent type is not AlarmEventRecord!"); } } TimePoint AlarmOperations::getCurrentTime() { if (!getCurrentTimeCallback) { return TIME_POINT_INVALID; } return getCurrentTimeCallback(); } } // namespace alarms
M module-services/service-time/AlarmOperations.hpp => module-services/service-time/AlarmOperations.hpp +29 -4
@@ 5,6 5,8 @@ #include "AlarmRepository.hpp" #include <service-time/AlarmHandlerFactory.hpp> #include <module-db/Interface/AlarmEventRecord.hpp> namespace alarms @@ 22,22 24,32 @@ namespace alarms virtual ~IAlarmOperations() noexcept = default; using GetCurrentTime = std::function<TimePoint()>; virtual void updateEventsCache(TimePoint now) = 0; virtual void getAlarm(const std::uint32_t alarmId, OnGetAlarmProcessed callback) = 0; virtual void addAlarm(AlarmEventRecord record, OnAddAlarmProcessed callback) = 0; virtual void updateAlarm(AlarmEventRecord record, OnUpdateAlarmProcessed callback) = 0; virtual void removeAlarm(const std::uint32_t alarmId, OnRemoveAlarmProcessed callback) = 0; virtual void addAlarm(AlarmEventRecord record, OnAddAlarmProcessed callback) = 0; virtual void updateAlarm(AlarmEventRecord record, OnUpdateAlarmProcessed callback) = 0; virtual void removeAlarm(const std::uint32_t alarmId, OnRemoveAlarmProcessed callback) = 0; virtual void getAlarmsInRange(TimePoint start, TimePoint end, std::uint32_t offset, std::uint32_t limit, OnGetAlarmsInRangeProcessed callback) = 0; virtual void getNextSingleEvents(TimePoint start, OnGetNextSingleProcessed callback) = 0; virtual void minuteUpdated(TimePoint now) = 0; virtual void addAlarmExecutionHandler(const alarms::AlarmType type, const std::shared_ptr<alarms::AlarmHandler> handler) = 0; }; class AlarmOperations : public IAlarmOperations { public: explicit AlarmOperations(std::unique_ptr<AbstractAlarmEventsRepository> &&alarmEventsRepo); explicit AlarmOperations(std::unique_ptr<AbstractAlarmEventsRepository> &&alarmEventsRepo, GetCurrentTime getCurrentTimeCallback); void updateEventsCache(TimePoint now) override; void getAlarm(const std::uint32_t alarmId, OnGetAlarmProcessed callback) override; void addAlarm(AlarmEventRecord record, OnAddAlarmProcessed callback) override; @@ 49,9 61,18 @@ namespace alarms std::uint32_t limit, OnGetAlarmsInRangeProcessed callback) override; void getNextSingleEvents(TimePoint start, OnGetNextSingleProcessed callback) override; void minuteUpdated(TimePoint now) override; void addAlarmExecutionHandler(const alarms::AlarmType type, const std::shared_ptr<alarms::AlarmHandler> handler) override; private: std::unique_ptr<AbstractAlarmEventsRepository> alarmEventsRepo; AlarmHandlerFactory alarmHandlerFactory; // Events we are waiting for (on one timepoint) std::vector<SingleEventRecord> nextSingleEvents; GetCurrentTime getCurrentTimeCallback; // Max 100 alarms for one minute seems reasonable, next events will be dropped constexpr static auto getNextSingleEventsOffset = 0; @@ 66,5 87,9 @@ namespace alarms std::shared_ptr<std::vector<AlarmEventRecord>> nextEvents, TimePoint start, std::vector<AlarmEventRecord> records); void checkAndUpdateCache(AlarmEventRecord record); void executeAlarm(const SingleEventRecord &singleAlarmEvent); TimePoint getCurrentTime(); }; } // namespace alarms
M module-services/service-time/AlarmRepository.hpp => module-services/service-time/AlarmRepository.hpp +3 -3
@@ 10,9 10,9 @@ #include <ctime> #include <vector> class EventRecord; class SingleEvent; class AlarmEventRecord; struct EventRecord; struct SingleEvent; struct AlarmEventRecord; /** * @brief Basic interface alarm API
M module-services/service-time/ServiceTime.cpp => module-services/service-time/ServiceTime.cpp +16 -2
@@ 42,7 42,8 @@ namespace stm timeManager = std::make_unique<TimeManager>(std::make_unique<RTCCommand>(this)); auto alarmEventsRepo = std::make_unique<alarms::AlarmEventsDBRepository>(this); auto alarmOperations = std::make_unique<alarms::AlarmOperations>(std::move(alarmEventsRepo)); auto alarmOperations = std::make_unique<alarms::AlarmOperations>(std::move(alarmEventsRepo), TimePointNow); alarmOperations->updateEventsCache(TimePointNow()); alarmMessageHandler = std::make_unique<alarms::AlarmMessageHandler>(this, std::move(alarmOperations)); } @@ 93,8 94,21 @@ namespace stm } } } return std::make_shared<sys::ResponseMessage>(); if (msgl->messageType == MessageType::EVMMinuteUpdated) { alarmMessageHandler->handleMinuteUpdated(); return std::make_shared<sys::ResponseMessage>(); } else { return std::make_shared<sys::ResponseMessage>(sys::ReturnCodes::Unresolved); } } void ServiceTime::addAlarmExecutionHandler(const alarms::AlarmType type, const std::shared_ptr<alarms::AlarmHandler> handler) { alarmMessageHandler->addAlarmExecutionHandler(type, handler); } void ServiceTime::registerMessageHandlers() { connect(typeid(CellularTimeNotificationMessage), [&](sys::Message *request) -> sys::MessagePointer {
M module-services/service-time/ServiceTime.hpp => module-services/service-time/ServiceTime.hpp +3 -0
@@ 57,6 57,9 @@ namespace stm sys::ReturnCodes SwitchPowerModeHandler(const sys::ServicePowerMode mode) override final; sys::MessagePointer DataReceivedHandler(sys::DataMessage *msgl, sys::ResponseMessage *resp = nullptr) override; void addAlarmExecutionHandler(const alarms::AlarmType type, const std::shared_ptr<alarms::AlarmHandler> handler); }; } /* namespace stm */
M module-services/service-time/include/service-time/AlarmServiceAPI.hpp => module-services/service-time/include/service-time/AlarmServiceAPI.hpp +1 -1
@@ 10,7 10,7 @@ #include <ctime> #include <vector> class AlarmEventRecord; struct AlarmEventRecord; /** * @brief Basic interface alarm API
M module-services/service-time/tests/tests-AlarmOperations.cpp => module-services/service-time/tests/tests-AlarmOperations.cpp +349 -13
@@ 3,11 3,18 @@ #include <AlarmOperations.hpp> #include <AlarmRepository.hpp> #include <service-time/AlarmHandler.hpp> #include <module-db/Interface/AlarmEventRecord.hpp> #include <gtest/gtest.h> #include <gmock/gmock.h> class MockAlarmHandler : public alarms::AlarmHandler { public: MOCK_METHOD(bool, handle, (const AlarmEventRecord &record), ()); }; class MockAlarmEventsRepository : public alarms::AbstractAlarmEventsRepository { public: @@ 30,18 37,47 @@ class MockAlarmEventsRepository : public alarms::AbstractAlarmEventsRepository std::uint32_t limit, const alarms::OnGetAlarmEventsInRangeCallback &callback), ()); MOCK_METHOD(void, addAlarmEvent, (const AlarmEventRecord &alarmEvent, const alarms::OnAddAlarmEventCallback &callback), ()); MOCK_METHOD(void, updateAlarmEvent, (const AlarmEventRecord &alarmEvent, const alarms::OnUpdateAlarmEventCallback &callback), ()); MOCK_METHOD(void, removeAlarmEvent, (const std::uint32_t id, const alarms::OnRemoveAlarmEventCallback &callback), ()); auto addAlarmEvent(const AlarmEventRecord &alarmEvent, const alarms::OnAddAlarmEventCallback &callback) -> void { addSingleEvent(alarmEvent); if (!alarmEvent.rruleText.empty()) { addRecurringEvent(alarmEvent); } callback({true}); } auto updateAlarmEvent(const AlarmEventRecord &alarmEvent, const alarms::OnAddAlarmEventCallback &callback) -> void { nextRecords.erase(std::remove_if(nextRecords.begin(), nextRecords.end(), [&alarmEvent](const AlarmEventRecord &ae) { return ae.ID == alarmEvent.ID; }), nextRecords.end()); recurringRecords.erase( std::remove_if(recurringRecords.begin(), recurringRecords.end(), [&alarmEvent](const AlarmEventRecord &ae) { return ae.ID == alarmEvent.ID; }), recurringRecords.end()); addSingleEvent(alarmEvent); if (!alarmEvent.rruleText.empty()) { addRecurringEvent(alarmEvent); } callback({true}); } auto removeAlarmEvent(const std::uint32_t alarmId, const alarms::OnRemoveAlarmEventCallback &callback) -> void { nextRecords.erase(std::remove_if(nextRecords.begin(), nextRecords.end(), [&alarmId](const AlarmEventRecord &ae) { return ae.ID == alarmId; }), nextRecords.end()); recurringRecords.erase(std::remove_if(recurringRecords.begin(), recurringRecords.end(), [&alarmId](const AlarmEventRecord &ae) { return ae.ID == alarmId; }), recurringRecords.end()); callback({true}); } void getAlarmEventsRecurringInRange(TimePoint start, TimePoint end, std::uint32_t offset, @@ 68,12 104,15 @@ class MockAlarmEventsRepository : public alarms::AbstractAlarmEventsRepository } }; alarms::IAlarmOperations::GetCurrentTime timeInjector = []() { return TimePointFromString("2022-11-11 05:00:00"); }; alarms::IAlarmOperations::OnUpdateAlarmProcessed universalBoolCallback = [](bool success) { EXPECT_EQ(success, true); }; class AlarmOperationsFixture : public ::testing::Test { protected: auto getMockedAlarmOperations(std::unique_ptr<MockAlarmEventsRepository> &alarmRepo) { return std::make_unique<alarms::AlarmOperations>(std::move(alarmRepo)); return std::make_unique<alarms::AlarmOperations>(std::move(alarmRepo), timeInjector); } }; @@ 366,3 405,300 @@ TEST_F(AlarmOperationsFixture, getNextMultipleEventsWithRecursive) auto alarmOperations = getMockedAlarmOperations(alarmRepoMock); alarmOperations->getNextSingleEvents(TimePointFromString("2022-01-01 00:00:00"), callback); } TEST_F(AlarmOperationsFixture, handleFirstEvent) { alarms::IAlarmOperations::OnGetNextSingleProcessed callback = [](std::vector<SingleEventRecord> records) { EXPECT_EQ(records.size(), 1); EXPECT_EQ(records[0].startDate, TimePointFromString("2022-11-11 09:00:00")); EXPECT_EQ(records[0].parent->ID, 1); }; auto alarmRepoMock = std::make_unique<MockAlarmEventsRepository>(); alarmRepoMock->nextRecords.push_back(AlarmEventRecord(1, defName, TimePointFromString("2022-11-11 11:00:00"), defDuration, defAllDay, defRRule, defMusic, defEnabled, defSnooze)); alarmRepoMock->nextRecords.push_back(AlarmEventRecord(2, defName, TimePointFromString("2022-11-11 09:00:00"), defDuration, defAllDay, defRRule, defMusic, defEnabled, defSnooze)); auto alarmOperations = getMockedAlarmOperations(alarmRepoMock); alarmOperations->updateEventsCache(TimePointFromString("2022-11-11 09:00:00")); auto handler = std::make_shared<MockAlarmHandler>(); EXPECT_CALL(*handler, handle(testing::_)).Times(1); alarmOperations->addAlarmExecutionHandler(alarms::AlarmType::Clock, handler); alarmOperations->minuteUpdated(TimePointFromString("2022-11-11 09:00:00")); } TEST_F(AlarmOperationsFixture, handleEventAfterAddCacheChanged) { auto alarmRepoMock = std::make_unique<MockAlarmEventsRepository>(); alarmRepoMock->nextRecords.push_back(AlarmEventRecord(1, defName, TimePointFromString("2022-11-11 15:00:00"), defDuration, defAllDay, defRRule, defMusic, defEnabled, defSnooze)); auto alarmOperations = getMockedAlarmOperations(alarmRepoMock); alarmOperations->updateEventsCache(TimePointFromString("2022-11-11 09:00:00")); alarmOperations->addAlarm(AlarmEventRecord(2, defName, TimePointFromString("2022-11-11 11:00:00"), defDuration, defAllDay, defRRule, defMusic, defEnabled, defSnooze), universalBoolCallback); auto handler = std::make_shared<MockAlarmHandler>(); EXPECT_CALL(*handler, handle(testing::_)).Times(1); alarmOperations->addAlarmExecutionHandler(alarms::AlarmType::Clock, handler); alarmOperations->minuteUpdated(TimePointFromString("2022-11-11 11:00:00")); } TEST_F(AlarmOperationsFixture, handleEventAfterAddCacheNotChanged) { auto alarmRepoMock = std::make_unique<MockAlarmEventsRepository>(); alarmRepoMock->nextRecords.push_back(AlarmEventRecord(1, defName, TimePointFromString("2022-11-11 15:00:00"), defDuration, defAllDay, defRRule, defMusic, defEnabled, defSnooze)); auto alarmOperations = getMockedAlarmOperations(alarmRepoMock); alarmOperations->updateEventsCache(TimePointFromString("2022-11-11 09:00:00")); alarmOperations->addAlarm(AlarmEventRecord(2, defName, TimePointFromString("2022-11-11 17:00:00"), defDuration, defAllDay, defRRule, defMusic, defEnabled, defSnooze), universalBoolCallback); auto handler = std::make_shared<MockAlarmHandler>(); EXPECT_CALL(*handler, handle(testing::_)).Times(1); alarmOperations->addAlarmExecutionHandler(alarms::AlarmType::Clock, handler); alarmOperations->minuteUpdated(TimePointFromString("2022-11-11 15:00:00")); } TEST_F(AlarmOperationsFixture, handleEventAfterAddCacheNotChanged2) { auto alarmRepoMock = std::make_unique<MockAlarmEventsRepository>(); alarmRepoMock->nextRecords.push_back(AlarmEventRecord(1, defName, TimePointFromString("2022-11-11 15:00:00"), defDuration, defAllDay, defRRule, defMusic, defEnabled, defSnooze)); auto alarmOperations = getMockedAlarmOperations(alarmRepoMock); alarmOperations->updateEventsCache(TimePointFromString("2022-11-11 09:00:00")); alarmOperations->addAlarm(AlarmEventRecord(2, defName, TimePointFromString("2022-11-10 12:00:00"), defDuration, defAllDay, defRRule, defMusic, defEnabled, defSnooze), universalBoolCallback); auto handler = std::make_shared<MockAlarmHandler>(); EXPECT_CALL(*handler, handle(testing::_)).Times(1); alarmOperations->addAlarmExecutionHandler(alarms::AlarmType::Clock, handler); alarmOperations->minuteUpdated(TimePointFromString("2022-11-11 15:00:00")); } TEST_F(AlarmOperationsFixture, handleEventAfterAddDisabled) { auto alarmRepoMock = std::make_unique<MockAlarmEventsRepository>(); alarmRepoMock->nextRecords.push_back(AlarmEventRecord(1, defName, TimePointFromString("2022-11-11 15:00:00"), defDuration, defAllDay, defRRule, defMusic, defEnabled, defSnooze)); auto alarmOperations = getMockedAlarmOperations(alarmRepoMock); alarmOperations->updateEventsCache(TimePointFromString("2022-11-11 09:00:00")); alarmOperations->addAlarm(AlarmEventRecord(2, defName, TimePointFromString("2022-11-11 11:00:00"), defDuration, defAllDay, defRRule, defMusic, false, defSnooze), universalBoolCallback); auto handler = std::make_shared<MockAlarmHandler>(); EXPECT_CALL(*handler, handle(testing::_)).Times(1); alarmOperations->addAlarmExecutionHandler(alarms::AlarmType::Clock, handler); alarmOperations->minuteUpdated(TimePointFromString("2022-11-11 15:00:00")); } TEST_F(AlarmOperationsFixture, handleAfterRemoveNearest) { auto alarmRepoMock = std::make_unique<MockAlarmEventsRepository>(); alarmRepoMock->nextRecords.push_back(AlarmEventRecord(1, defName, TimePointFromString("2022-11-11 11:00:00"), defDuration, defAllDay, defRRule, defMusic, defEnabled, defSnooze)); alarmRepoMock->nextRecords.push_back(AlarmEventRecord(2, defName, TimePointFromString("2022-11-11 09:00:00"), defDuration, defAllDay, defRRule, defMusic, defEnabled, defSnooze)); auto alarmOperations = getMockedAlarmOperations(alarmRepoMock); alarmOperations->updateEventsCache(TimePointFromString("2022-11-11 09:00:00")); alarmOperations->removeAlarm(2, universalBoolCallback); auto handler = std::make_shared<MockAlarmHandler>(); EXPECT_CALL(*handler, handle(testing::_)).Times(1); alarmOperations->addAlarmExecutionHandler(alarms::AlarmType::Clock, handler); alarmOperations->minuteUpdated(TimePointFromString("2022-11-11 11:00:00")); } TEST_F(AlarmOperationsFixture, handleAfterRemoveNotNearest) { auto alarmRepoMock = std::make_unique<MockAlarmEventsRepository>(); alarmRepoMock->nextRecords.push_back(AlarmEventRecord(1, defName, TimePointFromString("2022-11-11 11:00:00"), defDuration, defAllDay, defRRule, defMusic, defEnabled, defSnooze)); alarmRepoMock->nextRecords.push_back(AlarmEventRecord(2, defName, TimePointFromString("2022-11-11 09:00:00"), defDuration, defAllDay, defRRule, defMusic, defEnabled, defSnooze)); auto alarmOperations = getMockedAlarmOperations(alarmRepoMock); alarmOperations->updateEventsCache(TimePointFromString("2022-11-11 09:00:00")); alarmOperations->removeAlarm(1, universalBoolCallback); auto handler = std::make_shared<MockAlarmHandler>(); EXPECT_CALL(*handler, handle(testing::_)).Times(1); alarmOperations->addAlarmExecutionHandler(alarms::AlarmType::Clock, handler); alarmOperations->minuteUpdated(TimePointFromString("2022-11-11 09:00:00")); } TEST_F(AlarmOperationsFixture, handleAfterUpdateNearestDelayed) { auto alarmRepoMock = std::make_unique<MockAlarmEventsRepository>(); alarmRepoMock->nextRecords.push_back(AlarmEventRecord(1, defName, TimePointFromString("2022-11-11 11:00:00"), defDuration, defAllDay, defRRule, defMusic, defEnabled, defSnooze)); auto nearestAlarm = AlarmEventRecord(2, defName, TimePointFromString("2022-11-11 09:00:00"), defDuration, defAllDay, defRRule, defMusic, defEnabled, defSnooze); alarmRepoMock->nextRecords.push_back(nearestAlarm); auto alarmOperations = getMockedAlarmOperations(alarmRepoMock); alarmOperations->updateEventsCache(TimePointFromString("2022-11-11 09:00:00")); nearestAlarm.startDate = TimePointFromString("2022-11-11 15:00:00"); alarmOperations->updateAlarm(nearestAlarm, universalBoolCallback); auto handler = std::make_shared<MockAlarmHandler>(); EXPECT_CALL(*handler, handle(testing::_)).Times(1); alarmOperations->addAlarmExecutionHandler(alarms::AlarmType::Clock, handler); alarmOperations->minuteUpdated(TimePointFromString("2022-11-11 11:00:00")); } TEST_F(AlarmOperationsFixture, handleAfterUpdateSecondGetsFirst) { auto alarmRepoMock = std::make_unique<MockAlarmEventsRepository>(); auto secondAlarm = AlarmEventRecord(1, defName, TimePointFromString("2022-11-11 11:00:00"), defDuration, defAllDay, defRRule, defMusic, defEnabled, defSnooze); alarmRepoMock->nextRecords.push_back(secondAlarm); alarmRepoMock->nextRecords.push_back(AlarmEventRecord(2, defName, TimePointFromString("2022-11-11 09:00:00"), defDuration, defAllDay, defRRule, defMusic, defEnabled, defSnooze)); auto alarmOperations = getMockedAlarmOperations(alarmRepoMock); alarmOperations->updateEventsCache(TimePointFromString("2022-11-11 09:00:00")); secondAlarm.startDate = TimePointFromString("2022-11-11 7:00:00"); alarmOperations->updateAlarm(secondAlarm, universalBoolCallback); auto handler = std::make_shared<MockAlarmHandler>(); EXPECT_CALL(*handler, handle(testing::_)).Times(1); alarmOperations->addAlarmExecutionHandler(alarms::AlarmType::Clock, handler); alarmOperations->minuteUpdated(TimePointFromString("2022-11-11 7:00:00")); }