nymea/tests/auto/timemanager/testtimemanager.cpp

2252 lines
94 KiB
C++

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stürz <simon.stuerz@guh.io> *
* Copyright (C) 2014 Michael Zanetti <michael_zanetti@gmx.net> *
* *
* This file is part of nymea. *
* *
* nymea is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
**
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with nymea. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "nymeatestbase.h"
#include "nymeacore.h"
#include "servers/mocktcpserver.h"
using namespace nymeaserver;
class TestTimeManager: public NymeaTestBase
{
Q_OBJECT
private slots:
void initTestCase();
void changeTimeZone_data();
void changeTimeZone();
void loadSaveTimeDescriptor_data();
void loadSaveTimeDescriptor();
void addTimeDescriptor_data();
void addTimeDescriptor();
// CalendarItems
void testCalendarDateTime_data();
void testCalendarDateTime();
void testCalendarItemHourly_data();
void testCalendarItemHourly();
void testCalendarItemDaily_data();
void testCalendarItemDaily();
void testCalendarItemWeekly_data();
void testCalendarItemWeekly();
void testCalendarItemMonthly_data();
void testCalendarItemMonthly();
void testCalendarYearlyDateTime_data();
void testCalendarYearlyDateTime();
void testCalendarItemStates_data();
void testCalendarItemStates();
void testCalendarItemEvent_data();
void testCalendarItemEvent();
void testCalendarItemStatesEvent_data();
void testCalendarItemStatesEvent();
void testCalendarItemCrossesMidnight();
void testEventBasedWithCalendarItemCrossingMidnight();
// TimeEventItems
void testEventItemDateTime_data();
void testEventItemDateTime();
void testEventItemHourly_data();
void testEventItemHourly();
void testEventItemDaily_data();
void testEventItemDaily();
void testEventItemWeekly_data();
void testEventItemWeekly();
void testEventItemMonthly_data();
void testEventItemMonthly();
void testEventItemYearly_data();
void testEventItemYearly();
void testEventItemStates_data();
void testEventItemStates();
void testEnableDisableTimeRule();
private:
void initTimeManager();
void verifyRuleExecuted(const ActionTypeId &actionTypeId);
void verifyRuleNotExecuted();
void cleanupMockHistory();
void removeAllRules();
void setIntState(const int &value);
void setBoolState(const bool &value);
void triggerMockEvent1();
QVariantMap createTimeEventItem(const QString &time = QString(), const QVariantMap &repeatingOption = QVariantMap()) const;
QVariantMap createTimeEventItem(const int &dateTime, const QVariantMap &repeatingOption = QVariantMap()) const;
QVariantMap createTimeDescriptorTimeEvent(const QVariantMap &timeEventItem) const;
QVariantMap createTimeDescriptorTimeEvent(const QVariantList &timeEventItems) const;
QVariantMap createCalendarItem(const QString &time = QString(), const uint &duration = 0, const QVariantMap &repeatingOption = QVariantMap()) const;
QVariantMap createCalendarItem(const int &dateTime, const uint &duration = 0, const QVariantMap &repeatingOption = QVariantMap()) const;
QVariantMap createTimeDescriptorCalendar(const QVariantMap &calendarItem) const;
QVariantMap createTimeDescriptorCalendar(const QVariantList &calendarItems) const;
};
void TestTimeManager::initTestCase()
{
NymeaTestBase::initTestCase();
QLoggingCategory::setFilterRules("*.debug=false\n"
"Tests.debug=true\n"
"RuleEngine.debug=true\n"
// "RuleEngineDebug.debug=true\n"
"MockDevice.debug=true\n"
"JsonRpc.debug=true\n"
"TimeManager.debug=true");
}
void TestTimeManager::changeTimeZone_data()
{
QTest::addColumn<QByteArray>("timeZoneId");
QTest::addColumn<bool>("valid");
QTest::newRow("valid timezone: Asia/Tokyo") << QByteArray("Asia/Tokyo") << true;
QTest::newRow("valid timezone: America/Lima") << QByteArray("America/Lima") << true;
QTest::newRow("valid timezone: Africa/Harare") << QByteArray("Africa/Harare") << true;
QTest::newRow("invalid timezone: Mars/Diacria") << QByteArray("Mars/Diacria") << false;
QTest::newRow("invalid timezone: Moon/Kepler") << QByteArray("Moon/Kepler") << false;
}
void TestTimeManager::changeTimeZone()
{
QFETCH(QByteArray, timeZoneId);
QFETCH(bool, valid);
QTimeZone currentTimeZone(NymeaCore::instance()->timeManager()->timeZone());
QTimeZone newTimeZone(timeZoneId);
QDateTime currentDateTime = NymeaCore::instance()->timeManager()->currentDateTime();
NymeaCore::instance()->timeManager()->setTimeZone(timeZoneId);
QDateTime newDateTime = NymeaCore::instance()->timeManager()->currentDateTime();
int offsetOriginal = currentTimeZone.offsetFromUtc(currentDateTime);
int offsetNew = newTimeZone.offsetFromUtc(newDateTime);
if (valid)
QVERIFY(offsetOriginal != offsetNew);
}
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<QVariantMap>("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;
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
action.insert("deviceId", m_mockDeviceId);
action.insert("ruleActionParams", QVariantList());
// Create the rule map
ruleMap.insert("name", "Time based weekly calendar rule");
ruleMap.insert("timeDescriptor", timeDescriptor);
ruleMap.insert("actions", QVariantList() << action);
// 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();
// 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();
QCOMPARE(timeDescriptorMap, timeDescriptorMapLoaded);
// REMOVE rule
QVariantMap removeParams;
removeParams.insert("ruleId", ruleId);
response = injectAndWait("Rules.RemoveRule", removeParams);
verifyRuleError(response);
}
void TestTimeManager::addTimeDescriptor_data()
{
// valid RepeatingOptions
QVariantMap repeatingOptionDaily;
repeatingOptionDaily.insert("mode", "RepeatingModeDaily");
QVariantMap repeatingOptionNone;
repeatingOptionNone.insert("mode", "RepeatingModeNone");
QVariantMap repeatingOptionHourly;
repeatingOptionHourly.insert("mode", "RepeatingModeHourly");
QVariantMap repeatingOptionWeeklyMultiple;
repeatingOptionWeeklyMultiple.insert("mode", "RepeatingModeWeekly");
repeatingOptionWeeklyMultiple.insert("weekDays", QVariantList() << 2 << 4 << 5);
QVariantMap repeatingOptionMonthlyMultiple;
repeatingOptionMonthlyMultiple.insert("mode", "RepeatingModeMonthly");
repeatingOptionMonthlyMultiple.insert("monthDays", QVariantList() << 20 << 14 << 5);
QVariantMap repeatingOptionYearly;
repeatingOptionYearly.insert("mode", "RepeatingModeYearly");
// invalid RepeatingOptions
QVariantMap repeatingOptionInvalidNone;
repeatingOptionInvalidNone.insert("mode", "RepeatingModeNone");
repeatingOptionInvalidNone.insert("monthDays", QVariantList() << 13 << 12 << 27);
QVariantMap repeatingOptionInvalidWeekly;
repeatingOptionInvalidWeekly.insert("mode", "RepeatingModeWeekly");
repeatingOptionInvalidWeekly.insert("monthDays", QVariantList() << 12 << 2 << 7);
QVariantMap repeatingOptionInvalidMonthly;
repeatingOptionInvalidMonthly.insert("mode", "RepeatingModeMonthly");
repeatingOptionInvalidMonthly.insert("weekDays", QVariantList() << 1 << 2 << 7);
QVariantMap repeatingOptionInvalidWeekDays;
repeatingOptionInvalidWeekDays.insert("mode", "RepeatingModeWeekly");
repeatingOptionInvalidWeekDays.insert("weekDays", QVariantList() << -1);
QVariantMap repeatingOptionInvalidWeekDays2;
repeatingOptionInvalidWeekDays2.insert("mode", "RepeatingModeWeekly");
repeatingOptionInvalidWeekDays2.insert("weekDays", QVariantList() << 8);
QVariantMap repeatingOptionInvalidMonthDays;
repeatingOptionInvalidMonthDays.insert("mode", "RepeatingModeMonthly");
repeatingOptionInvalidMonthDays.insert("monthDays", QVariantList() << -1);
QVariantMap repeatingOptionInvalidMonthDays2;
repeatingOptionInvalidMonthDays2.insert("mode", "RepeatingModeMonthly");
repeatingOptionInvalidMonthDays2.insert("monthDays", QVariantList() << 32);
// Multiple calendar items
QVariantList calendarItems;
calendarItems.append(createCalendarItem("08:00", 5, repeatingOptionDaily));
calendarItems.append(createCalendarItem("09:00", 5, repeatingOptionWeeklyMultiple));
// Multiple timeEvent items
QVariantList timeEventItems;
timeEventItems.append(createTimeEventItem("08:00", repeatingOptionDaily));
timeEventItems.append(createTimeEventItem("09:00", repeatingOptionWeeklyMultiple));
QTest::addColumn<QVariantMap>("timeDescriptor");
QTest::addColumn<RuleEngine::RuleError>("error");
QTest::newRow("valid: calendarItem") << createTimeDescriptorCalendar(createCalendarItem("08:00", 5)) << RuleEngine::RuleErrorNoError;
QTest::newRow("valid: calendarItem dateTime") << createTimeDescriptorCalendar(createCalendarItem(QDateTime::currentDateTime().toTime_t(), 5)) << RuleEngine::RuleErrorNoError;
QTest::newRow("valid: calendarItem dateTime - yearly") << createTimeDescriptorCalendar(createCalendarItem(QDateTime::currentDateTime().toTime_t(), 5, repeatingOptionYearly)) << RuleEngine::RuleErrorNoError;
QTest::newRow("valid: calendarItem - daily") << createTimeDescriptorCalendar(createCalendarItem("08:00", 5, repeatingOptionDaily)) << RuleEngine::RuleErrorNoError;
QTest::newRow("valid: calendarItem - none") << createTimeDescriptorCalendar(createCalendarItem("09:00", 30, repeatingOptionNone)) << RuleEngine::RuleErrorNoError;
QTest::newRow("valid: calendarItem - hourly") << createTimeDescriptorCalendar(createCalendarItem("09:00", 30, repeatingOptionHourly)) << RuleEngine::RuleErrorNoError;
QTest::newRow("valid: calendarItems - weekly - multiple days") << createTimeDescriptorCalendar(calendarItems) << RuleEngine::RuleErrorNoError;
QTest::newRow("valid: calendarItem - monthly - multiple days") << createTimeDescriptorCalendar(createCalendarItem("23:00", 5, repeatingOptionMonthlyMultiple)) << RuleEngine::RuleErrorNoError;
QTest::newRow("valid: timeEventItem") << createTimeDescriptorTimeEvent(createTimeEventItem("08:00")) << RuleEngine::RuleErrorNoError;
QTest::newRow("valid: timeEventItem dateTime") << createTimeDescriptorTimeEvent(createTimeEventItem(QDateTime::currentDateTime().toTime_t())) << RuleEngine::RuleErrorNoError;
QTest::newRow("valid: timeEventItem dateTime - yearly") << createTimeDescriptorTimeEvent(createTimeEventItem(QDateTime::currentDateTime().toTime_t(), repeatingOptionYearly)) << RuleEngine::RuleErrorNoError;
QTest::newRow("valid: timeEventItem - daily") << createTimeDescriptorTimeEvent(createTimeEventItem("08:00", repeatingOptionDaily)) << RuleEngine::RuleErrorNoError;
QTest::newRow("valid: timeEventItem - none") << createTimeDescriptorTimeEvent(createTimeEventItem("09:00", repeatingOptionNone)) << RuleEngine::RuleErrorNoError;
QTest::newRow("valid: timeEventItem - hourly") << createTimeDescriptorTimeEvent(createTimeEventItem("09:00", repeatingOptionHourly)) << RuleEngine::RuleErrorNoError;
QTest::newRow("valid: timeEventItem - weekly - multiple days") << createTimeDescriptorTimeEvent(timeEventItems) << RuleEngine::RuleErrorNoError;
QTest::newRow("valid: timeEventItem - monthly - multiple days") << createTimeDescriptorTimeEvent(createTimeEventItem("23:00", repeatingOptionMonthlyMultiple)) << RuleEngine::RuleErrorNoError;
QTest::newRow("invalid: calendarItem empty") << createTimeDescriptorCalendar(createCalendarItem()) << RuleEngine::RuleErrorInvalidCalendarItem;
QTest::newRow("invalid: calendarItem none") << createTimeDescriptorCalendar(createCalendarItem("00:12", 12, repeatingOptionInvalidNone)) << RuleEngine::RuleErrorInvalidRepeatingOption;
QTest::newRow("invalid: calendarItem dateTime - daily") << createTimeDescriptorCalendar(createCalendarItem(QDateTime::currentDateTime().toTime_t(), 5, repeatingOptionDaily)) << RuleEngine::RuleErrorInvalidCalendarItem;
QTest::newRow("invalid: calendarItem invalid time") << createTimeDescriptorCalendar(createCalendarItem("35:80", 5)) << RuleEngine::RuleErrorInvalidCalendarItem;
QTest::newRow("invalid: calendarItem invalid duration") << createTimeDescriptorCalendar(createCalendarItem("12:00", 0)) << RuleEngine::RuleErrorInvalidCalendarItem;
QTest::newRow("invalid: calendarItem - monthly - weekDays") << createTimeDescriptorCalendar(createCalendarItem("13:13", 5, repeatingOptionInvalidMonthly)) << RuleEngine::RuleErrorInvalidRepeatingOption;
QTest::newRow("invalid: calendarItem - weekly - monthDays") << createTimeDescriptorCalendar(createCalendarItem("15:30", 20, repeatingOptionInvalidWeekly)) << RuleEngine::RuleErrorInvalidRepeatingOption;
QTest::newRow("invalid: calendarItem - invalid weekdays (negative)") << createTimeDescriptorCalendar(createCalendarItem("13:13", 5, repeatingOptionInvalidWeekDays)) << RuleEngine::RuleErrorInvalidRepeatingOption;
QTest::newRow("invalid: calendarItem - invalid weekdays (to big)") << createTimeDescriptorCalendar(createCalendarItem("13:13", 5, repeatingOptionInvalidWeekDays2)) << RuleEngine::RuleErrorInvalidRepeatingOption;
QTest::newRow("invalid: calendarItem - invalid monthdays (negative)") << createTimeDescriptorCalendar(createCalendarItem("13:13", 5, repeatingOptionInvalidMonthDays)) << RuleEngine::RuleErrorInvalidRepeatingOption;
QTest::newRow("invalid: calendarItem - invalid monthdays (to big)") << createTimeDescriptorCalendar(createCalendarItem("13:13", 5, repeatingOptionInvalidMonthDays2)) << RuleEngine::RuleErrorInvalidRepeatingOption;
QTest::newRow("invalid: timeEventItem empty") << createTimeDescriptorTimeEvent(createTimeEventItem()) << RuleEngine::RuleErrorInvalidTimeEventItem;
QTest::newRow("invalid: timeEventItem none") << createTimeDescriptorTimeEvent(createTimeEventItem("00:12", repeatingOptionInvalidNone)) << RuleEngine::RuleErrorInvalidRepeatingOption;
QTest::newRow("invalid: timeEventItem - dateTime + repeatingOption") << createTimeDescriptorTimeEvent(createTimeEventItem(QDateTime::currentDateTime().toTime_t(), repeatingOptionDaily)) << RuleEngine::RuleErrorInvalidTimeEventItem;
QTest::newRow("invalid: timeEventItem invalid time") << createTimeDescriptorTimeEvent(createTimeEventItem("35:80")) << RuleEngine::RuleErrorInvalidTimeEventItem;
QTest::newRow("invalid: timeEventItem - monthly - weekDays") << createTimeDescriptorTimeEvent(createTimeEventItem("13:13", repeatingOptionInvalidMonthly)) << RuleEngine::RuleErrorInvalidRepeatingOption;
QTest::newRow("invalid: timeEventItem - weekly - monthDays") << createTimeDescriptorTimeEvent(createTimeEventItem("15:30", repeatingOptionInvalidWeekly)) << RuleEngine::RuleErrorInvalidRepeatingOption;
QTest::newRow("invalid: timeEventItem - invalid weekdays (negative)") << createTimeDescriptorTimeEvent(createTimeEventItem("13:13", repeatingOptionInvalidWeekDays)) << RuleEngine::RuleErrorInvalidRepeatingOption;
QTest::newRow("invalid: timeEventItem - invalid weekdays (to big)") << createTimeDescriptorTimeEvent(createTimeEventItem("13:13", repeatingOptionInvalidWeekDays2)) << RuleEngine::RuleErrorInvalidRepeatingOption;
QTest::newRow("invalid: timeEventItem - invalid monthdays (negative)") << createTimeDescriptorTimeEvent(createTimeEventItem("13:13", repeatingOptionInvalidMonthDays)) << RuleEngine::RuleErrorInvalidRepeatingOption;
QTest::newRow("invalid: timeEventItem - invalid monthdays (to big)") << createTimeDescriptorTimeEvent(createTimeEventItem("13:13", repeatingOptionInvalidMonthDays2)) << RuleEngine::RuleErrorInvalidRepeatingOption;
}
void TestTimeManager::addTimeDescriptor()
{
QFETCH(QVariantMap, timeDescriptor);
QFETCH(RuleEngine::RuleError, error);
// ADD the rule
QVariantMap ruleMap; QVariantMap action;
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
action.insert("deviceId", m_mockDeviceId);
action.insert("ruleActionParams", QVariantList());
ruleMap.insert("name", "TimeBased rule");
ruleMap.insert("timeDescriptor", timeDescriptor);
ruleMap.insert("actions", QVariantList() << action);
QVariant response = injectAndWait("Rules.AddRule", ruleMap);
verifyRuleError(response, error);
if (error != RuleEngine::RuleErrorNoError)
return;
RuleId newRuleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toString());
// REMOVE rule
QVariantMap removeParams;
removeParams.insert("ruleId", newRuleId);
response = injectAndWait("Rules.RemoveRule", removeParams);
verifyRuleError(response);
}
void TestTimeManager::testCalendarDateTime_data()
{
QTest::addColumn<QDateTime>("dateTime");
QTest::addColumn<int>("duration");
QTest::newRow("dateTime - christmas") << QDateTime::fromString("24.12.2017 20:00", "dd.MM.yyyy hh:mm") << 60;
QTest::newRow("dateTime - new year") << QDateTime::fromString("31.12.2017 23:00", "dd.MM.yyyy hh:mm") << 120;
QTest::newRow("dateTime - valentines day") << QDateTime::fromString("14.02.2017 08:00", "dd.MM.yyyy hh:mm") << 120;
}
void TestTimeManager::testCalendarDateTime()
{
QFETCH(QDateTime, dateTime);
QFETCH(int, duration);
initTimeManager();
// Action (without params)
QVariantMap ruleMap; QVariantMap action; QVariantMap exitAction;
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
action.insert("deviceId", m_mockDeviceId);
action.insert("ruleActionParams", QVariantList());
// Exit action (with params)
QVariantList actionParams;
QVariantMap param1;
param1.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
param1.insert("value", 12);
actionParams.append(param1);
QVariantMap param2;
param2.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId);
param2.insert("value", true);
actionParams.append(param2);
exitAction.insert("actionTypeId", mockWithParamsActionTypeId);
exitAction.insert("deviceId", m_mockDeviceId);
exitAction.insert("ruleActionParams", actionParams);
// CalendarItem
QVariantMap calendarItem;
calendarItem.insert("datetime", QVariant(dateTime.toTime_t()));
calendarItem.insert("duration", QVariant(duration));
// Create the rule map
ruleMap.insert("name", "Time based hourly calendar rule");
ruleMap.insert("timeDescriptor", createTimeDescriptorCalendar(calendarItem));
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());
QDateTime oneMinuteBeforeEvent = dateTime.addSecs(-60);
NymeaCore::instance()->timeManager()->setTime(oneMinuteBeforeEvent);
verifyRuleNotExecuted();
// active
NymeaCore::instance()->timeManager()->setTime(dateTime);
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
// active unchanged
NymeaCore::instance()->timeManager()->setTime(dateTime.addSecs(duration * 30));
verifyRuleNotExecuted();
// inactive
NymeaCore::instance()->timeManager()->setTime(dateTime.addSecs(duration * 60));
verifyRuleExecuted(mockWithParamsActionTypeId);
cleanupMockHistory();
// inactive unchanged
NymeaCore::instance()->timeManager()->setTime(dateTime.addSecs((duration + 1) * 60));
verifyRuleNotExecuted();
// REMOVE rule
QVariantMap removeParams;
removeParams.insert("ruleId", ruleId);
response = injectAndWait("Rules.RemoveRule", removeParams);
verifyRuleError(response);
}
void TestTimeManager::testCalendarItemHourly_data()
{
QTest::addColumn<int>("duration");
//QTest::newRow("hourly - for 60 minutes") << 60;
QTest::newRow("hourly - for 5 minutes") << 5;
}
void TestTimeManager::testCalendarItemHourly()
{
QFETCH(int, duration);
initTimeManager();
QVariantMap ruleMap; QVariantMap action; QVariantMap exitAction; QVariantMap repeatingOptionHourly;
repeatingOptionHourly.insert("mode", "RepeatingModeHourly");
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
action.insert("deviceId", m_mockDeviceId);
action.insert("ruleActionParams", QVariantList());
exitAction.insert("actionTypeId", mockWithParamsActionTypeId);
QVariantList actionParams;
QVariantMap param1;
param1.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
param1.insert("value", 7);
actionParams.append(param1);
QVariantMap param2;
param2.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId);
param2.insert("value", true);
actionParams.append(param2);
exitAction.insert("deviceId", m_mockDeviceId);
exitAction.insert("ruleActionParams", actionParams);
ruleMap.insert("name", "Time based hourly calendar rule");
ruleMap.insert("timeDescriptor", createTimeDescriptorCalendar(createCalendarItem("08:05", duration, repeatingOptionHourly)));
ruleMap.insert("actions", QVariantList() << action);
ruleMap.insert("exitActions", QVariantList() << exitAction);
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);
QDateTime currentDateTime = NymeaCore::instance()->timeManager()->currentDateTime();
QDateTime future = QDateTime(currentDateTime.date(), QTime(8, 4));
// Check if should be enabled always
if (duration == 60) {
NymeaCore::instance()->timeManager()->setTime(future);
// Should be active since adding
verifyRuleExecuted(mockWithoutParamsActionTypeId);
} else {
// check the next 24 hours in 8h steps
for (int i = 0; i < 24; i+=8) {
// inactive
NymeaCore::instance()->timeManager()->setTime(future);
verifyRuleNotExecuted();
// active
NymeaCore::instance()->timeManager()->setTime(QDateTime(currentDateTime.date(), QTime(future.time().hour(), 5)));
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
// active unchanged
NymeaCore::instance()->timeManager()->setTime(QDateTime(currentDateTime.date(), QTime(future.time().hour(), 7)));
verifyRuleNotExecuted();
// inactive
NymeaCore::instance()->timeManager()->setTime(QDateTime(currentDateTime.date(), QTime(future.time().hour(), 10)));
verifyRuleExecuted(mockWithParamsActionTypeId);
cleanupMockHistory();
// inactive unchanged
NymeaCore::instance()->timeManager()->setTime(QDateTime(currentDateTime.date(), QTime(future.time().hour(), 11)));
verifyRuleNotExecuted();
// 'i' hours "Back to the future"
future = future.addSecs(i*60*60);
}
}
cleanupMockHistory();
// REMOVE rule
QVariantMap removeParams;
removeParams.insert("ruleId", ruleId);
response = injectAndWait("Rules.RemoveRule", removeParams);
verifyRuleError(response);
}
void TestTimeManager::testCalendarItemDaily_data()
{
QVariantMap repeatingOptionDaily;
repeatingOptionDaily.insert("mode", "RepeatingModeDaily");
QTest::addColumn<QVariantMap>("timeDescriptor");
QTest::addColumn<QString>("time");
QTest::addColumn<int>("duration");
QTest::newRow("daily") << createTimeDescriptorCalendar(createCalendarItem("06:55", 10, repeatingOptionDaily)) << "06:55" << 10;
QTest::newRow("daily - jump date") << createTimeDescriptorCalendar(createCalendarItem("23:55", 10, repeatingOptionDaily)) << "23:55" << 10;
}
void TestTimeManager::testCalendarItemDaily()
{
QFETCH(QVariantMap, timeDescriptor);
QFETCH(QString, time);
initTimeManager();
QVariantMap ruleMap; QVariantMap action; QVariantMap exitAction;
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
action.insert("deviceId", m_mockDeviceId);
action.insert("ruleActionParams", QVariantList());
exitAction.insert("actionTypeId", mockWithParamsActionTypeId);
QVariantList actionParams;
QVariantMap param1;
param1.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
param1.insert("value", 12);
actionParams.append(param1);
QVariantMap param2;
param2.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId);
param2.insert("value", true);
actionParams.append(param2);
exitAction.insert("deviceId", m_mockDeviceId);
exitAction.insert("ruleActionParams", actionParams);
ruleMap.insert("name", "Time based hourly calendar rule");
ruleMap.insert("timeDescriptor", timeDescriptor);
ruleMap.insert("actions", QVariantList() << action);
ruleMap.insert("exitActions", QVariantList() << exitAction);
QVariant response = injectAndWait("Rules.AddRule", ruleMap);
verifyRuleError(response);
RuleId ruleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toString());
QDateTime currentDateTime = NymeaCore::instance()->timeManager()->currentDateTime();
// start with one minute before starttime today
QDateTime future = QDateTime(currentDateTime.date(), QTime::fromString(time, "hh:mm").addSecs(-60));
// if always true
if (time == "08:00") {
NymeaCore::instance()->timeManager()->setTime(future);
// Should be active since adding
verifyRuleExecuted(mockWithoutParamsActionTypeId);
} else {
// check the next 7 days
for (int i = 0; i < 7; i++) {
// inactive
NymeaCore::instance()->timeManager()->setTime(future);
verifyRuleNotExecuted();
// active
NymeaCore::instance()->timeManager()->setTime(future.addSecs(60));
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
// active unchanged
NymeaCore::instance()->timeManager()->setTime(future.addSecs(6* 60));
verifyRuleNotExecuted();
// inactive
NymeaCore::instance()->timeManager()->setTime(future.addSecs(11 * 60));
verifyRuleExecuted(mockWithParamsActionTypeId);
cleanupMockHistory();
// inactive unchanged
NymeaCore::instance()->timeManager()->setTime(future.addSecs(12 * 60));
verifyRuleNotExecuted();
// One day "Back to the future"
future = future.addDays(1);
}
}
cleanupMockHistory();
// REMOVE rule
QVariantMap removeParams;
removeParams.insert("ruleId", ruleId);
response = injectAndWait("Rules.RemoveRule", removeParams);
verifyRuleError(response);
}
void TestTimeManager::testCalendarItemWeekly_data()
{
QVariantMap repeatingOptionWeekly;
repeatingOptionWeekly.insert("mode", "RepeatingModeWeekly");
repeatingOptionWeekly.insert("weekDays", QVariantList() << 2 << 4 << 6);
QVariantMap repeatingOptionWeeklyOverlapping;
repeatingOptionWeeklyOverlapping.insert("mode", "RepeatingModeWeekly");
repeatingOptionWeeklyOverlapping.insert("weekDays", QVariantList() << 6);
QTest::addColumn<QVariantMap>("timeDescriptor");
QTest::addColumn<QVariantMap>("repeatingOption");
QTest::addColumn<QString>("time");
QTest::addColumn<bool>("overlapping");
QTest::newRow("weekly") << createTimeDescriptorCalendar(createCalendarItem("06:55", 10, repeatingOptionWeekly)) << repeatingOptionWeekly << "06:55" << false;
//QTest::newRow("weekly - always") << createTimeDescriptorCalendar(createCalendarItem("22:34", 10080)) << QVariantMap() << "22:34" << false;
//QTest::newRow("weekly - overlapping") << createTimeDescriptorCalendar(createCalendarItem("08:00", 2880, repeatingOptionWeeklyOverlapping)) << repeatingOptionWeeklyOverlapping << "08:00" << true;
}
void TestTimeManager::testCalendarItemWeekly()
{
QFETCH(QVariantMap, timeDescriptor);
QFETCH(QVariantMap, repeatingOption);
QFETCH(QString, time);
QFETCH(bool, overlapping);
initTimeManager();
// Action (without params)
QVariantMap ruleMap; QVariantMap action; QVariantMap exitAction;
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
action.insert("deviceId", m_mockDeviceId);
action.insert("ruleActionParams", QVariantList());
// Exit action (with params)
QVariantList actionParams;
QVariantMap param1;
param1.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
param1.insert("value", 12);
actionParams.append(param1);
QVariantMap param2;
param2.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId);
param2.insert("value", true);
actionParams.append(param2);
exitAction.insert("actionTypeId", mockWithParamsActionTypeId);
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());
QDateTime currentDateTime = NymeaCore::instance()->timeManager()->currentDateTime();
// start with one minute before starttime today
QDateTime future = QDateTime(currentDateTime.date(), QTime::fromString(time, "hh:mm").addSecs(-60));
QVariantList weekDaysVariant = repeatingOption.value("weekDays").toList();
QList<int> weekDays;
foreach (const QVariant &variant, weekDaysVariant) {
weekDays.append(variant.toInt());
}
// the whole week active (always)
if (repeatingOption.isEmpty()) {
NymeaCore::instance()->timeManager()->setTime(future);
// Should be active since adding
verifyRuleExecuted(mockWithoutParamsActionTypeId);
} else {
if (!overlapping) {
// check the next 7 days (because not overlapping the week)
for (int i = 0; i < 7; i++) {
// inactive
NymeaCore::instance()->timeManager()->setTime(future);
verifyRuleNotExecuted();
// Check if today is a weekday
if (weekDays.contains(future.date().dayOfWeek())) {
// should trigger today
// active
NymeaCore::instance()->timeManager()->setTime(future.addSecs(60));
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
// active unchanged
NymeaCore::instance()->timeManager()->setTime(future.addSecs(6* 60));
verifyRuleNotExecuted();
// inactive
NymeaCore::instance()->timeManager()->setTime(future.addSecs(11 * 60));
verifyRuleExecuted(mockWithParamsActionTypeId);
cleanupMockHistory();
// inactive unchanged
NymeaCore::instance()->timeManager()->setTime(future.addSecs(12 * 60));
verifyRuleNotExecuted();
// One day "Back to the future"
future = future.addDays(1);
} else {
// should not trigger today
NymeaCore::instance()->timeManager()->setTime(future.addSecs(6* 60));
verifyRuleNotExecuted();
// One day "Back to the future"
future = future.addDays(1);
}
}
} else {
// Overlapping the week
int weekDay = weekDays.first();
// go to the next start day (weeksaturday)
QDateTime startDate = future;
while (startDate.date().dayOfWeek() < weekDay) {
startDate = startDate.addDays(1);
}
// inactive
NymeaCore::instance()->timeManager()->setTime(startDate);
verifyRuleNotExecuted();
// active
NymeaCore::instance()->timeManager()->setTime(startDate.addSecs(60));
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
// still active
NymeaCore::instance()->timeManager()->setTime(startDate.addDays(1));
verifyRuleNotExecuted();
// still active
NymeaCore::instance()->timeManager()->setTime(startDate.addDays(2));
verifyRuleNotExecuted();
// inactive
NymeaCore::instance()->timeManager()->setTime(startDate.addDays(2).addSecs(60));
verifyRuleExecuted(mockWithParamsActionTypeId);
}
}
cleanupMockHistory();
// REMOVE rule
QVariantMap removeParams;
removeParams.insert("ruleId", ruleId);
response = injectAndWait("Rules.RemoveRule", removeParams);
verifyRuleError(response);
}
void TestTimeManager::testCalendarItemMonthly_data()
{
QVariantMap repeatingOptionMonthly;
repeatingOptionMonthly.insert("mode", "RepeatingModeMonthly");
repeatingOptionMonthly.insert("monthDays", QVariantList() << 1 << 10 << 16 << 20 << 25);
QVariantMap repeatingOptionMonthlyOverlapping;
repeatingOptionMonthlyOverlapping.insert("mode", "RepeatingModeMonthly");
repeatingOptionMonthlyOverlapping.insert("monthDays", QVariantList() << 28);
QTest::addColumn<QVariantMap>("timeDescriptor");
QTest::addColumn<QVariantMap>("repeatingOption");
QTest::addColumn<QString>("time");
QTest::addColumn<bool>("overlapping");
QTest::newRow("monthly") << createTimeDescriptorCalendar(createCalendarItem("06:55", 10, repeatingOptionMonthly)) << repeatingOptionMonthly << "06:55" << false;
//QTest::newRow("monthly - overlapping") << createTimeDescriptorCalendar(createCalendarItem("08:00", 4320, repeatingOptionMonthlyOverlapping)) << repeatingOptionMonthlyOverlapping << "08:00" << true;
}
void TestTimeManager::testCalendarItemMonthly()
{
QFETCH(QVariantMap, timeDescriptor);
QFETCH(QVariantMap, repeatingOption);
QFETCH(QString, time);
QFETCH(bool, overlapping);
initTimeManager();
// Action (without params)
QVariantMap ruleMap; QVariantMap action; QVariantMap exitAction;
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
action.insert("deviceId", m_mockDeviceId);
action.insert("ruleActionParams", QVariantList());
// Exit action (with params)
QVariantList actionParams;
QVariantMap param1;
param1.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
param1.insert("value", 12);
actionParams.append(param1);
QVariantMap param2;
param2.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId);
param2.insert("value", true);
actionParams.append(param2);
exitAction.insert("actionTypeId", mockWithParamsActionTypeId);
exitAction.insert("deviceId", m_mockDeviceId);
exitAction.insert("ruleActionParams", actionParams);
// Create the rule map
ruleMap.insert("name", "Time based monthly 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());
QDateTime currentDateTime = NymeaCore::instance()->timeManager()->currentDateTime();
QVariantList monthDaysVariant = repeatingOption.value("monthDays").toList();
QList<int> monthDays;
foreach (const QVariant &variant, monthDaysVariant) {
monthDays.append(variant.toInt());
}
// start with one minute before starttime today
QDateTime future = QDateTime(currentDateTime.date(), QTime::fromString(time, "hh:mm").addSecs(-60));
if (!overlapping) {
// run one month to the future
for (int i = 0; i < 31; i++) {
QDateTime dateTime = future.addDays(i);
// Check if today is a weekday
if (monthDays.contains(dateTime.date().day())) {
// should trigger today
// not active yet
NymeaCore::instance()->timeManager()->setTime(dateTime);
verifyRuleNotExecuted();
// active
NymeaCore::instance()->timeManager()->setTime(dateTime.addSecs(60));
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
// active unchanged
NymeaCore::instance()->timeManager()->setTime(dateTime.addSecs(6* 60));
verifyRuleNotExecuted();
// inactive
NymeaCore::instance()->timeManager()->setTime(dateTime.addSecs(11 * 60));
verifyRuleExecuted(mockWithParamsActionTypeId);
cleanupMockHistory();
// inactive unchanged
NymeaCore::instance()->timeManager()->setTime(dateTime.addSecs(12 * 60));
verifyRuleNotExecuted();
} else {
// should not trigger today
NymeaCore::instance()->timeManager()->setTime(dateTime.addSecs(60));
verifyRuleNotExecuted();
}
}
} else {
// Overlapping the month
int monthDay = monthDays.first();
QCOMPARE(monthDay, 28);
// go to the next start day (28.MM.yyyy)
QDateTime startDate = future;
while (startDate.date().day() < monthDay) {
startDate = startDate.addDays(1);
}
// inactive
NymeaCore::instance()->timeManager()->setTime(startDate);
verifyRuleNotExecuted();
// active
NymeaCore::instance()->timeManager()->setTime(startDate.addSecs(60));
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
// still active
NymeaCore::instance()->timeManager()->setTime(startDate.addDays(3));
verifyRuleNotExecuted();
// inactive
NymeaCore::instance()->timeManager()->setTime(startDate.addDays(3).addSecs(60));
verifyRuleExecuted(mockWithParamsActionTypeId);
}
cleanupMockHistory();
// REMOVE rule
QVariantMap removeParams;
removeParams.insert("ruleId", ruleId);
response = injectAndWait("Rules.RemoveRule", removeParams);
verifyRuleError(response);
}
void TestTimeManager::testCalendarYearlyDateTime_data()
{
QTest::addColumn<QDateTime>("dateTime");
QTest::addColumn<int>("duration");
QTest::newRow("dateTime - yearly - christmas") << QDateTime::fromString(QString("24.12.%1 20:00").arg(QDateTime::currentDateTime().date().year() + 1), "dd.MM.yyyy hh:mm") << 60;
QTest::newRow("dateTime - yearly - new year") << QDateTime::fromString(QString("31.12.%1 23:00").arg(QDateTime::currentDateTime().date().year() + 1), "dd.MM.yyyy hh:mm") << 120;
QTest::newRow("dateTime - yearly - valentines day") << QDateTime::fromString("14.02.2017 08:00", "dd.MM.yyyy hh:mm") << 120;
}
void TestTimeManager::testCalendarYearlyDateTime()
{
QFETCH(QDateTime, dateTime);
QFETCH(int, duration);
initTimeManager();
// Action (without params)
QVariantMap ruleMap; QVariantMap action; QVariantMap exitAction;
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
action.insert("deviceId", m_mockDeviceId);
action.insert("ruleActionParams", QVariantList());
// Exit action (with params)
QVariantList actionParams;
QVariantMap param1;
param1.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
param1.insert("value", 12);
actionParams.append(param1);
QVariantMap param2;
param2.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId);
param2.insert("value", true);
actionParams.append(param2);
exitAction.insert("actionTypeId", mockWithParamsActionTypeId);
exitAction.insert("deviceId", m_mockDeviceId);
exitAction.insert("ruleActionParams", actionParams);
// RepeatingOption
QVariantMap repeatingOption;
repeatingOption.insert("mode", "RepeatingModeYearly");
// CalendarItem
QVariantMap calendarItem;
calendarItem.insert("datetime", QVariant(dateTime.toTime_t()));
calendarItem.insert("duration", QVariant(duration));
calendarItem.insert("repeating", repeatingOption);
// Create the rule map
ruleMap.insert("name", "Time based yearly calendar rule");
ruleMap.insert("timeDescriptor", createTimeDescriptorCalendar(calendarItem));
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());
QDateTime oneMinuteBeforeEvent = dateTime.addSecs(-60);
NymeaCore::instance()->timeManager()->setTime(oneMinuteBeforeEvent);
verifyRuleNotExecuted();
// active
NymeaCore::instance()->timeManager()->setTime(dateTime);
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
cleanupMockHistory();
// active unchanged
NymeaCore::instance()->timeManager()->setTime(dateTime.addSecs(duration * 30));
verifyRuleNotExecuted();
// inactive
NymeaCore::instance()->timeManager()->setTime(dateTime.addSecs(duration * 60));
verifyRuleExecuted(mockWithParamsActionTypeId);
cleanupMockHistory();
cleanupMockHistory();
// inactive unchanged
NymeaCore::instance()->timeManager()->setTime(dateTime.addSecs((duration + 1) * 60));
verifyRuleNotExecuted();
// One year "Back to the future"
oneMinuteBeforeEvent = oneMinuteBeforeEvent.addYears(1);
dateTime = dateTime.addYears(1);
NymeaCore::instance()->timeManager()->setTime(oneMinuteBeforeEvent);
verifyRuleNotExecuted();
// active
NymeaCore::instance()->timeManager()->setTime(dateTime);
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
cleanupMockHistory();
// active unchanged
NymeaCore::instance()->timeManager()->setTime(dateTime.addSecs(duration * 30));
verifyRuleNotExecuted();
// inactive
NymeaCore::instance()->timeManager()->setTime(dateTime.addSecs(duration * 60));
verifyRuleExecuted(mockWithParamsActionTypeId);
cleanupMockHistory();
// inactive unchanged
NymeaCore::instance()->timeManager()->setTime(dateTime.addSecs((duration + 1) * 60));
verifyRuleNotExecuted();
cleanupMockHistory();
// REMOVE rule
QVariantMap removeParams;
removeParams.insert("ruleId", ruleId);
response = injectAndWait("Rules.RemoveRule", removeParams);
verifyRuleError(response);
}
void TestTimeManager::testCalendarItemStates_data()
{
initTimeManager();
// Repeating option
QVariantMap repeatingOptionDaily;
repeatingOptionDaily.insert("mode", "RepeatingModeDaily");
// Action
QVariantMap action;
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
action.insert("deviceId", m_mockDeviceId);
action.insert("ruleActionParams", QVariantList());
// Exit action (with params)
QVariantMap exitAction;
QVariantList actionParams;
QVariantMap param1;
param1.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
param1.insert("value", 12);
actionParams.append(param1);
QVariantMap param2;
param2.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId);
param2.insert("value", true);
actionParams.append(param2);
exitAction.insert("actionTypeId", mockWithParamsActionTypeId);
exitAction.insert("deviceId", m_mockDeviceId);
exitAction.insert("ruleActionParams", actionParams);
// Stateevaluators
QVariantMap stateEvaluator;
QVariantMap stateDescriptorInt;
stateDescriptorInt.insert("deviceId", m_mockDeviceId);
stateDescriptorInt.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorGreaterOrEqual));
stateDescriptorInt.insert("stateTypeId", mockIntStateTypeId);
stateDescriptorInt.insert("value", 65);
QVariantMap stateDescriptorBool;
stateDescriptorBool.insert("deviceId", m_mockDeviceId);
stateDescriptorBool.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals));
stateDescriptorBool.insert("stateTypeId", mockBoolStateTypeId);
stateDescriptorBool.insert("value", true);
QVariantMap stateEvaluatorInt;
stateEvaluatorInt.insert("stateDescriptor", stateDescriptorInt);
stateEvaluatorInt.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd));
QVariantMap stateEvaluatorBool;
stateEvaluatorBool.insert("stateDescriptor", stateDescriptorBool);
stateEvaluatorBool.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd));
QVariantList childEvaluators;
childEvaluators.append(stateEvaluatorInt);
childEvaluators.append(stateEvaluatorBool);
stateEvaluator.insert("childEvaluators", childEvaluators);
stateEvaluator.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd));
// The rule
QVariantMap ruleMap;
ruleMap.insert("name", "Time and state based daily calendar rule");
ruleMap.insert("stateEvaluator", stateEvaluator);
ruleMap.insert("actions", QVariantList() << action);
ruleMap.insert("exitActions", QVariantList() << exitAction);
ruleMap.insert("timeDescriptor", createTimeDescriptorCalendar(createCalendarItem("08:00", 10, repeatingOptionDaily)));
NymeaCore::instance()->timeManager()->setTime(QDateTime(QDate::currentDate(), QTime(07,59)));
QVariant response = injectAndWait("Rules.AddRule", ruleMap);
verifyRuleError(response);
QTest::addColumn<QDateTime>("dateTime");
QTest::addColumn<bool>("boolValue");
QTest::addColumn<int>("intValue");
QTest::addColumn<bool>("trigger");
QTest::addColumn<bool>("active");
QTest::newRow("07:59 | true - 66") << QDateTime(QDate::currentDate(), QTime(07,59)) << true << 66 << false << false;
QTest::newRow("08:00 | true - 66") << QDateTime(QDate::currentDate(), QTime(8,0)) << true << 66 << true << true;
QTest::newRow("08:01 | true - 66") << QDateTime(QDate::currentDate(), QTime(8,1)) << true << 66 << false << false;
QTest::newRow("08:02 | false - 66") << QDateTime(QDate::currentDate(), QTime(8,2)) << false << 66 << true << false;
QTest::newRow("08:03 | true - 65") << QDateTime(QDate::currentDate(), QTime(8,3)) << true << 65 << true << true;
QTest::newRow("08:06 | true - 64") << QDateTime(QDate::currentDate(), QTime(8,6)) << true << 64 << true << false;
QTest::newRow("08:07 | false - 64") << QDateTime(QDate::currentDate(), QTime(8,7)) << false << 64 << false << false;
QTest::newRow("08:07 | false - 65") << QDateTime(QDate::currentDate(), QTime(8,7)) << false << 65 << false << false;
QTest::newRow("08:08 | true - 65") << QDateTime(QDate::currentDate(), QTime(8,8)) << true << 65 << true << true;
QTest::newRow("08:09 | true - 65") << QDateTime(QDate::currentDate(), QTime(8,9)) << true << 65 << false << false;
QTest::newRow("08:10 | true - 65") << QDateTime(QDate::currentDate(), QTime(8,10)) << true << 65 << true << false;
QTest::newRow("08:11 | true - 65") << QDateTime(QDate::currentDate(), QTime(8,11)) << true << 65 << false << false;
}
void TestTimeManager::testCalendarItemStates()
{
QFETCH(QDateTime, dateTime);
QFETCH(bool, boolValue);
QFETCH(int, intValue);
QFETCH(bool, trigger);
QFETCH(bool, active);
NymeaCore::instance()->timeManager()->setTime(dateTime);
setBoolState(boolValue);
setIntState(intValue);
// Actions
if (trigger && active) {
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
}
// Exit actions
if (trigger && !active) {
verifyRuleExecuted(mockWithParamsActionTypeId);
cleanupMockHistory();
}
// Nothing triggert
if (!trigger) {
verifyRuleNotExecuted();
}
}
void TestTimeManager::testCalendarItemEvent_data()
{
initTimeManager();
// Action (without params)
QVariantMap action;
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
action.insert("deviceId", m_mockDeviceId);
action.insert("ruleActionParams", QVariantList());
QVariantMap eventDescriptor;
eventDescriptor.insert("eventTypeId", mockEvent1EventTypeId);
eventDescriptor.insert("deviceId", m_mockDeviceId);
// The rule
QVariantMap ruleMap;
ruleMap.insert("name", "Time and state based daily calendar rule");
ruleMap.insert("actions", QVariantList() << action);
ruleMap.insert("eventDescriptors", QVariantList() << eventDescriptor);
ruleMap.insert("timeDescriptor", createTimeDescriptorCalendar(createCalendarItem("08:00", 10)));
NymeaCore::instance()->timeManager()->setTime(QDateTime(QDate::currentDate(), QTime(7,59)));
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);
printJson(response);
QTest::addColumn<QDateTime>("dateTime");
QTest::addColumn<bool>("trigger");
QTest::newRow("07:59 | not trigger") << QDateTime(QDate::currentDate(), QTime(07,59)) << false;
QTest::newRow("08:00 | trigger") << QDateTime(QDate::currentDate(), QTime(8,0)) << true;
QTest::newRow("08:05 | trigger") << QDateTime(QDate::currentDate(), QTime(8,5)) << true;
QTest::newRow("08:10 | not trigger") << QDateTime(QDate::currentDate(), QTime(8,10)) << false;
}
void TestTimeManager::testCalendarItemEvent()
{
QFETCH(QDateTime, dateTime);
QFETCH(bool, trigger);
cleanupMockHistory();
NymeaCore::instance()->timeManager()->setTime(dateTime);
// Trigger event
triggerMockEvent1();
if (trigger) {
verifyRuleExecuted(mockWithoutParamsActionTypeId);
} else {
verifyRuleNotExecuted();
}
}
void TestTimeManager::testCalendarItemStatesEvent_data()
{
initTimeManager();
NymeaCore::instance()->timeManager()->setTime(QDateTime(QDate::currentDate(), QTime(7,59)));
// Action (without params)
QVariantMap action;
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
action.insert("deviceId", m_mockDeviceId);
action.insert("ruleActionParams", QVariantList());
// Event descriptor
QVariantMap eventDescriptor;
eventDescriptor.insert("eventTypeId", mockEvent1EventTypeId);
eventDescriptor.insert("deviceId", m_mockDeviceId);
// State evaluator
QVariantMap stateDescriptorBool;
stateDescriptorBool.insert("deviceId", m_mockDeviceId);
stateDescriptorBool.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals));
stateDescriptorBool.insert("stateTypeId", mockBoolStateTypeId);
stateDescriptorBool.insert("value", true);
QVariantMap stateEvaluator;
stateEvaluator.insert("stateDescriptor", stateDescriptorBool);
// The rule
QVariantMap ruleMap;
ruleMap.insert("name", "Time and state and event based daily calendar rule");
ruleMap.insert("actions", QVariantList() << action);
ruleMap.insert("eventDescriptors", QVariantList() << eventDescriptor);
ruleMap.insert("stateEvaluator", stateEvaluator);
ruleMap.insert("timeDescriptor", createTimeDescriptorCalendar(createCalendarItem("08:00", 10)));
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);
QTest::addColumn<QDateTime>("dateTime");
QTest::addColumn<bool>("boolValue");
QTest::addColumn<bool>("trigger");
QTest::newRow("07:59 | state true | not trigger") << QDateTime(QDate::currentDate(), QTime(07,59)) << true << false;
QTest::newRow("08:00 | state true | trigger") << QDateTime(QDate::currentDate(), QTime(8,0)) << true << true;
QTest::newRow("08:01 | state false | not trigger") << QDateTime(QDate::currentDate(), QTime(8,1)) << false << false;
QTest::newRow("08:02 | state true | trigger") << QDateTime(QDate::currentDate(), QTime(8,2)) << true << true;
QTest::newRow("08:10 | state true | not trigger") << QDateTime(QDate::currentDate(), QTime(8,10)) << true << false;
}
void TestTimeManager::testCalendarItemStatesEvent()
{
QFETCH(QDateTime, dateTime);
QFETCH(bool, boolValue);
QFETCH(bool, trigger);
NymeaCore::instance()->timeManager()->setTime(dateTime);
setBoolState(boolValue);
// Trigger event
triggerMockEvent1();
if (trigger) {
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
} else {
verifyRuleNotExecuted();
}
}
void TestTimeManager::testCalendarItemCrossesMidnight()
{
initTimeManager();
NymeaCore::instance()->timeManager()->setTime(QDateTime(QDate::currentDate(), QTime(20,00)));
// Action
QVariantMap action;
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
action.insert("deviceId", m_mockDeviceId);
action.insert("ruleActionParams", QVariantList());
QVariantMap repeatingOptionDaily;
repeatingOptionDaily.insert("mode", "RepeatingModeDaily");
// The rule
QVariantMap ruleMap;
ruleMap.insert("name", "Time based from 23:00 to 01:00");
ruleMap.insert("actions", QVariantList() << action);
ruleMap.insert("timeDescriptor", createTimeDescriptorCalendar(createCalendarItem("23:00", 120, repeatingOptionDaily)));
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);
QVERIFY2(response.toMap().value("params").toMap().value("rule").toMap().value("active").toBool() == false, "Rule is active while it should not be (20:00)");
NymeaCore::instance()->timeManager()->setTime(QDateTime(QDate::currentDate(), QTime(22,59)));
response = injectAndWait("Rules.GetRuleDetails", params);
QVERIFY2(response.toMap().value("params").toMap().value("rule").toMap().value("active").toBool() == false, "Rule is active while it should not be (22:59)");
NymeaCore::instance()->timeManager()->setTime(QDateTime(QDate::currentDate(), QTime(23,00)));
response = injectAndWait("Rules.GetRuleDetails", params);
QVERIFY2(response.toMap().value("params").toMap().value("rule").toMap().value("active").toBool() == true, "Rule is not active while it should be (23:00)");
NymeaCore::instance()->timeManager()->setTime(QDateTime(QDate::currentDate(), QTime(23,10)));
response = injectAndWait("Rules.GetRuleDetails", params);
QVERIFY2(response.toMap().value("params").toMap().value("rule").toMap().value("active").toBool() == true, "Rule is not active while it should be (23:10)");
NymeaCore::instance()->timeManager()->setTime(QDateTime(QDate::currentDate(), QTime(00,00)));
response = injectAndWait("Rules.GetRuleDetails", params);
QVERIFY2(response.toMap().value("params").toMap().value("rule").toMap().value("active").toBool() == true, "Rule is not active while it should be (00:00)");
NymeaCore::instance()->timeManager()->setTime(QDateTime(QDate::currentDate(), QTime(00,30)));
response = injectAndWait("Rules.GetRuleDetails", params);
QVERIFY2(response.toMap().value("params").toMap().value("rule").toMap().value("active").toBool() == true, "Rule is not active while it should be (00:30)");
NymeaCore::instance()->timeManager()->setTime(QDateTime(QDate::currentDate(), QTime(01,00)));
response = injectAndWait("Rules.GetRuleDetails", params);
QVERIFY2(response.toMap().value("params").toMap().value("rule").toMap().value("active").toBool() == false, "Rule is active while it should not be (01:00)");
NymeaCore::instance()->timeManager()->setTime(QDateTime(QDate::currentDate(), QTime(02,00)));
response = injectAndWait("Rules.GetRuleDetails", params);
QVERIFY2(response.toMap().value("params").toMap().value("rule").toMap().value("active").toBool() == false, "Rule is active while it should not be (02:00)");
}
void TestTimeManager::testEventBasedWithCalendarItemCrossingMidnight()
{
initTimeManager();
NymeaCore::instance()->timeManager()->setTime(QDateTime(QDate::currentDate(), QTime(20,00)));
// Event descriptor
QVariantMap eventDescriptor;
eventDescriptor.insert("eventTypeId", mockEvent1EventTypeId);
eventDescriptor.insert("deviceId", m_mockDeviceId);
// Action
QVariantMap action;
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
action.insert("deviceId", m_mockDeviceId);
action.insert("ruleActionParams", QVariantList());
QVariantMap repeatingOptionDaily;
repeatingOptionDaily.insert("mode", "RepeatingModeDaily");
// The rule
QVariantMap ruleMap;
ruleMap.insert("name", "Time based from 23:00 to 01:00");
ruleMap.insert("actions", QVariantList() << action);
ruleMap.insert("eventDescriptors", QVariantList() << eventDescriptor);
ruleMap.insert("timeDescriptor", createTimeDescriptorCalendar(createCalendarItem("23:00", 120, repeatingOptionDaily)));
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);
QVERIFY2(response.toMap().value("params").toMap().value("rule").toMap().value("id").toUuid() == ruleId, "Rule not found in GetRules");
cleanupMockHistory();
NymeaCore::instance()->timeManager()->setTime(QDateTime(QDate::currentDate(), QTime(20, 00)));
triggerMockEvent1();
verifyRuleNotExecuted();
cleanupMockHistory();
NymeaCore::instance()->timeManager()->setTime(QDateTime(QDate::currentDate(), QTime(23, 00)));
triggerMockEvent1();
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
NymeaCore::instance()->timeManager()->setTime(QDateTime(QDate::currentDate(), QTime(23, 50)));
triggerMockEvent1();
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
NymeaCore::instance()->timeManager()->setTime(QDateTime(QDate::currentDate(), QTime(00, 00)));
triggerMockEvent1();
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
NymeaCore::instance()->timeManager()->setTime(QDateTime(QDate::currentDate(), QTime(01, 00)));
triggerMockEvent1();
verifyRuleNotExecuted();
}
void TestTimeManager::testEventItemDateTime_data()
{
QTest::addColumn<QDateTime>("dateTime");
QTest::newRow("dateTime - christmas") << QDateTime::fromString("24.12.2016 20:00", "dd.MM.yyyy hh:mm");
QTest::newRow("dateTime - new year") << QDateTime::fromString("31.12.2016 00:00", "dd.MM.yyyy hh:mm");
QTest::newRow("dateTime - valentines day") << QDateTime::fromString("14.02.2016 08:00", "dd.MM.yyyy hh:mm");
}
void TestTimeManager::testEventItemDateTime()
{
QFETCH(QDateTime, dateTime);
initTimeManager();
// Action (without params)
QVariantMap ruleMap; QVariantMap action;
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
action.insert("deviceId", m_mockDeviceId);
action.insert("ruleActionParams", QVariantList());
// Create the rule map
ruleMap.insert("name", "Time based hourly calendar rule");
ruleMap.insert("timeDescriptor", createTimeDescriptorTimeEvent(createTimeEventItem(dateTime.toTime_t())));
ruleMap.insert("actions", QVariantList() << action);
// Add the rule
QVariant response = injectAndWait("Rules.AddRule", ruleMap);
verifyRuleError(response);
RuleId ruleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toString());
// not triggering
NymeaCore::instance()->timeManager()->setTime(dateTime.addSecs(-120));
NymeaCore::instance()->timeManager()->setTime(dateTime.addSecs(-60));
verifyRuleNotExecuted();
// trigger
NymeaCore::instance()->timeManager()->setTime(dateTime);
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
// not triggering
NymeaCore::instance()->timeManager()->setTime(dateTime.addSecs(60));
verifyRuleNotExecuted();
cleanupMockHistory();
// REMOVE rule
QVariantMap removeParams;
removeParams.insert("ruleId", ruleId);
response = injectAndWait("Rules.RemoveRule", removeParams);
verifyRuleError(response);
}
void TestTimeManager::testEventItemHourly_data()
{
QTest::addColumn<QTime>("time");
QTest::newRow("timeEvent - houly 08:10") << QTime(8,10);
QTest::newRow("timeEvent - houly 12:33") << QTime(12,33);
}
void TestTimeManager::testEventItemHourly()
{
QFETCH(QTime, time);
initTimeManager();
// Repeating option
QVariantMap repeatingOptionHourly;
repeatingOptionHourly.insert("mode", "RepeatingModeHourly");
// Action
QVariantMap action;
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
action.insert("deviceId", m_mockDeviceId);
action.insert("ruleActionParams", QVariantList());
QVariantMap ruleMap;
ruleMap.insert("name", "Time based hourly event rule");
ruleMap.insert("timeDescriptor", createTimeDescriptorTimeEvent(createTimeEventItem(time.toString("hh:mm"), repeatingOptionHourly)));
ruleMap.insert("actions", QVariantList() << action);
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);
QDateTime currentDateTime = NymeaCore::instance()->timeManager()->currentDateTime();
QDateTime beforeEventDateTime = QDateTime(currentDateTime.date(), time.addSecs(-60));
// check the next 24 hours in 8h steps
for (int i = 0; i < 24; i+=8) {
// Back to the future (8h)
beforeEventDateTime = beforeEventDateTime.addSecs(i * 60 * 60);
// not triggering
NymeaCore::instance()->timeManager()->setTime(beforeEventDateTime);
verifyRuleNotExecuted();
// trigger
NymeaCore::instance()->timeManager()->setTime(beforeEventDateTime.addSecs(60));
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
// not triggering
NymeaCore::instance()->timeManager()->setTime(beforeEventDateTime.addSecs(120));
verifyRuleNotExecuted();
cleanupMockHistory();
}
cleanupMockHistory();
// REMOVE rule
QVariantMap removeParams;
removeParams.insert("ruleId", ruleId);
response = injectAndWait("Rules.RemoveRule", removeParams);
verifyRuleError(response);
}
void TestTimeManager::testEventItemDaily_data()
{
QTest::addColumn<QTime>("time");
QTest::addColumn<bool>("withRepeatingOption");
QTest::newRow("timeEvent - daily 10:01") << QTime(10,1) << false;
QTest::newRow("timeEvent - daily 22:22") << QTime(22,22) << true;
}
void TestTimeManager::testEventItemDaily()
{
QFETCH(QTime, time);
QFETCH(bool, withRepeatingOption);
initTimeManager();
// Repeating option
QVariantMap repeatingOptionDaily;
repeatingOptionDaily.insert("mode", "RepeatingModeDaily");
// Action
QVariantMap action;
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
action.insert("deviceId", m_mockDeviceId);
action.insert("ruleActionParams", QVariantList());
QVariantMap ruleMap;
ruleMap.insert("name", "Time based daily event rule");
ruleMap.insert("actions", QVariantList() << action);
if (withRepeatingOption) {
ruleMap.insert("timeDescriptor", createTimeDescriptorTimeEvent(createTimeEventItem(time.toString("hh:mm"), repeatingOptionDaily)));
} else {
ruleMap.insert("timeDescriptor", createTimeDescriptorTimeEvent(createTimeEventItem(time.toString("hh:mm"))));
}
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);
QDateTime currentDateTime = NymeaCore::instance()->timeManager()->currentDateTime();
QDateTime beforeEventDateTime = QDateTime(currentDateTime.date(), time.addSecs(-60));
// check the next 2 days
for (int i = 0; i < 2; i++) {
// not triggering
NymeaCore::instance()->timeManager()->setTime(beforeEventDateTime);
verifyRuleNotExecuted();
// trigger
NymeaCore::instance()->timeManager()->setTime(beforeEventDateTime.addSecs(60));
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
// not triggering
NymeaCore::instance()->timeManager()->setTime(beforeEventDateTime.addSecs(120));
verifyRuleNotExecuted();
// Back to the future (1 day)
beforeEventDateTime = beforeEventDateTime.addDays(1);
}
cleanupMockHistory();
// REMOVE rule
QVariantMap removeParams;
removeParams.insert("ruleId", ruleId);
response = injectAndWait("Rules.RemoveRule", removeParams);
verifyRuleError(response);
}
void TestTimeManager::testEventItemWeekly_data()
{
QTest::addColumn<QTime>("time");
QTest::addColumn<QVariantList>("weekDays");
QTest::newRow("timeEvent - houly 08:10") << QTime(8,10) << (QVariantList() << 6 << 7);
QTest::newRow("timeEvent - houly 12:33") << QTime(12,33) << (QVariantList() << 2 << 4 << 7);
}
void TestTimeManager::testEventItemWeekly()
{
QFETCH(QTime, time);
QFETCH(QVariantList, weekDays);
initTimeManager();
// Repeating option
QVariantMap repeatingOptionWeekly;
repeatingOptionWeekly.insert("mode", "RepeatingModeWeekly");
repeatingOptionWeekly.insert("weekDays", weekDays);
// Action
QVariantMap action;
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
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(time.toString("hh:mm"), repeatingOptionWeekly)));
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);
QDateTime currentDateTime = NymeaCore::instance()->timeManager()->currentDateTime();
QDateTime beforeEventDateTime = QDateTime(currentDateTime.date(), time.addSecs(-60));
QList<int> allowedDays;
foreach (const QVariant &weekDayVariant, weekDays) {
allowedDays.append(weekDayVariant.toInt());
}
// check the next 7 days
for (int i = 0; i < 7; i++) {
// check if today is one of the weekdays
if (allowedDays.contains(beforeEventDateTime.date().dayOfWeek())) {
// not triggering
NymeaCore::instance()->timeManager()->setTime(beforeEventDateTime);
verifyRuleNotExecuted();
// trigger
NymeaCore::instance()->timeManager()->setTime(beforeEventDateTime.addSecs(60));
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
// not triggering
NymeaCore::instance()->timeManager()->setTime(beforeEventDateTime.addSecs(120));
verifyRuleNotExecuted();
} else {
// not triggering on this weekday
NymeaCore::instance()->timeManager()->setTime(beforeEventDateTime.addSecs(60));
verifyRuleNotExecuted();
}
// Back to the future (1 day)
beforeEventDateTime = beforeEventDateTime.addDays(1);
}
cleanupMockHistory();
// REMOVE rule
QVariantMap removeParams;
removeParams.insert("ruleId", ruleId);
response = injectAndWait("Rules.RemoveRule", removeParams);
verifyRuleError(response);
}
void TestTimeManager::testEventItemMonthly_data()
{
QTest::addColumn<QTime>("time");
QTest::addColumn<QVariantList>("monthDays");
QTest::newRow("timeEvent - houly 08:10") << QTime(8,10) << (QVariantList() << 1 << 12 << 17 << 19 << 31);
QTest::newRow("timeEvent - houly 12:33") << QTime(12,33) << (QVariantList() << 2 << 4 << 7 << 30);
}
void TestTimeManager::testEventItemMonthly()
{
QFETCH(QTime, time);
QFETCH(QVariantList, monthDays);
initTimeManager();
// Repeating option
QVariantMap repeatingOptionMonthly;
repeatingOptionMonthly.insert("mode", "RepeatingModeMonthly");
repeatingOptionMonthly.insert("monthDays", monthDays);
// Action
QVariantMap action;
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
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(time.toString("hh:mm"), repeatingOptionMonthly)));
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);
QDateTime currentDateTime = NymeaCore::instance()->timeManager()->currentDateTime();
QDateTime beforeEventDateTime = QDateTime(currentDateTime.date(), time.addSecs(-60));
QList<int> allowedDays;
foreach (const QVariant &monthDayVariant, monthDays) {
allowedDays.append(monthDayVariant.toInt());
}
// check the next 7 days
for (int i = 0; i < 31; i++) {
// check if today is one of the month days
if (allowedDays.contains(beforeEventDateTime.date().day())) {
// not triggering
NymeaCore::instance()->timeManager()->setTime(beforeEventDateTime);
verifyRuleNotExecuted();
// trigger
NymeaCore::instance()->timeManager()->setTime(beforeEventDateTime.addSecs(60));
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
// not triggering
NymeaCore::instance()->timeManager()->setTime(beforeEventDateTime.addSecs(120));
verifyRuleNotExecuted();
} else {
// not triggering on this weekday
NymeaCore::instance()->timeManager()->setTime(beforeEventDateTime.addSecs(60));
verifyRuleNotExecuted();
}
// Back to the future (1 day)
beforeEventDateTime = beforeEventDateTime.addDays(1);
}
cleanupMockHistory();
// REMOVE rule
QVariantMap removeParams;
removeParams.insert("ruleId", ruleId);
response = injectAndWait("Rules.RemoveRule", removeParams);
verifyRuleError(response);
}
void TestTimeManager::testEventItemYearly_data()
{
QTest::addColumn<QDateTime>("dateTime");
QTest::newRow("dateTime - christmas") << QDateTime::fromString("24.12.2016 20:00", "dd.MM.yyyy hh:mm");
QTest::newRow("dateTime - new year") << QDateTime::fromString("31.12.2016 00:00", "dd.MM.yyyy hh:mm");
QTest::newRow("dateTime - valentines day") << QDateTime::fromString("14.02.2016 08:00", "dd.MM.yyyy hh:mm");
}
void TestTimeManager::testEventItemYearly()
{
QFETCH(QDateTime, dateTime);
initTimeManager();
// Repeating option
QVariantMap repeatingOptionYearly;
repeatingOptionYearly.insert("mode", "RepeatingModeYearly");
// Action (without params)
QVariantMap ruleMap; QVariantMap action;
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
action.insert("deviceId", m_mockDeviceId);
action.insert("ruleActionParams", QVariantList());
// Create the rule map
ruleMap.insert("name", "Time based hourly calendar rule");
ruleMap.insert("timeDescriptor", createTimeDescriptorTimeEvent(createTimeEventItem(dateTime.toTime_t(), repeatingOptionYearly)));
ruleMap.insert("actions", QVariantList() << action);
// Add the rule
QVariant response = injectAndWait("Rules.AddRule", ruleMap);
verifyRuleError(response);
RuleId ruleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toString());
// Tick now, one minute before, on time, one minute after
// not triggering
NymeaCore::instance()->timeManager()->setTime(dateTime.addSecs(-60));
verifyRuleNotExecuted();
// trigger
NymeaCore::instance()->timeManager()->setTime(dateTime);
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
// not triggering
NymeaCore::instance()->timeManager()->setTime(dateTime.addSecs(60));
verifyRuleNotExecuted();
// Tick next year, one minute before, on time, one minute after
QDateTime nextYear = dateTime.addYears(1);
// not triggering
NymeaCore::instance()->timeManager()->setTime(nextYear.addSecs(-60));
verifyRuleNotExecuted();
// trigger
NymeaCore::instance()->timeManager()->setTime(nextYear);
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
// not triggering
NymeaCore::instance()->timeManager()->setTime(nextYear.addSecs(60));
verifyRuleNotExecuted();
cleanupMockHistory();
// REMOVE rule
QVariantMap removeParams;
removeParams.insert("ruleId", ruleId);
response = injectAndWait("Rules.RemoveRule", removeParams);
verifyRuleError(response);
}
void TestTimeManager::testEventItemStates_data()
{
initTimeManager();
NymeaCore::instance()->timeManager()->setTime(QDateTime(QDate::currentDate(), QTime(7,59)));
// Action (without params)
QVariantMap action;
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
action.insert("deviceId", m_mockDeviceId);
action.insert("ruleActionParams", QVariantList());
// Time descriptor
QVariantMap timeEventItem1 = createTimeEventItem("08:00");
QVariantMap timeEventItem2 = createTimeEventItem("09:00");
QVariantMap timeDescriptor;
timeDescriptor.insert("timeEventItems", QVariantList() << timeEventItem1 << timeEventItem2);
// State evaluator
QVariantMap stateDescriptorBool;
stateDescriptorBool.insert("deviceId", m_mockDeviceId);
stateDescriptorBool.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals));
stateDescriptorBool.insert("stateTypeId", mockBoolStateTypeId);
stateDescriptorBool.insert("value", true);
QVariantMap stateEvaluator;
stateEvaluator.insert("stateDescriptor", stateDescriptorBool);
// The rule
QVariantMap ruleMap;
ruleMap.insert("name", "Time and state and event based daily calendar rule");
ruleMap.insert("actions", QVariantList() << action);
ruleMap.insert("stateEvaluator", stateEvaluator);
ruleMap.insert("timeDescriptor", timeDescriptor);
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);
QTest::addColumn<QDateTime>("dateTime");
QTest::addColumn<bool>("boolValue");
QTest::addColumn<bool>("trigger");
QTest::newRow("TimeEvent 07:59 | state false | not trigger") << QDateTime(QDate::currentDate(), QTime(7,59)) << false << false;
QTest::newRow("TimeEvent 07:59 | state true | not trigger") << QDateTime(QDate::currentDate(), QTime(7,59)) << true << false;
QTest::newRow("TimeEvent 08:00 | state false | not trigger") << QDateTime(QDate::currentDate(), QTime(8,0)) << false << false;
QTest::newRow("TimeEvent 07:59 | state true | not trigger") << QDateTime(QDate::currentDate(), QTime(7,59)) << true << false;
QTest::newRow("TimeEvent 08:00 | state true | trigger") << QDateTime(QDate::currentDate(), QTime(8,0)) << true << true;
QTest::newRow("TimeEvent 08:01 | state true | not trigger") << QDateTime(QDate::currentDate(), QTime(8,1)) << true << false;
QTest::newRow("TimeEvent 08:01 | state false | not trigger") << QDateTime(QDate::currentDate(), QTime(8,1)) << true << false;
QTest::newRow("TimeEvent 08:30 | state true | not trigger") << QDateTime(QDate::currentDate(), QTime(8,30)) << true << false;
QTest::newRow("TimeEvent 09:00 | state true | trigger") << QDateTime(QDate::currentDate(), QTime(9,0)) << true << true;
QTest::newRow("TimeEvent 09:01 | state true | not trigger") << QDateTime(QDate::currentDate(), QTime(9,1)) << true << false;
}
void TestTimeManager::testEventItemStates()
{
QFETCH(QDateTime, dateTime);
QFETCH(bool, boolValue);
QFETCH(bool, trigger);
// Set state
setBoolState(boolValue);
// Set time
NymeaCore::instance()->timeManager()->setTime(dateTime);
if (trigger) {
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
} else {
verifyRuleNotExecuted();
}
}
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", mockWithoutParamsActionTypeId);
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
NymeaCore::instance()->timeManager()->setTime(dateTime.addSecs(-2));
NymeaCore::instance()->timeManager()->setTime(dateTime.addSecs(-1));
verifyRuleNotExecuted();
// trigger
NymeaCore::instance()->timeManager()->setTime(dateTime);
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
// not triggering
NymeaCore::instance()->timeManager()->setTime(dateTime.addSecs(1));
NymeaCore::instance()->timeManager()->setTime(dateTime.addSecs(2));
verifyRuleNotExecuted();
// Now DISABLE the rule
QVariantMap enableDisableParams;
enableDisableParams.insert("ruleId", ruleId.toString());
response = injectAndWait("Rules.DisableRule", enableDisableParams);
verifyRuleError(response);
// trigger
NymeaCore::instance()->timeManager()->setTime(dateTime.addSecs(-1));
NymeaCore::instance()->timeManager()->setTime(dateTime);
verifyRuleNotExecuted();
// Now ENABLE the rule again
response.clear();
response = injectAndWait("Rules.EnableRule", enableDisableParams);
verifyRuleError(response);
// trigger
NymeaCore::instance()->timeManager()->setTime(dateTime.addSecs(-1));
NymeaCore::instance()->timeManager()->setTime(dateTime);
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
// REMOVE rule
QVariantMap removeParams;
removeParams.insert("ruleId", ruleId);
response = injectAndWait("Rules.RemoveRule", removeParams);
verifyRuleError(response);
}
void TestTimeManager::initTimeManager()
{
cleanupMockHistory();
removeAllRules();
enableNotifications();
NymeaCore::instance()->timeManager()->stopTimer();
qDebug() << NymeaCore::instance()->timeManager()->currentTime().toString();
qDebug() << NymeaCore::instance()->timeManager()->currentDate().toString();
}
void TestTimeManager::verifyRuleExecuted(const ActionTypeId &actionTypeId)
{
// Verify rule got executed
QNetworkAccessManager nam;
QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*)));
QNetworkRequest request(QUrl(QString("http://localhost:%1/actionhistory").arg(QString::number(m_mockDevice1Port))));
QNetworkReply *reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
QByteArray actionHistory = reply->readAll();
QVERIFY2(actionTypeId == ActionTypeId(actionHistory), "Action not triggered");
reply->deleteLater();
}
void TestTimeManager::verifyRuleNotExecuted()
{
QNetworkAccessManager nam;
QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*)));
QNetworkRequest request(QUrl(QString("http://localhost:%1/actionhistory").arg(QString::number(m_mockDevice1Port))));
QNetworkReply *reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
QByteArray actionHistory = reply->readAll();
qWarning() << "actionHistory" << actionHistory;
QVERIFY2(actionHistory.isEmpty(), "Actfdsfadsion is triggered while it should not have been.");
reply->deleteLater();
}
void TestTimeManager::cleanupMockHistory() {
QNetworkAccessManager nam;
QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*)));
QNetworkRequest request(QUrl(QString("http://localhost:%1/clearactionhistory").arg(QString::number(m_mockDevice1Port))));
QNetworkReply *reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
}
void TestTimeManager::removeAllRules()
{
qDebug() << "Remove all rules";
QVariant response = injectAndWait("Rules.GetRules");
QVariantList ruleDescriptions = response.toMap().value("params").toMap().value("ruleDescriptions").toList();
QVariantMap removeParams;
foreach (const QVariant &ruleDescription, ruleDescriptions) {
removeParams.insert("ruleId", ruleDescription.toMap().value("id"));
response = injectAndWait("Rules.RemoveRule", removeParams);
verifyRuleError(response);
}
}
void TestTimeManager::setIntState(const int &value)
{
qDebug() << "Setting mock int state to" << value;
QVariantMap params;
params.insert("deviceId", m_mockDeviceId);
params.insert("stateTypeId", mockIntStateTypeId);
QVariant response = injectAndWait("Devices.GetStateValue", params);
verifyDeviceError(response);
int currentStateValue = response.toMap().value("params").toMap().value("value").toInt();
bool shouldGetNotification = currentStateValue != value;
QNetworkAccessManager nam;
QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*)));
QSignalSpy stateSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray)));
spy.clear();
QNetworkRequest request(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockIntStateTypeId.toString()).arg(value)));
QNetworkReply *reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
if (shouldGetNotification) {
stateSpy.wait(100);
// Wait for state changed notification
QVariantList stateChangedVariants = checkNotifications(stateSpy, "Devices.StateChanged");
QVERIFY2(stateChangedVariants.count() == 1, "Did not get Devices.StateChanged notification.");
QVariantMap notification = stateChangedVariants.first().toMap().value("params").toMap();
QVERIFY2(notification.contains("deviceId"), "Devices.StateChanged notification does not contain deviceId");
QVERIFY2(DeviceId(notification.value("deviceId").toString()) == m_mockDeviceId, "Devices.StateChanged notification does not contain the correct deviceId");
QVERIFY2(notification.contains("stateTypeId"), "Devices.StateChanged notification does not contain stateTypeId");
QVERIFY2(StateTypeId(notification.value("stateTypeId").toString()) == mockIntStateTypeId, "Devices.StateChanged notification does not contain the correct stateTypeId");
QVERIFY2(notification.contains("value"), "Devices.StateChanged notification does not contain new state value");
QVERIFY2(notification.value("value").toInt() == value, "Devices.StateChanged notification does not contain the new value");
}
}
void TestTimeManager::setBoolState(const bool &value)
{
qCDebug(dcTests()) << "Setting mock bool state to" << value;
// Get the current state value to check if we have to wait for state changed notfication
QVariantMap params;
params.insert("deviceId", m_mockDeviceId);
params.insert("stateTypeId", mockBoolStateTypeId);
QVariant response = injectAndWait("Devices.GetStateValue", params);
verifyDeviceError(response);
bool currentStateValue = response.toMap().value("params").toMap().value("value").toBool();
bool shouldGetNotification = currentStateValue != value;
QNetworkAccessManager nam;
QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*)));
QSignalSpy stateSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray)));
QNetworkRequest request(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockBoolStateTypeId.toString()).arg(value)));
QNetworkReply *reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
if (shouldGetNotification) {
stateSpy.wait(100);
// Wait for state changed notification
QVariantList stateChangedSignals = checkNotifications(stateSpy, "Devices.StateChanged");
QCOMPARE(stateChangedSignals.count(), 1);
QVariantMap notification = stateChangedSignals.first().toMap().value("params").toMap();
QVERIFY2(notification.contains("deviceId"), "Devices.StateChanged notification does not contain deviceId");
QVERIFY2(DeviceId(notification.value("deviceId").toString()) == m_mockDeviceId, "Devices.StateChanged notification does not contain the correct deviceId");
QVERIFY2(notification.contains("stateTypeId"), "Devices.StateChanged notification does not contain stateTypeId");
QVERIFY2(StateTypeId(notification.value("stateTypeId").toString()) == mockBoolStateTypeId, "Devices.StateChanged notification does not contain the correct stateTypeId");
QVERIFY2(notification.contains("value"), "Devices.StateChanged notification does not contain new state value");
QVERIFY2(notification.value("value").toBool() == value, "Devices.StateChanged notification does not contain the new value");
}
}
void TestTimeManager::triggerMockEvent1()
{
qDebug() << "Trigger mock event 1";
QNetworkAccessManager nam;
QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*)));
QSignalSpy eventSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray)));
QNetworkRequest request(QUrl(QString("http://localhost:%1/generateevent?eventtypeid=%2").arg(m_mockDevice1Port).arg(mockEvent1EventTypeId.toString())));
QNetworkReply *reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
eventSpy.wait(200);
QVariantList eventTriggerVariants = checkNotifications(eventSpy, "Events.EventTriggered");
QVERIFY2(eventTriggerVariants.count() == 1, "Did not get Events.EventTriggered notification.");
QVERIFY2(eventTriggerVariants.first().toMap().value("params").toMap().contains("event"), "Notification Events.EventTriggered does not contain event.");
QVariantMap eventMap = eventTriggerVariants.first().toMap().value("params").toMap().value("event").toMap();
QVERIFY2(eventMap.contains("deviceId"), "Events.EventTriggered notification does not contain deviceId");
QVERIFY2(DeviceId(eventMap.value("deviceId").toString()) == m_mockDeviceId, "Events.EventTriggered notification does not contain the correct deviceId");
QVERIFY2(eventMap.contains("eventTypeId"), "Events.EventTriggered notification does not contain eventTypeId");
QVERIFY2(EventTypeId(eventMap.value("eventTypeId").toString()) == mockEvent1EventTypeId, "Events.EventTriggered notification does not contain the correct eventTypeId");
}
QVariantMap TestTimeManager::createTimeEventItem(const QString &time, const QVariantMap &repeatingOption) const
{
QVariantMap calendarItem;
calendarItem.insert("time", time);
if (!repeatingOption.isEmpty())
calendarItem.insert("repeating", repeatingOption);
return calendarItem;
}
QVariantMap TestTimeManager::createTimeEventItem(const int &dateTime, const QVariantMap &repeatingOption) const
{
QVariantMap calendarItem;
calendarItem.insert("datetime", dateTime);
if (!repeatingOption.isEmpty())
calendarItem.insert("repeating", repeatingOption);
return calendarItem;
}
QVariantMap TestTimeManager::createTimeDescriptorTimeEvent(const QVariantMap &timeEventItem) const
{
QVariantMap timeDescriptorTimeEvent;
timeDescriptorTimeEvent.insert("timeEventItems", QVariantList() << timeEventItem);
return timeDescriptorTimeEvent;
}
QVariantMap TestTimeManager::createTimeDescriptorTimeEvent(const QVariantList &timeEventItems) const
{
QVariantMap timeDescriptorTimeEvent;
timeDescriptorTimeEvent.insert("timeEventItems", timeEventItems);
return timeDescriptorTimeEvent;
}
QVariantMap TestTimeManager::createCalendarItem(const QString &time, const uint &duration, const QVariantMap &repeatingOption) const
{
QVariantMap calendarItem;
calendarItem.insert("startTime", time);
calendarItem.insert("duration", duration);
if (!repeatingOption.isEmpty())
calendarItem.insert("repeating", repeatingOption);
return calendarItem;
}
QVariantMap TestTimeManager::createCalendarItem(const int &dateTime, const uint &duration, const QVariantMap &repeatingOption) const
{
QVariantMap calendarItem;
calendarItem.insert("datetime", dateTime);
calendarItem.insert("duration", duration);
if (!repeatingOption.isEmpty())
calendarItem.insert("repeating", repeatingOption);
return calendarItem;
}
QVariantMap TestTimeManager::createTimeDescriptorCalendar(const QVariantMap &calendarItem) const
{
QVariantMap timeDescriptorCalendar;
timeDescriptorCalendar.insert("calendarItems", QVariantList() << calendarItem);
return timeDescriptorCalendar;
}
QVariantMap TestTimeManager::createTimeDescriptorCalendar(const QVariantList &calendarItems) const
{
QVariantMap timeDescriptorCalendar;
timeDescriptorCalendar.insert("calendarItems", calendarItems);
return timeDescriptorCalendar;
}
#include "testtimemanager.moc"
QTEST_MAIN(TestTimeManager)