From d713e3ba29ddf954c9cc27c02a8ac9c329a9b8d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 7 Apr 2016 23:44:12 +0200 Subject: [PATCH] add store load timeDescriptor --- libguh/guhsettings.cpp | 20 +++ libguh/guhsettings.h | 5 + server/ruleengine.cpp | 171 ++++++++++++++++++++- tests/auto/timemanager/testtimemanager.cpp | 160 ++++++++++++++++++- 4 files changed, 347 insertions(+), 9 deletions(-) diff --git a/libguh/guhsettings.cpp b/libguh/guhsettings.cpp index db326861..481848af 100644 --- a/libguh/guhsettings.cpp +++ b/libguh/guhsettings.cpp @@ -209,6 +209,26 @@ QStringList GuhSettings::allKeys() const return m_settings->allKeys(); } +void GuhSettings::beginWriteArray(const QString &prefix) +{ + m_settings->beginWriteArray(prefix); +} + +void GuhSettings::setArrayIndex(int i) +{ + m_settings->setArrayIndex(i); +} + +int GuhSettings::beginReadArray(const QString &prefix) +{ + return m_settings->beginReadArray(prefix); +} + +void GuhSettings::endArray() +{ + m_settings->endArray(); +} + /*! Begins a new group with the given \a prefix.*/ void GuhSettings::beginGroup(const QString &prefix) { diff --git a/libguh/guhsettings.h b/libguh/guhsettings.h index 5c960114..5ccb2ba1 100644 --- a/libguh/guhsettings.h +++ b/libguh/guhsettings.h @@ -52,6 +52,11 @@ public: // forwarded QSettings methods QStringList allKeys() const; + void beginWriteArray(const QString &prefix); + void setArrayIndex(int i); + int beginReadArray(const QString &prefix); + + void endArray(); void beginGroup(const QString &prefix); QStringList childGroups() const; QStringList childKeys() const; diff --git a/server/ruleengine.cpp b/server/ruleengine.cpp index 93b32ca8..a5d54e62 100644 --- a/server/ruleengine.cpp +++ b/server/ruleengine.cpp @@ -99,13 +99,15 @@ #include "ruleengine.h" -#include "loggingcategories.h" -#include "types/paramdescriptor.h" -#include "types/eventdescriptor.h" -#include "guhsettings.h" - #include "guhcore.h" +#include "loggingcategories.h" +#include "time/calendaritem.h" +#include "time/repeatingoption.h" +#include "time/timeeventitem.h" +#include "types/eventdescriptor.h" +#include "types/paramdescriptor.h" +#include "guhsettings.h" #include "devicemanager.h" #include "plugin/device.h" @@ -133,9 +135,93 @@ RuleEngine::RuleEngine(QObject *parent) : qCDebug(dcRuleEngine) << "load rule" << name << idString; + // Load timeDescriptor + TimeDescriptor timeDescriptor; + QList calendarItems; + QList timeEventItems; + + settings.beginGroup("timeDescriptor"); + + settings.beginGroup("calendarItems"); + foreach (const QString &childGroup, settings.childGroups()) { + settings.beginGroup(childGroup); + + CalendarItem calendarItem; + calendarItem.setDateTime(QDateTime::fromTime_t(settings.value("dateTime", 0).toUInt())); + calendarItem.setStartTime(QTime::fromString(settings.value("startTime").toString())); + calendarItem.setDuration(settings.value("duration", 0).toUInt()); + + QList weekDays; + QList monthDays; + RepeatingOption::RepeatingMode mode = (RepeatingOption::RepeatingMode)settings.value("mode", 0).toInt(); + + // Load weekDays + int weekDaysCount = settings.beginReadArray("weekDays"); + for (int i = 0; i < weekDaysCount; ++i) { + settings.setArrayIndex(i); + weekDays.append(settings.value("weekDay", 0).toInt()); + } + settings.endArray(); + + // Load weekDays + int monthDaysCount = settings.beginReadArray("monthDays"); + for (int i = 0; i < monthDaysCount; ++i) { + settings.setArrayIndex(i); + monthDays.append(settings.value("monthDay", 0).toInt()); + } + settings.endArray(); + + settings.endGroup(); + + calendarItem.setRepeatingOption(RepeatingOption(mode, weekDays, monthDays)); + calendarItems.append(calendarItem); + } + settings.endGroup(); + + timeDescriptor.setCalendarItems(calendarItems); + + settings.beginGroup("timeEventItems"); + foreach (const QString &childGroup, settings.childGroups()) { + settings.beginGroup(childGroup); + + TimeEventItem timeEventItem; + timeEventItem.setDateTime(settings.value("dateTime", 0).toUInt()); + timeEventItem.setTime(QTime::fromString(settings.value("time").toString())); + + QList weekDays; + QList monthDays; + RepeatingOption::RepeatingMode mode = (RepeatingOption::RepeatingMode)settings.value("mode", 0).toInt(); + + // Load weekDays + int weekDaysCount = settings.beginReadArray("weekDays"); + for (int i = 0; i < weekDaysCount; ++i) { + settings.setArrayIndex(i); + weekDays.append(settings.value("weekDay", 0).toInt()); + } + settings.endArray(); + + // Load weekDays + int monthDaysCount = settings.beginReadArray("monthDays"); + for (int i = 0; i < monthDaysCount; ++i) { + settings.setArrayIndex(i); + monthDays.append(settings.value("monthDay", 0).toInt()); + } + settings.endArray(); + + settings.endGroup(); + + timeEventItem.setRepeatingOption(RepeatingOption(mode, weekDays, monthDays)); + timeEventItems.append(timeEventItem); + } + settings.endGroup(); + + settings.endGroup(); + + timeDescriptor.setTimeEventItems(timeEventItems); + + // Load events QList eventDescriptorList; settings.beginGroup("events"); - foreach (QString eventGroupName, settings.childGroups()) { if (eventGroupName.startsWith("EventDescriptor-")) { settings.beginGroup(eventGroupName); @@ -160,8 +246,12 @@ RuleEngine::RuleEngine(QObject *parent) : } settings.endGroup(); + settings.endGroup(); + + // Load stateEvaluator StateEvaluator stateEvaluator = StateEvaluator::loadFromSettings(settings, "stateEvaluator"); - + + // Load actions QList actions; settings.beginGroup("ruleActions"); foreach (const QString &actionNumber, settings.childGroups()) { @@ -190,6 +280,7 @@ RuleEngine::RuleEngine(QObject *parent) : } settings.endGroup(); + // Load exit actions QList exitActions; settings.beginGroup("ruleExitActions"); foreach (const QString &actionNumber, settings.childGroups()) { @@ -216,6 +307,7 @@ RuleEngine::RuleEngine(QObject *parent) : Rule rule; rule.setId(RuleId(idString)); rule.setName(name); + rule.setTimeDescriptor(timeDescriptor); rule.setEventDescriptors(eventDescriptorList); rule.setStateEvaluator(stateEvaluator); rule.setActions(actions); @@ -917,12 +1009,75 @@ void RuleEngine::appendRule(const Rule &rule) void RuleEngine::saveRule(const Rule &rule) { - // Save Events / EventDescriptors GuhSettings settings(GuhSettings::SettingsRoleRules); settings.beginGroup(rule.id().toString()); settings.setValue("name", rule.name()); settings.setValue("enabled", rule.enabled()); settings.setValue("executable", rule.executable()); + + // Save timeDescriptor + settings.beginGroup("timeDescriptor"); + if (!rule.timeDescriptor().isEmpty()) { + settings.beginGroup("calendarItems"); + for (int i = 0; i < rule.timeDescriptor().calendarItems().count(); i++) { + const CalendarItem &calendarItem = rule.timeDescriptor().calendarItems().at(i); + settings.beginGroup("CalendarItem-" + QString::number(i)); + settings.setValue("dateTime", calendarItem.dateTime().toTime_t()); + settings.setValue("startTime", calendarItem.startTime().toString("hh:mm")); + settings.setValue("duration", calendarItem.duration()); + settings.setValue("mode", calendarItem.repeatingOption().mode()); + + // Save weekDays + settings.beginWriteArray("weekDays"); + for (int i = 0; i < calendarItem.repeatingOption().weekDays().count(); ++i) { + settings.setArrayIndex(i); + settings.setValue("weekDay", calendarItem.repeatingOption().weekDays().at(i)); + } + settings.endArray(); + + // Save monthDays + settings.beginWriteArray("monthDays"); + for (int i = 0; i < calendarItem.repeatingOption().monthDays().count(); ++i) { + settings.setArrayIndex(i); + settings.setValue("monthDay", calendarItem.repeatingOption().monthDays().at(i)); + } + settings.endArray(); + + settings.endGroup(); + } + settings.endGroup(); + + settings.beginGroup("timeEventItems"); + for (int i = 0; i < rule.timeDescriptor().timeEventItems().count(); i++) { + const TimeEventItem &timeEventItem = rule.timeDescriptor().timeEventItems().at(i); + settings.beginGroup("TimeEventItem-" + QString::number(i)); + settings.setValue("dateTime", timeEventItem.dateTime().toTime_t()); + settings.setValue("time", timeEventItem.time().toString("hh:mm")); + settings.setValue("mode", timeEventItem.repeatingOption().mode()); + + // Save weekDays + settings.beginWriteArray("weekDays"); + for (int i = 0; i < timeEventItem.repeatingOption().weekDays().count(); ++i) { + settings.setArrayIndex(i); + settings.setValue("weekDay", timeEventItem.repeatingOption().weekDays().at(i)); + } + settings.endArray(); + + // Save monthDays + settings.beginWriteArray("monthDays"); + for (int i = 0; i < timeEventItem.repeatingOption().monthDays().count(); ++i) { + settings.setArrayIndex(i); + settings.setValue("monthDay", timeEventItem.repeatingOption().monthDays().at(i)); + } + settings.endArray(); + + settings.endGroup(); + } + settings.endGroup(); + } + settings.endGroup(); + + // Save Events / EventDescriptors settings.beginGroup("events"); for (int i = 0; i < rule.eventDescriptors().count(); i++) { const EventDescriptor &eventDescriptor = rule.eventDescriptors().at(i); diff --git a/tests/auto/timemanager/testtimemanager.cpp b/tests/auto/timemanager/testtimemanager.cpp index 889ae8f0..ac991f32 100644 --- a/tests/auto/timemanager/testtimemanager.cpp +++ b/tests/auto/timemanager/testtimemanager.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -43,6 +44,9 @@ private slots: void changeTimeZone_data(); void changeTimeZone(); + void loadSaveTimeDescriptor_data(); + void loadSaveTimeDescriptor(); + void addTimeDescriptor_data(); void addTimeDescriptor(); @@ -84,6 +88,8 @@ private slots: void testEventItemYearly_data(); void testEventItemYearly(); + void testEnableDisableTimeRule(); + private: void initTimeManager(); @@ -140,6 +146,95 @@ void TestTimeManager::changeTimeZone() } +void TestTimeManager::loadSaveTimeDescriptor_data() +{ + // Repeating options + QVariantMap repeatingOptionWeekly; + repeatingOptionWeekly.insert("mode", "RepeatingModeWeekly"); + repeatingOptionWeekly.insert("weekDays", QVariantList() << 2 << 4 << 5); + + QVariantMap repeatingOptionMonthly; + repeatingOptionMonthly.insert("mode", "RepeatingModeMonthly"); + repeatingOptionMonthly.insert("monthDays", QVariantList() << 20 << 14 << 5); + + QVariantMap repeatingOptionYearly; + repeatingOptionYearly.insert("mode", "RepeatingModeYearly"); + + QVariantList calendarItems; + calendarItems.append(createCalendarItem("12:10", 20, repeatingOptionWeekly)); + calendarItems.append(createCalendarItem("23:33", 11, repeatingOptionMonthly)); + calendarItems.append(createCalendarItem(QDateTime::currentDateTime().toTime_t(), 50, repeatingOptionYearly)); + + QVariantList timeEventItems; + timeEventItems.append(createTimeEventItem(QDateTime::currentDateTime().toTime_t(), repeatingOptionYearly)); + timeEventItems.append(createTimeEventItem("13:12", repeatingOptionWeekly)); + timeEventItems.append(createTimeEventItem("18:45", repeatingOptionMonthly)); + + QTest::addColumn("timeDescriptor"); + + QTest::newRow("calendarItems") << createTimeDescriptorCalendar(calendarItems); + QTest::newRow("timeEventItems") << createTimeDescriptorTimeEvent(timeEventItems); +} + +void TestTimeManager::loadSaveTimeDescriptor() +{ + QFETCH(QVariantMap, timeDescriptor); + + initTimeManager(); + + // Action (without params) + QVariantMap ruleMap; QVariantMap action; QVariantMap exitAction; + action.insert("actionTypeId", mockActionIdNoParams); + action.insert("deviceId", m_mockDeviceId); + action.insert("ruleActionParams", QVariantList()); + + // Exit action (with params) + QVariantList actionParams; + QVariantMap param1; + param1.insert("name", "mockActionParam1"); + param1.insert("value", 12); + actionParams.append(param1); + QVariantMap param2; + param2.insert("name", "mockActionParam2"); + param2.insert("value", true); + actionParams.append(param2); + exitAction.insert("actionTypeId", mockActionIdWithParams); + exitAction.insert("deviceId", m_mockDeviceId); + exitAction.insert("ruleActionParams", actionParams); + + // Create the rule map + ruleMap.insert("name", "Time based weekly calendar rule"); + ruleMap.insert("timeDescriptor", timeDescriptor); + ruleMap.insert("actions", QVariantList() << action); + ruleMap.insert("exitActions", QVariantList() << exitAction); + + // Add the rule + QVariant response = injectAndWait("Rules.AddRule", ruleMap); + verifyRuleError(response); + RuleId ruleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toString()); + + QVariantMap params; + params.insert("ruleId", ruleId); + response = injectAndWait("Rules.GetRuleDetails", params); + verifyRuleError(response); + + QVariantMap timeDescriptorMap = response.toMap().value("params").toMap().value("rule").toMap().value("timeDescriptor").toMap(); + qDebug() << QJsonDocument::fromVariant(timeDescriptorMap).toJson(); + + // Restart the server + restartServer(); + + // Get the loaded rule + response = injectAndWait("Rules.GetRuleDetails", params); + verifyRuleError(response); + + QVariantMap timeDescriptorMapLoaded = response.toMap().value("params").toMap().value("rule").toMap().value("timeDescriptor").toMap(); + qDebug() << QJsonDocument::fromVariant(timeDescriptorMapLoaded).toJson(); + + QCOMPARE(timeDescriptorMap, timeDescriptorMapLoaded); + +} + void TestTimeManager::addTimeDescriptor_data() { // valid RepeatingOptions @@ -267,7 +362,6 @@ void TestTimeManager::addTimeDescriptor() if (error != RuleEngine::RuleErrorNoError) return; - // Print rule RuleId newRuleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toString()); // REMOVE rule @@ -1363,6 +1457,70 @@ void TestTimeManager::testEventItemYearly() verifyRuleError(response); } +void TestTimeManager::testEnableDisableTimeRule() +{ + initTimeManager(); + QDateTime dateTime(QDate::currentDate(), QTime(10,15)); + + // Repeating option + QVariantMap repeatingOptionDaily; + repeatingOptionDaily.insert("mode", "RepeatingModeDaily"); + + // Action + QVariantMap action; + action.insert("actionTypeId", mockActionIdNoParams); + action.insert("deviceId", m_mockDeviceId); + action.insert("ruleActionParams", QVariantList()); + + QVariantMap ruleMap; + ruleMap.insert("name", "Time based daily event rule"); + ruleMap.insert("actions", QVariantList() << action); + ruleMap.insert("timeDescriptor", createTimeDescriptorTimeEvent(createTimeEventItem(dateTime.time().toString("hh:mm"), repeatingOptionDaily))); + + + QVariant response = injectAndWait("Rules.AddRule", ruleMap); + verifyRuleError(response); + RuleId ruleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toString()); + + // not triggering + GuhCore::instance()->timeManager()->setTime(dateTime.addMSecs(-60)); + verifyRuleNotExecuted(); + // trigger + GuhCore::instance()->timeManager()->setTime(dateTime); + verifyRuleExecuted(mockActionIdNoParams); + cleanupMockHistory(); + // not triggering + GuhCore::instance()->timeManager()->setTime(dateTime.addMSecs(60)); + verifyRuleNotExecuted(); + + + // Now DISABLE the rule + QVariantMap enableDisableParams; + enableDisableParams.insert("ruleId", ruleId.toString()); + response = injectAndWait("Rules.DisableRule", enableDisableParams); + verifyRuleError(response); + + // trigger + GuhCore::instance()->timeManager()->setTime(dateTime); + verifyRuleNotExecuted(); + + // Now ENABLE the rule again + response.clear(); + response = injectAndWait("Rules.EnableRule", enableDisableParams); + verifyRuleError(response); + + // trigger + GuhCore::instance()->timeManager()->setTime(dateTime); + verifyRuleExecuted(mockActionIdNoParams); + cleanupMockHistory(); + + // REMOVE rule + QVariantMap removeParams; + removeParams.insert("ruleId", ruleId); + response = injectAndWait("Rules.RemoveRule", removeParams); + verifyRuleError(response); +} + void TestTimeManager::initTimeManager() { GuhCore::instance()->timeManager()->stopTimer();