nymea/tests/auto/rules/testrules.cpp

3207 lines
146 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 "nymeasettings.h"
#include "servers/mocktcpserver.h"
#include "nymeacore.h"
using namespace nymeaserver;
class TestRules: public NymeaTestBase
{
Q_OBJECT
private:
void cleanupMockHistory();
void cleanupRules();
DeviceId addDisplayPinDevice();
QVariantMap createEventDescriptor(const DeviceId &deviceId, const EventTypeId &eventTypeId);
QVariantMap createActionWithParams(const DeviceId &deviceId);
QVariantMap createStateEvaluatorFromSingleDescriptor(const QVariantMap &stateDescriptor);
void setWritableStateValue(const DeviceId &deviceId, const StateTypeId &stateTypeId, const QVariant &value);
void verifyRuleExecuted(const ActionTypeId &actionTypeId);
void verifyRuleNotExecuted();
QVariant validIntStateBasedRule(const QString &name, const bool &executable, const bool &enabled);
void generateEvent(const EventTypeId &eventTypeId);
private slots:
void initTestCase();
void cleanup();
void emptyRule();
void getInvalidRule();
void addRemoveRules_data();
void addRemoveRules();
void editRules_data();
void editRules();
void executeRuleActions_data();
void executeRuleActions();
void findRule();
void removeInvalidRule();
void loadStoreConfig();
void evaluateEvent();
void evaluateEventParams();
void testStateEvaluator_data();
void testStateEvaluator();
void testStateEvaluator2_data();
void testStateEvaluator2();
void testStateEvaluator3_data();
void testStateEvaluator3();
void testChildEvaluator_data();
void testChildEvaluator();
void testStateChange();
void enableDisableRule();
void testEventBasedAction();
void testEventBasedRuleWithExitAction();
void testStateBasedAction();
void removePolicyUpdate();
void removePolicyCascade();
void removePolicyUpdateRendersUselessRule();
void testRuleActionParams_data();
void testRuleActionParams();
void testRuleActionPAramsFromEventParameter_data();
void testRuleActionPAramsFromEventParameter();
void testInitStatesActive();
void testInterfaceBasedEventRule();
void testInterfaceBasedStateRule();
void testLoopingRules();
void testScene();
void testHousekeeping_data();
void testHousekeeping();
};
void TestRules::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 TestRules::cleanupRules() {
QVariant response = injectAndWait("Rules.GetRules");
foreach (const QVariant &ruleDescription, response.toMap().value("params").toMap().value("ruleDescriptions").toList()) {
QVariantMap params;
params.insert("ruleId", ruleDescription.toMap().value("id").toString());
verifyRuleError(injectAndWait("Rules.RemoveRule", params));
}
}
DeviceId TestRules::addDisplayPinDevice()
{
// Discover device
QVariantList discoveryParams;
QVariantMap resultCountParam;
resultCountParam.insert("paramTypeId", mockDisplayPinDiscoveryResultCountParamTypeId);
resultCountParam.insert("value", 1);
discoveryParams.append(resultCountParam);
QVariantMap params;
params.insert("deviceClassId", mockDisplayPinDeviceClassId);
params.insert("discoveryParams", discoveryParams);
QVariant response = injectAndWait("Devices.GetDiscoveredDevices", params);
verifyDeviceError(response, Device::DeviceErrorNoError);
// Pair device
DeviceDescriptorId descriptorId = DeviceDescriptorId(response.toMap().value("params").toMap().value("deviceDescriptors").toList().first().toMap().value("id").toString());
params.clear();
params.insert("deviceClassId", mockDisplayPinDeviceClassId);
params.insert("name", "Display pin mock device");
params.insert("deviceDescriptorId", descriptorId.toString());
response = injectAndWait("Devices.PairDevice", params);
verifyDeviceError(response);
PairingTransactionId pairingTransactionId(response.toMap().value("params").toMap().value("pairingTransactionId").toString());
QString displayMessage = response.toMap().value("params").toMap().value("displayMessage").toString();
qDebug() << "displayMessage" << displayMessage;
params.clear();
params.insert("pairingTransactionId", pairingTransactionId.toString());
params.insert("secret", "243681");
response = injectAndWait("Devices.ConfirmPairing", params);
verifyDeviceError(response);
return DeviceId(response.toMap().value("params").toMap().value("deviceId").toString());
}
QVariantMap TestRules::createEventDescriptor(const DeviceId &deviceId, const EventTypeId &eventTypeId)
{
QVariantMap eventDescriptor;
eventDescriptor.insert("eventTypeId", eventTypeId);
eventDescriptor.insert("deviceId", deviceId);
return eventDescriptor;
}
QVariantMap TestRules::createActionWithParams(const DeviceId &deviceId)
{
QVariantMap action;
QVariantList ruleActionParams;
QVariantMap param1;
param1.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
param1.insert("value", 4);
QVariantMap param2;
param2.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId);
param2.insert("value", true);
ruleActionParams.append(param1);
ruleActionParams.append(param2);
action.insert("deviceId", deviceId);
action.insert("actionTypeId", mockWithParamsActionTypeId);
action.insert("ruleActionParams", ruleActionParams);
return action;
}
QVariantMap TestRules::createStateEvaluatorFromSingleDescriptor(const QVariantMap &stateDescriptor)
{
QVariantMap stateEvaluator;
stateEvaluator.insert("stateDescriptor", stateDescriptor);
return stateEvaluator;
}
void TestRules::setWritableStateValue(const DeviceId &deviceId, const StateTypeId &stateTypeId, const QVariant &value)
{
QVariantMap params;
params.insert("deviceId", deviceId);
params.insert("stateTypeId", stateTypeId);
QVariant response = injectAndWait("Devices.GetStateValue", params);
verifyDeviceError(response);
QVariant currentStateValue = response.toMap().value("params").toMap().value("value");
bool shouldGetNotification = currentStateValue != value;
QSignalSpy stateSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray)));
QVariantMap paramMap;
paramMap.insert("paramTypeId", stateTypeId.toString());
paramMap.insert("value", value);
params.clear(); response.clear();
params.insert("deviceId", deviceId);
params.insert("actionTypeId", stateTypeId.toString());
params.insert("params", QVariantList() << paramMap);
printJson(params);
response = injectAndWait("Actions.ExecuteAction", params);
qCDebug(dcTests()) << "Execute action response" << response;
verifyDeviceError(response);
if (shouldGetNotification) {
stateSpy.wait(200);
// 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()) == deviceId, "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()) == stateTypeId, "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") == QVariant(value), "Devices.StateChanged notification does not contain the new value");
}
}
void TestRules::verifyRuleExecuted(const ActionTypeId &actionTypeId)
{
// Verify rule got executed
bool actionFound = false;
QByteArray actionHistory;
int i = 0;
while (!actionFound && i < 50) {
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);
actionHistory = reply->readAll();
actionFound = actionTypeId == ActionTypeId(actionHistory);
reply->deleteLater();
if (!actionFound) {
QTest::qWait(100);
}
i++;
}
QVERIFY2(actionFound, "Action not triggered. Current action history: \"" + actionHistory + "\"");
}
void TestRules::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();
QVERIFY2(actionHistory.isEmpty(), "Action is triggered while it should not have been. Current action history: \"" + actionHistory + "\"");
reply->deleteLater();
}
/***********************************************************************/
void TestRules::cleanup() {
cleanupMockHistory();
cleanupRules();
}
void TestRules::emptyRule()
{
QVariantMap params;
params.insert("name", QString());
params.insert("actions", QVariantList());
QVariant response = injectAndWait("Rules.AddRule", params);
verifyRuleError(response, RuleEngine::RuleErrorInvalidRuleFormat);
}
void TestRules::getInvalidRule()
{
QVariantMap params;
params.insert("ruleId", QUuid::createUuid());
QVariant response = injectAndWait("Rules.GetRuleDetails", params);
verifyRuleError(response, RuleEngine::RuleErrorRuleNotFound);
}
QVariant TestRules::validIntStateBasedRule(const QString &name, const bool &executable, const bool &enabled)
{
QVariantMap params;
// StateDescriptor
QVariantMap stateDescriptor;
stateDescriptor.insert("stateTypeId", mockIntStateTypeId);
stateDescriptor.insert("deviceId", m_mockDeviceId);
stateDescriptor.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorLess));
stateDescriptor.insert("value", 25);
// StateEvaluator
QVariantMap stateEvaluator;
stateEvaluator.insert("stateDescriptor", stateDescriptor);
stateEvaluator.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd));
// RuleAction
QVariantMap action;
action.insert("actionTypeId", mockWithParamsActionTypeId);
QVariantList actionParams;
QVariantMap param1;
param1.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
param1.insert("value", 5);
actionParams.append(param1);
QVariantMap param2;
param2.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId);
param2.insert("value", true);
actionParams.append(param2);
action.insert("deviceId", m_mockDeviceId);
action.insert("ruleActionParams", actionParams);
// RuleExitAction
QVariantMap exitAction;
exitAction.insert("actionTypeId", mockWithoutParamsActionTypeId);
exitAction.insert("deviceId", m_mockDeviceId);
exitAction.insert("ruleActionParams", QVariantList());
params.insert("name", name);
params.insert("enabled", enabled);
params.insert("executable", executable);
params.insert("stateEvaluator", stateEvaluator);
params.insert("actions", QVariantList() << action);
params.insert("exitActions", QVariantList() << exitAction);
return params;
}
void TestRules::generateEvent(const EventTypeId &eventTypeId)
{
// Trigger an event
QNetworkAccessManager nam;
QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*)));
// trigger event in mock device
QNetworkRequest request(QUrl(QString("http://localhost:%1/generateevent?eventtypeid=%2").arg(m_mockDevice1Port).arg(eventTypeId.toString())));
QNetworkReply *reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
}
void TestRules::initTestCase()
{
NymeaTestBase::initTestCase();
QLoggingCategory::setFilterRules("*.debug=false\n"
"Tests.debug=true\n"
"RuleEngine.debug=true\n"
// "RuleEngineDebug.debug=true\n"
"MockDevice.*=true");
}
void TestRules::addRemoveRules_data()
{
// RuleAction
QVariantMap validActionNoParams;
validActionNoParams.insert("actionTypeId", mockWithoutParamsActionTypeId);
validActionNoParams.insert("deviceId", m_mockDeviceId);
validActionNoParams.insert("ruleActionParams", QVariantList());
QVariantMap invalidAction;
invalidAction.insert("actionTypeId", ActionTypeId());
invalidAction.insert("deviceId", m_mockDeviceId);
invalidAction.insert("ruleActionParams", QVariantList());
// RuleExitAction
QVariantMap validExitActionNoParams;
validExitActionNoParams.insert("actionTypeId", mockWithoutParamsActionTypeId);
validExitActionNoParams.insert("deviceId", m_mockDeviceId);
validExitActionNoParams.insert("ruleActionParams", QVariantList());
QVariantMap invalidExitAction;
invalidExitAction.insert("actionTypeId", ActionTypeId());
invalidExitAction.insert("deviceId", m_mockDeviceId);
invalidExitAction.insert("ruleActionParams", QVariantList());
// StateDescriptor
QVariantMap stateDescriptor;
stateDescriptor.insert("stateTypeId", mockIntStateTypeId);
stateDescriptor.insert("deviceId", m_mockDeviceId);
stateDescriptor.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorLess));
stateDescriptor.insert("value", 20);
// StateEvaluator
QVariantMap validStateEvaluator;
validStateEvaluator.insert("stateDescriptor", stateDescriptor);
validStateEvaluator.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd));
QVariantMap invalidStateEvaluator;
stateDescriptor.remove("deviceId");
invalidStateEvaluator.insert("stateDescriptor", stateDescriptor);
// EventDescriptor
QVariantMap validEventDescriptor1;
validEventDescriptor1.insert("eventTypeId", mockEvent1EventTypeId);
validEventDescriptor1.insert("deviceId", m_mockDeviceId);
validEventDescriptor1.insert("paramDescriptors", QVariantList());
QVariantMap validEventDescriptor2;
validEventDescriptor2.insert("eventTypeId", mockEvent2EventTypeId);
validEventDescriptor2.insert("deviceId", m_mockDeviceId);
QVariantList params;
QVariantMap param1;
param1.insert("paramTypeId", mockEvent2EventIntParamParamTypeId);
param1.insert("value", 3);
param1.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals));
params.append(param1);
validEventDescriptor2.insert("paramDescriptors", params);
QVariantMap validEventDescriptor3;
validEventDescriptor3.insert("eventTypeId", mockEvent2EventTypeId);
validEventDescriptor3.insert("deviceId", m_mockDeviceId);
validEventDescriptor3.insert("paramDescriptors", QVariantList());
// EventDescriptorList
QVariantList eventDescriptorList;
eventDescriptorList.append(validEventDescriptor1);
eventDescriptorList.append(validEventDescriptor2);
QVariantMap invalidEventDescriptor;
invalidEventDescriptor.insert("eventTypeId", mockEvent1EventTypeId);
invalidEventDescriptor.insert("deviceId", DeviceId());
invalidEventDescriptor.insert("paramDescriptors", QVariantList());
// RuleAction event based
QVariantMap validActionEventBased;
validActionEventBased.insert("actionTypeId", mockWithParamsActionTypeId);
validActionEventBased.insert("deviceId", m_mockDeviceId);
QVariantMap validActionEventBasedParam1;
validActionEventBasedParam1.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
validActionEventBasedParam1.insert("eventTypeId", mockEvent2EventTypeId);
validActionEventBasedParam1.insert("eventParamTypeId", mockEvent2EventIntParamParamTypeId);
QVariantMap validActionEventBasedParam2;
validActionEventBasedParam2.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId);
validActionEventBasedParam2.insert("value", false);
validActionEventBased.insert("ruleActionParams", QVariantList() << validActionEventBasedParam1 << validActionEventBasedParam2);
QVariantMap invalidActionEventBased;
invalidActionEventBased.insert("actionTypeId", mockWithoutParamsActionTypeId);
invalidActionEventBased.insert("deviceId", m_mockDeviceId);
validActionEventBasedParam1.insert("value", 10);
invalidActionEventBased.insert("ruleActionParams", QVariantList() << validActionEventBasedParam1);
QVariantMap invalidActionEventBased2;
invalidActionEventBased2.insert("actionTypeId", mockWithParamsActionTypeId);
invalidActionEventBased2.insert("deviceId", m_mockDeviceId);
QVariantMap invalidActionEventBasedParam2;
invalidActionEventBasedParam2.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
invalidActionEventBasedParam2.insert("eventTypeId", mockEvent1EventTypeId);
invalidActionEventBasedParam2.insert("eventParamTypeId", "value");
QVariantMap invalidActionEventBasedParam3;
invalidActionEventBasedParam3.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId);
invalidActionEventBasedParam3.insert("value", 2);
invalidActionEventBased2.insert("ruleActionParams", QVariantList() << invalidActionEventBasedParam2 << invalidActionEventBasedParam3);
QVariantMap invalidActionEventBased3;
invalidActionEventBased3.insert("actionTypeId", mockWithParamsActionTypeId);
invalidActionEventBased3.insert("deviceId", m_mockDeviceId);
QVariantMap invalidActionEventBasedParam4;
invalidActionEventBasedParam4.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
invalidActionEventBasedParam4.insert("eventTypeId", mockEvent1EventTypeId);
invalidActionEventBasedParam4.insert("eventParamTypeId", mockEvent2EventIntParamParamTypeId);
invalidActionEventBased3.insert("ruleActionParams", QVariantList() << invalidActionEventBasedParam4);
QTest::addColumn<bool>("enabled");
QTest::addColumn<QVariantMap>("action1");
QTest::addColumn<QVariantMap>("exitAction1");
QTest::addColumn<QVariantMap>("eventDescriptor");
QTest::addColumn<QVariantList>("eventDescriptorList");
QTest::addColumn<QVariantMap>("stateEvaluator");
QTest::addColumn<RuleEngine::RuleError>("error");
QTest::addColumn<bool>("jsonError");
QTest::addColumn<QString>("name");
// Rules with event based actions
QTest::newRow("valid rule. enabled, 1 Action (eventBased), 1 EventDescriptor, name") << true << validActionEventBased << QVariantMap() << validEventDescriptor3 << QVariantList() << QVariantMap() << RuleEngine::RuleErrorNoError << true << "ActionEventRule1";
QTest::newRow("invalid rule. enabled, 1 Action (eventBased), 1 EventDescriptor, name") << true << invalidActionEventBased2 << QVariantMap() << validEventDescriptor3 << QVariantList() << QVariantMap() << RuleEngine::RuleErrorInvalidRuleActionParameter << false << "TestRule";
QTest::newRow("invalid rule. enabled, 1 Action (eventBased), types not matching, name") << true << invalidActionEventBased3 << QVariantMap() << validEventDescriptor1 << QVariantList() << QVariantMap() << RuleEngine::RuleErrorTypesNotMatching << false << "TestRule";
QTest::newRow("invalid rule. enabled, 1 Action (eventBased), 1 EventDescriptor, name") << true << invalidActionEventBased << QVariantMap() << validEventDescriptor2 << QVariantList() << QVariantMap() << RuleEngine::RuleErrorTypesNotMatching << false << "TestRule";
QTest::newRow("invalid rule. enabled, 1 Action (eventBased), 1 StateEvaluator, name") << true << validActionEventBased << QVariantMap() << QVariantMap() << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorInvalidRuleActionParameter << false << "TestRule";
QTest::newRow("invalid rule. enabled, 1 Action (eventBased), 1 EventDescriptor, name") << true << validActionEventBased << validActionEventBased << validEventDescriptor2 << QVariantList() << QVariantMap() << RuleEngine::RuleErrorInvalidRuleFormat << false << "TestRule";
QTest::newRow("invalid rule. enabled, 1 Action, 1 ExitAction (EventBased), name") << true << validActionNoParams << validActionEventBased << validEventDescriptor2 << QVariantList() << QVariantMap() << RuleEngine::RuleErrorInvalidRuleFormat << false << "TestRule";
// Rules with exit actions
QTest::newRow("valid rule. enabled, 1 Action, 1 Exit Action, 1 StateEvaluator, name") << true << validActionNoParams << validExitActionNoParams << QVariantMap() << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorNoError << true << "TestRule";
QTest::newRow("valid rule. disabled, 1 Action, 1 Exit Action, 1 StateEvaluator, name") << false << validActionNoParams << validExitActionNoParams << QVariantMap() << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorNoError << true << "TestRule";
QTest::newRow("invalid rule. disabled, 1 Action, 1 invalid Exit Action, 1 StateEvaluator, name") << false << validActionNoParams << invalidExitAction << QVariantMap() << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorActionTypeNotFound << false << "TestRule";
QTest::newRow("valid rule. 1 Action, 1 Exit Action, 1 EventDescriptor, 1 StateEvaluator, name") << true << validActionNoParams << validExitActionNoParams << validEventDescriptor1 << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorNoError << false << "TestRule";
QTest::newRow("invalid rule. 1 Action, 1 Exit Action, eventDescriptorList, NO StateEvaluator, name")<< true << validActionNoParams << validExitActionNoParams << QVariantMap() << eventDescriptorList << QVariantMap() << RuleEngine::RuleErrorInvalidRuleFormat << false << "TestRule";
QTest::newRow("valid rule. 1 Action, 1 Exit Action, eventDescriptorList, 1 StateEvaluator, name") << true << validActionNoParams << validExitActionNoParams << QVariantMap() << eventDescriptorList << validStateEvaluator << RuleEngine::RuleErrorNoError << false << "TestRule";
// Rules without exit actions
QTest::newRow("valid rule. enabled, 1 EventDescriptor, StateEvaluator, 1 Action, name") << true << validActionNoParams << QVariantMap() << validEventDescriptor1 << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorNoError << true << "TestRule";
QTest::newRow("valid rule. disabled, 1 EventDescriptor, StateEvaluator, 1 Action, name") << false << validActionNoParams << QVariantMap() << validEventDescriptor1 << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorNoError << true << "TestRule";
QTest::newRow("valid rule. 2 EventDescriptors, 1 Action, name") << true << validActionNoParams << QVariantMap() << QVariantMap() << eventDescriptorList << validStateEvaluator << RuleEngine::RuleErrorNoError << true << "TestRule";
QTest::newRow("invalid action") << true << invalidAction << QVariantMap() << validEventDescriptor1 << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorActionTypeNotFound << false << "TestRule";
QTest::newRow("invalid event descriptor") << true << validActionNoParams << QVariantMap() << invalidEventDescriptor << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorEventTypeNotFound << false << "TestRule";
}
void TestRules::addRemoveRules()
{
QFETCH(bool, enabled);
QFETCH(QVariantMap, action1);
QFETCH(QVariantMap, exitAction1);
QFETCH(QVariantMap, eventDescriptor);
QFETCH(QVariantList, eventDescriptorList);
QFETCH(QVariantMap, stateEvaluator);
QFETCH(RuleEngine::RuleError, error);
QFETCH(bool, jsonError);
QFETCH(QString, name);
QVariantMap params;
params.insert("name", name);
QVariantList actions;
actions.append(action1);
params.insert("actions", actions);
if (!eventDescriptor.isEmpty()) {
params.insert("eventDescriptors", QVariantList() << eventDescriptor);
}
if (!eventDescriptorList.isEmpty()) {
params.insert("eventDescriptors", eventDescriptorList);
}
QVariantList exitActions;
if (!exitAction1.isEmpty()) {
exitActions.append(exitAction1);
params.insert("exitActions", exitActions);
}
params.insert("stateEvaluator", stateEvaluator);
if (!enabled) {
params.insert("enabled", enabled);
}
QVariant response = injectAndWait("Rules.AddRule", params);
if (!jsonError) {
verifyRuleError(response, error);
}
RuleId newRuleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toString());
response = injectAndWait("Rules.GetRules");
QVariantList rules = response.toMap().value("params").toMap().value("ruleDescriptions").toList();
if (error != RuleEngine::RuleErrorNoError) {
QVERIFY2(rules.count() == 0, "There should be no rules.");
return;
}
QVERIFY2(rules.count() == 1, "There should be exactly one rule");
QCOMPARE(RuleId(rules.first().toMap().value("id").toString()), newRuleId);
params.clear();
params.insert("ruleId", newRuleId);
response = injectAndWait("Rules.GetRuleDetails", params);
QVariantMap rule = response.toMap().value("params").toMap().value("rule").toMap();
qDebug() << rule.value("name").toString();
QVERIFY2(rule.value("enabled").toBool() == enabled, "Rule enabled state doesn't match");
QVariantList eventDescriptors = rule.value("eventDescriptors").toList();
if (!eventDescriptor.isEmpty()) {
QVERIFY2(eventDescriptors.count() == 1, "There should be exactly one eventDescriptor");
QVERIFY2(eventDescriptors.first().toMap() == eventDescriptor, "Event descriptor doesn't match");
} else if (eventDescriptorList.isEmpty()){
QVERIFY2(eventDescriptors.count() == eventDescriptorList.count(), QString("There should be exactly %1 eventDescriptor").arg(eventDescriptorList.count()).toLatin1().data());
foreach (const QVariant &eventDescriptorVariant, eventDescriptorList) {
bool found = false;
foreach (const QVariant &replyEventDescriptorVariant, eventDescriptors) {
if (eventDescriptorVariant.toMap().value("deviceId") == replyEventDescriptorVariant.toMap().value("deviceId") &&
eventDescriptorVariant.toMap().value("eventTypeId") == replyEventDescriptorVariant.toMap().value("eventTypeId")) {
found = true;
QVERIFY2(eventDescriptorVariant == replyEventDescriptorVariant, "Event descriptor doesn't match");
}
}
QVERIFY2(found, "Missing event descriptor");
}
}
QVariantList replyActions = rule.value("actions").toList();
QVERIFY2(actions == replyActions, "Actions don't match");
QVariantList replyExitActions = rule.value("exitActions").toList();
QVERIFY2(exitActions == replyExitActions, "ExitActions don't match");
params.clear();
params.insert("ruleId", newRuleId);
response = injectAndWait("Rules.RemoveRule", params);
verifyRuleError(response);
response = injectAndWait("Rules.GetRules");
rules = response.toMap().value("params").toMap().value("ruleDescriptions").toList();
QVERIFY2(rules.count() == 0, "There should be no rules.");
}
void TestRules::editRules_data()
{
// RuleAction
QVariantMap validActionNoParams;
validActionNoParams.insert("actionTypeId", mockWithoutParamsActionTypeId);
validActionNoParams.insert("deviceId", m_mockDeviceId);
validActionNoParams.insert("ruleActionParams", QVariantList());
QVariantMap invalidAction;
invalidAction.insert("actionTypeId", ActionTypeId());
invalidAction.insert("deviceId", m_mockDeviceId);
invalidAction.insert("ruleActionParams", QVariantList());
// RuleExitAction
QVariantMap validExitActionNoParams;
validExitActionNoParams.insert("actionTypeId", mockWithoutParamsActionTypeId);
validExitActionNoParams.insert("deviceId", m_mockDeviceId);
validExitActionNoParams.insert("ruleActionParams", QVariantList());
QVariantMap invalidExitAction;
invalidExitAction.insert("actionTypeId", ActionTypeId());
invalidExitAction.insert("deviceId", m_mockDeviceId);
invalidExitAction.insert("ruleActionParams", QVariantList());
// StateDescriptor
QVariantMap stateDescriptor;
stateDescriptor.insert("stateTypeId", mockIntStateTypeId);
stateDescriptor.insert("deviceId", m_mockDeviceId);
stateDescriptor.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorLess));
stateDescriptor.insert("value", 20);
// StateEvaluator
QVariantMap validStateEvaluator;
validStateEvaluator.insert("stateDescriptor", stateDescriptor);
validStateEvaluator.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd));
QVariantMap invalidStateEvaluator;
stateDescriptor.remove("deviceId");
invalidStateEvaluator.insert("stateDescriptor", stateDescriptor);
// EventDescriptor
QVariantMap validEventDescriptor1;
validEventDescriptor1.insert("eventTypeId", mockEvent1EventTypeId);
validEventDescriptor1.insert("deviceId", m_mockDeviceId);
validEventDescriptor1.insert("paramDescriptors", QVariantList());
QVariantMap validEventDescriptor2;
validEventDescriptor2.insert("eventTypeId", mockEvent2EventTypeId);
validEventDescriptor2.insert("deviceId", m_mockDeviceId);
QVariantList params;
QVariantMap param1;
param1.insert("paramTypeId", mockEvent2EventIntParamParamTypeId);
param1.insert("value", 3);
param1.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals));
params.append(param1);
validEventDescriptor2.insert("paramDescriptors", params);
QVariantMap validEventDescriptor3;
validEventDescriptor3.insert("eventTypeId", mockEvent2EventTypeId);
validEventDescriptor3.insert("deviceId", m_mockDeviceId);
validEventDescriptor3.insert("paramDescriptors", QVariantList());
// EventDescriptorList
QVariantList eventDescriptorList;
eventDescriptorList.append(validEventDescriptor1);
eventDescriptorList.append(validEventDescriptor2);
QVariantMap invalidEventDescriptor;
invalidEventDescriptor.insert("eventTypeId", mockEvent1EventTypeId);
invalidEventDescriptor.insert("deviceId", DeviceId());
invalidEventDescriptor.insert("paramDescriptors", QVariantList());
// RuleAction event based
QVariantMap validActionEventBased;
validActionEventBased.insert("actionTypeId", mockWithParamsActionTypeId);
validActionEventBased.insert("deviceId", m_mockDeviceId);
QVariantMap validActionEventBasedParam1;
validActionEventBasedParam1.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
validActionEventBasedParam1.insert("eventTypeId", mockEvent2EventTypeId);
validActionEventBasedParam1.insert("eventParamTypeId", mockEvent2EventIntParamParamTypeId);
QVariantMap validActionEventBasedParam2;
validActionEventBasedParam2.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId);
validActionEventBasedParam2.insert("value", false);
validActionEventBased.insert("ruleActionParams", QVariantList() << validActionEventBasedParam1 << validActionEventBasedParam2);
QVariantMap invalidActionEventBased;
invalidActionEventBased.insert("actionTypeId", mockWithoutParamsActionTypeId);
invalidActionEventBased.insert("deviceId", m_mockDeviceId);
validActionEventBasedParam1.insert("value", 10);
invalidActionEventBased.insert("ruleActionParams", QVariantList() << validActionEventBasedParam1);
QVariantMap invalidActionEventBased2;
invalidActionEventBased2.insert("actionTypeId", mockWithParamsActionTypeId);
invalidActionEventBased2.insert("deviceId", m_mockDeviceId);
QVariantMap invalidActionEventBasedParam2;
invalidActionEventBasedParam2.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
invalidActionEventBasedParam2.insert("eventTypeId", mockEvent1EventTypeId);
invalidActionEventBasedParam2.insert("eventParamTypeId", "value");
QVariantMap invalidActionEventBasedParam3;
invalidActionEventBasedParam3.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId);
invalidActionEventBasedParam3.insert("value", 2);
invalidActionEventBased2.insert("ruleActionParams", QVariantList() << invalidActionEventBasedParam2 << invalidActionEventBasedParam3);
QVariantMap invalidActionEventBased3;
invalidActionEventBased3.insert("actionTypeId", mockWithParamsActionTypeId);
invalidActionEventBased3.insert("deviceId", m_mockDeviceId);
QVariantMap invalidActionEventBasedParam4;
invalidActionEventBasedParam4.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
invalidActionEventBasedParam4.insert("eventTypeId", mockEvent1EventTypeId);
invalidActionEventBasedParam4.insert("eventParamTypeId", mockEvent2EventIntParamParamTypeId);
invalidActionEventBased3.insert("ruleActionParams", QVariantList() << invalidActionEventBasedParam4);
QTest::addColumn<bool>("enabled");
QTest::addColumn<QVariantMap>("action");
QTest::addColumn<QVariantMap>("exitAction");
QTest::addColumn<QVariantMap>("eventDescriptor");
QTest::addColumn<QVariantList>("eventDescriptorList");
QTest::addColumn<QVariantMap>("stateEvaluator");
QTest::addColumn<RuleEngine::RuleError>("error");
QTest::addColumn<QString>("name");
// Rules with event based actions
QTest::newRow("valid rule. enabled, 1 Action (eventBased), 1 EventDescriptor, name") << true << validActionEventBased << QVariantMap() << validEventDescriptor3 << QVariantList() << QVariantMap() << RuleEngine::RuleErrorNoError << "ActionEventRule1";
QTest::newRow("invalid rule. enabled, 1 Action (eventBased), 1 EventDescriptor, name") << true << invalidActionEventBased2 << QVariantMap() << validEventDescriptor3 << QVariantList() << QVariantMap() << RuleEngine::RuleErrorInvalidRuleActionParameter << "TestRule";
QTest::newRow("invalid rule. enabled, 1 Action (eventBased), types not matching, name") << true << invalidActionEventBased3 << QVariantMap() << validEventDescriptor1 << QVariantList() << QVariantMap() << RuleEngine::RuleErrorTypesNotMatching << "TestRule";
QTest::newRow("invalid rule. enabled, 1 Action (eventBased), 1 EventDescriptor, name") << true << invalidActionEventBased << QVariantMap() << validEventDescriptor2 << QVariantList() << QVariantMap() << RuleEngine::RuleErrorTypesNotMatching << "TestRule";
QTest::newRow("invalid rule. enabled, 1 Action (eventBased), 1 StateEvaluator, name") << true << validActionEventBased << QVariantMap() << QVariantMap() << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorInvalidRuleActionParameter << "TestRule";
QTest::newRow("invalid rule. enabled, 1 Action (eventBased), 1 EventDescriptor, name") << true << validActionEventBased << validActionEventBased << validEventDescriptor2 << QVariantList() << QVariantMap() << RuleEngine::RuleErrorInvalidRuleFormat << "TestRule";
QTest::newRow("invalid rule. enabled, 1 Action, 1 ExitAction (EventBased), name") << true << validActionNoParams << validActionEventBased << validEventDescriptor2 << QVariantList() << QVariantMap() << RuleEngine::RuleErrorInvalidRuleFormat << "TestRule";
// Rules with exit actions
QTest::newRow("valid rule. enabled, 1 Action, 1 Exit Action, 1 StateEvaluator, name") << true << validActionNoParams << validExitActionNoParams << QVariantMap() << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorNoError << "TestRule";
QTest::newRow("valid rule. disabled, 1 Action, 1 Exit Action, 1 StateEvaluator, name") << false << validActionNoParams << validExitActionNoParams << QVariantMap() << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorNoError << "TestRule";
QTest::newRow("valid rule. 1 Action, 1 Exit Action, 1 EventDescriptor, 1 StateEvaluator, name") << true << validActionNoParams << validExitActionNoParams << validEventDescriptor1 << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorNoError << "TestRule";
QTest::newRow("valid rule. 1 Action, 1 Exit Action, eventDescriptorList, 1 StateEvaluator, name") << true << validActionNoParams << validExitActionNoParams << QVariantMap() << eventDescriptorList << validStateEvaluator << RuleEngine::RuleErrorNoError << "TestRule";
// Rules without exit actions
QTest::newRow("valid rule. enabled, 1 EventDescriptor, StateEvaluator, 1 Action, name") << true << validActionNoParams << QVariantMap() << validEventDescriptor1 << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorNoError << "TestRule";
QTest::newRow("valid rule. disabled, 1 EventDescriptor, StateEvaluator, 1 Action, name") << false << validActionNoParams << QVariantMap() << validEventDescriptor1 << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorNoError << "TestRule";
QTest::newRow("valid rule. 2 EventDescriptors, 1 Action, name") << true << validActionNoParams << QVariantMap() << QVariantMap() << eventDescriptorList << validStateEvaluator << RuleEngine::RuleErrorNoError << "TestRule";
}
void TestRules::editRules()
{
QFETCH(bool, enabled);
QFETCH(QVariantMap, action);
QFETCH(QVariantMap, exitAction);
QFETCH(QVariantMap, eventDescriptor);
QFETCH(QVariantList, eventDescriptorList);
QFETCH(QVariantMap, stateEvaluator);
QFETCH(RuleEngine::RuleError, error);
QFETCH(QString, name);
// Add the rule we want to edit
QVariantList eventParamDescriptors;
QVariantMap eventDescriptor1;
eventDescriptor1.insert("eventTypeId", mockEvent1EventTypeId);
eventDescriptor1.insert("deviceId", m_mockDeviceId);
eventDescriptor1.insert("paramDescriptors", QVariantList());
QVariantMap eventDescriptor2;
eventDescriptor2.insert("eventTypeId", mockEvent2EventTypeId);
eventDescriptor2.insert("deviceId", m_mockDeviceId);
eventDescriptor2.insert("paramDescriptors", QVariantList());
QVariantMap eventParam1;
eventParam1.insert("paramTypeId", mockEvent2EventIntParamParamTypeId);
eventParam1.insert("value", 3);
eventParam1.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals));
eventParamDescriptors.append(eventParam1);
eventDescriptor2.insert("paramDescriptors", eventParamDescriptors);
QVariantList eventDescriptorList1;
eventDescriptorList1.append(eventDescriptor1);
eventDescriptorList1.append(eventDescriptor2);
QVariantMap stateEvaluator0;
QVariantMap stateDescriptor1;
stateDescriptor1.insert("deviceId", m_mockDeviceId);
stateDescriptor1.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals));
stateDescriptor1.insert("stateTypeId", mockIntStateTypeId);
stateDescriptor1.insert("value", 1);
QVariantMap stateDescriptor2;
stateDescriptor2.insert("deviceId", m_mockDeviceId);
stateDescriptor2.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals));
stateDescriptor2.insert("stateTypeId", mockBoolStateTypeId);
stateDescriptor2.insert("value", true);
QVariantMap stateEvaluator1;
stateEvaluator1.insert("stateDescriptor", stateDescriptor1);
stateEvaluator1.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd));
QVariantMap stateEvaluator2;
stateEvaluator2.insert("stateDescriptor", stateDescriptor2);
stateEvaluator2.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd));
QVariantList childEvaluators;
childEvaluators.append(stateEvaluator1);
childEvaluators.append(stateEvaluator2);
stateEvaluator0.insert("childEvaluators", childEvaluators);
stateEvaluator0.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd));
QVariantMap action1;
action1.insert("actionTypeId", mockWithoutParamsActionTypeId);
action1.insert("deviceId", m_mockDeviceId);
action1.insert("ruleActionParams", QVariantList());
QVariantMap action2;
action2.insert("actionTypeId", mockWithParamsActionTypeId);
qDebug() << "got action id" << mockWithParamsActionTypeId;
action2.insert("deviceId", m_mockDeviceId);
QVariantList action2Params;
QVariantMap action2Param1;
action2Param1.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
action2Param1.insert("value", 5);
action2Params.append(action2Param1);
QVariantMap action2Param2;
action2Param2.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId);
action2Param2.insert("value", true);
action2Params.append(action2Param2);
action2.insert("ruleActionParams", action2Params);
// RuleAction event based
QVariantMap validActionEventBased;
validActionEventBased.insert("actionTypeId", mockWithParamsActionTypeId);
validActionEventBased.insert("deviceId", m_mockDeviceId);
QVariantMap validActionEventBasedParam1;
validActionEventBasedParam1.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
validActionEventBasedParam1.insert("eventTypeId", mockEvent2EventTypeId);
validActionEventBasedParam1.insert("eventParamTypeId", mockEvent2EventIntParamParamTypeId);
QVariantMap validActionEventBasedParam2;
validActionEventBasedParam2.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId);
validActionEventBasedParam2.insert("value", false);
validActionEventBased.insert("ruleActionParams", QVariantList() << validActionEventBasedParam1 << validActionEventBasedParam2);
QVariantList validEventDescriptors3;
QVariantMap validEventDescriptor3;
validEventDescriptor3.insert("eventTypeId", mockEvent2EventTypeId);
validEventDescriptor3.insert("deviceId", m_mockDeviceId);
validEventDescriptor3.insert("paramDescriptors", QVariantList());
validEventDescriptors3.append(validEventDescriptor3);
QVariantMap params;
QVariantList actions;
actions.append(action1);
actions.append(action2);
params.insert("actions", actions);
params.insert("eventDescriptors", eventDescriptorList1);
params.insert("stateEvaluator", stateEvaluator0);
params.insert("name", "TestRule");
QVariant response = injectAndWait("Rules.AddRule", params);
RuleId ruleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toString());
verifyRuleError(response);
// enable notifications
QCOMPARE(enableNotifications(), true);
// now create the new rule and edit the original one
params.clear();
params.insert("ruleId", ruleId.toString());
params.insert("name", name);
if (!eventDescriptor.isEmpty()) {
params.insert("eventDescriptors", QVariantList() << eventDescriptor);
}
if (!eventDescriptorList.isEmpty()) {
params.insert("eventDescriptors", eventDescriptorList);
}
actions.clear();
actions.append(action);
params.insert("actions", actions);
QVariantList exitActions;
if (!exitAction.isEmpty()) {
exitActions.append(exitAction);
params.insert("exitActions", exitActions);
}
params.insert("stateEvaluator", stateEvaluator);
if (!enabled) {
params.insert("enabled", enabled);
}
// Setup connection to mock client
QSignalSpy clientSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray)));
response.clear();
response = injectAndWait("Rules.EditRule", params);
verifyRuleError(response, error);
if (error == RuleEngine::RuleErrorNoError){
clientSpy.wait(1);
// We need to get exactly 2 replies. The actual reply and the Changed notification
// Make sure there are no other notifications (e.g. RuleAdded or similar)
QCOMPARE(clientSpy.count(), 2);
QVariant notification = checkNotification(clientSpy, "Rules.RuleConfigurationChanged");
QVERIFY2(notification != QVariant(), "not received \"Rules.RuleConfigurationChanged\" notification");
// now check if the received rule matches the our new rule
QVariantMap rule = response.toMap().value("params").toMap().value("rule").toMap();
QVERIFY2(rule.value("enabled").toBool() == enabled, "Rule enabled state doesn't match");
QVariantList eventDescriptors = rule.value("eventDescriptors").toList();
if (!eventDescriptor.isEmpty()) {
QVERIFY2(eventDescriptors.count() == 1, "There should be exactly one eventDescriptor");
QVERIFY2(eventDescriptors.first().toMap() == eventDescriptor, "Event descriptor doesn't match");
} else if (eventDescriptorList.isEmpty()){
QVERIFY2(eventDescriptors.count() == eventDescriptorList.count(), QString("There should be exactly %1 eventDescriptor").arg(eventDescriptorList.count()).toLatin1().data());
foreach (const QVariant &eventDescriptorVariant, eventDescriptorList) {
bool found = false;
foreach (const QVariant &replyEventDescriptorVariant, eventDescriptors) {
if (eventDescriptorVariant.toMap().value("deviceId") == replyEventDescriptorVariant.toMap().value("deviceId") &&
eventDescriptorVariant.toMap().value("eventTypeId") == replyEventDescriptorVariant.toMap().value("eventTypeId")) {
found = true;
QVERIFY2(eventDescriptorVariant == replyEventDescriptorVariant, "Event descriptor doesn't match");
}
}
QVERIFY2(found, "Missing event descriptor");
}
}
QVariantList replyActions = rule.value("actions").toList();
QVERIFY2(actions == replyActions, "Actions don't match");
QVariantList replyExitActions = rule.value("exitActions").toList();
QVERIFY2(exitActions == replyExitActions, "ExitActions don't match");
}
// Remove the rule
params.clear();
params.insert("ruleId", ruleId);
response = injectAndWait("Rules.RemoveRule", params);
verifyRuleError(response);
// check if removed
response = injectAndWait("Rules.GetRules");
QVariantList rules = response.toMap().value("params").toMap().value("rules").toList();
QVERIFY2(rules.count() == 0, "There should be no rules.");
}
void TestRules::executeRuleActions_data()
{
QTest::addColumn<QVariantMap>("params");
QTest::addColumn<RuleEngine::RuleError>("ruleError");
QTest::newRow("executable rule, enabled") << validIntStateBasedRule("Executeable", true, true).toMap() << RuleEngine::RuleErrorNoError;
QTest::newRow("executable rule, disabled") << validIntStateBasedRule("Executeable", true, false).toMap() << RuleEngine::RuleErrorNoError;
QTest::newRow("not executable rule, enabled") << validIntStateBasedRule("Not Executable", false, true).toMap() << RuleEngine::RuleErrorNotExecutable;
QTest::newRow("not executable rule, disabled") << validIntStateBasedRule("Not Executable", false, false).toMap() << RuleEngine::RuleErrorNotExecutable;
}
void TestRules::executeRuleActions()
{
QFETCH(QVariantMap, params);
QFETCH(RuleEngine::RuleError, ruleError);
// ADD rule
QVariant response = injectAndWait("Rules.AddRule", params);
verifyRuleError(response);
RuleId ruleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toString());
QVERIFY(!ruleId.isNull());
cleanupMockHistory();
QTest::qWait(200);
// EEXCUTE action invalid ruleId
QVariantMap executeParams;
executeParams.insert("ruleId", QUuid::createUuid().toString());
response = injectAndWait("Rules.ExecuteActions", executeParams);
verifyRuleError(response, RuleEngine::RuleErrorRuleNotFound);
// EXECUTE actions
qDebug() << "Execute rule actions";
executeParams.clear();
executeParams.insert("ruleId", ruleId.toString());
response = injectAndWait("Rules.ExecuteActions", executeParams);
verifyRuleError(response, ruleError);
// give the ruleeingine time to execute the actions
QTest::qWait(1000);
if (ruleError == RuleEngine::RuleErrorNoError) {
verifyRuleExecuted(mockWithParamsActionTypeId);
} else {
verifyRuleNotExecuted();
}
cleanupMockHistory();
QTest::qWait(200);
// EXECUTE exit actions invalid ruleId
executeParams.clear();
executeParams.insert("ruleId", QUuid::createUuid().toString());
response = injectAndWait("Rules.ExecuteExitActions", executeParams);
verifyRuleError(response, RuleEngine::RuleErrorRuleNotFound);
// EXECUTE exit actions
qDebug() << "Execute rule exit actions";
executeParams.clear();
executeParams.insert("ruleId", ruleId.toString());
response = injectAndWait("Rules.ExecuteExitActions", executeParams);
verifyRuleError(response, ruleError);
// give the ruleeingine time to execute the actions
QTest::qWait(1000);
if (ruleError == RuleEngine::RuleErrorNoError) {
verifyRuleExecuted(mockWithoutParamsActionTypeId);
} else {
verifyRuleNotExecuted();
}
cleanupMockHistory();
// REMOVE rule
QVariantMap removeParams;
removeParams.insert("ruleId", ruleId);
response = injectAndWait("Rules.RemoveRule", removeParams);
verifyRuleError(response);
}
void TestRules::findRule()
{
// ADD rule
QVariantMap params = validIntStateBasedRule("Executeable", true, true).toMap();
QVariant response = injectAndWait("Rules.AddRule", params);
verifyRuleError(response);
RuleId ruleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toString());
QVERIFY(!ruleId.isNull());
params.clear();
params.insert("deviceId", m_mockDeviceId);
response = injectAndWait("Rules.FindRules", params);
QCOMPARE(response.toMap().value("params").toMap().value("ruleIds").toList().count(), 1);
QCOMPARE(response.toMap().value("params").toMap().value("ruleIds").toList().first().toString(), ruleId.toString());
// REMOVE rule
QVariantMap removeParams;
removeParams.insert("ruleId", ruleId);
response = injectAndWait("Rules.RemoveRule", removeParams);
verifyRuleError(response);
}
void TestRules::removeInvalidRule()
{
QVariantMap params;
params.insert("ruleId", RuleId::createRuleId());
QVariant response = injectAndWait("Rules.RemoveRule", params);
verifyRuleError(response, RuleEngine::RuleErrorRuleNotFound);
}
void TestRules::loadStoreConfig()
{
QVariantMap eventDescriptor1;
eventDescriptor1.insert("eventTypeId", mockEvent1EventTypeId);
eventDescriptor1.insert("deviceId", m_mockDeviceId);
eventDescriptor1.insert("paramDescriptors", QVariantList());
QVariantMap eventDescriptor2;
eventDescriptor2.insert("eventTypeId", mockEvent2EventTypeId);
eventDescriptor2.insert("deviceId", m_mockDeviceId);
eventDescriptor2.insert("paramDescriptors", QVariantList());
QVariantList eventParamDescriptors;
QVariantMap eventParam1;
eventParam1.insert("paramTypeId", mockEvent2EventIntParamParamTypeId);
eventParam1.insert("value", 3);
eventParam1.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals));
eventParamDescriptors.append(eventParam1);
eventDescriptor2.insert("paramDescriptors", eventParamDescriptors);
QVariantList eventDescriptorList;
eventDescriptorList.append(eventDescriptor1);
eventDescriptorList.append(eventDescriptor2);
QVariantMap stateEvaluator1;
QVariantList childEvaluators;
QVariantMap stateDescriptor2;
stateDescriptor2.insert("deviceId", m_mockDeviceId);
stateDescriptor2.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals));
stateDescriptor2.insert("stateTypeId", mockIntStateTypeId);
stateDescriptor2.insert("value", 1);
QVariantMap stateEvaluator2;
stateEvaluator2.insert("stateDescriptor", stateDescriptor2);
stateEvaluator2.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd));
QVariantMap stateDescriptor3;
stateDescriptor3.insert("deviceId", m_mockDeviceId);
stateDescriptor3.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals));
stateDescriptor3.insert("stateTypeId", mockBoolStateTypeId);
stateDescriptor3.insert("value", true);
QVariantMap stateEvaluator3;
stateEvaluator3.insert("stateDescriptor", stateDescriptor3);
stateEvaluator3.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd));
QVariantMap stateDescriptor4;
stateDescriptor4.insert("interface", "battery");
stateDescriptor4.insert("interfaceState", "batteryCritical");
stateDescriptor4.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals));
stateDescriptor4.insert("value", true);
QVariantMap stateEvaluator4;
stateEvaluator4.insert("stateDescriptor", stateDescriptor4);
stateEvaluator4.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd));
childEvaluators.append(stateEvaluator2);
childEvaluators.append(stateEvaluator3);
childEvaluators.append(stateEvaluator4);
stateEvaluator1.insert("childEvaluators", childEvaluators);
stateEvaluator1.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd));
QVariantMap action1;
action1.insert("actionTypeId", mockWithoutParamsActionTypeId);
action1.insert("deviceId", m_mockDeviceId);
action1.insert("ruleActionParams", QVariantList());
QVariantMap action2;
action2.insert("actionTypeId", mockWithParamsActionTypeId);
action2.insert("deviceId", m_mockDeviceId);
QVariantList action2Params;
QVariantMap action2Param1;
action2Param1.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
action2Param1.insert("value", 5);
action2Params.append(action2Param1);
QVariantMap action2Param2;
action2Param2.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId);
action2Param2.insert("value", true);
action2Params.append(action2Param2);
action2.insert("ruleActionParams", action2Params);
// RuleAction event based
QVariantMap validActionEventBased;
validActionEventBased.insert("actionTypeId", mockWithParamsActionTypeId);
validActionEventBased.insert("deviceId", m_mockDeviceId);
QVariantMap validActionEventBasedParam1;
validActionEventBasedParam1.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
validActionEventBasedParam1.insert("eventTypeId", mockEvent2EventTypeId);
validActionEventBasedParam1.insert("eventParamTypeId", mockEvent2EventIntParamParamTypeId);
QVariantMap validActionEventBasedParam2;
validActionEventBasedParam2.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId);
validActionEventBasedParam2.insert("value", false);
validActionEventBased.insert("ruleActionParams", QVariantList() << validActionEventBasedParam1 << validActionEventBasedParam2);
QVariantList validEventDescriptors3;
QVariantMap validEventDescriptor3;
validEventDescriptor3.insert("eventTypeId", mockEvent2EventTypeId);
validEventDescriptor3.insert("deviceId", m_mockDeviceId);
validEventDescriptor3.insert("paramDescriptors", QVariantList());
validEventDescriptors3.append(validEventDescriptor3);
// Interface based event descriptor
QVariantMap eventDescriptorInterfaces;
eventDescriptorInterfaces.insert("interface", "battery");
eventDescriptorInterfaces.insert("interfaceEvent", "batteryCritical");
QVariantMap eventDescriptorInterfacesParam;
eventDescriptorInterfacesParam.insert("paramName", "batteryCritical");
eventDescriptorInterfacesParam.insert("value", true);
eventDescriptorInterfacesParam.insert("operator", "ValueOperatorEquals");
QVariantList eventDescriptorInterfacesParams;
eventDescriptorInterfacesParams.append(eventDescriptorInterfacesParam);
eventDescriptorInterfaces.insert("paramDescriptors", eventDescriptorInterfacesParams);
QVariantList eventDescriptorsInterfaces;
eventDescriptorsInterfaces.append(eventDescriptorInterfaces);
// Interface based state evaluator
QVariantMap stateDescriptorInterfaces;
stateDescriptorInterfaces.insert("interface", "battery");
stateDescriptorInterfaces.insert("interfaceState", "batteryCritical");
stateDescriptorInterfaces.insert("operator", "ValueOperatorEquals");
stateDescriptorInterfaces.insert("value", true);
QVariantMap stateEvaluatorInterfaces;
stateEvaluatorInterfaces.insert("stateDescriptor", stateDescriptorInterfaces);
stateEvaluatorInterfaces.insert("operator", "StateOperatorAnd");
// Interface based actions
QVariantMap ruleActionParamInterfaces;
ruleActionParamInterfaces.insert("paramName", "power");
ruleActionParamInterfaces.insert("value", true);
QVariantList ruleActionParamsInterfaces;
ruleActionParamsInterfaces.append(ruleActionParamInterfaces);
QVariantMap actionInterfaces;
actionInterfaces.insert("interface", "light");
actionInterfaces.insert("interfaceAction", "power");
actionInterfaces.insert("ruleActionParams", ruleActionParamsInterfaces);
QVariantList actionsInterfaces;
actionsInterfaces.append(actionInterfaces);
// rule 1
qCDebug(dcTests()) << "Adding rule 1";
QVariantMap params;
QVariantList actions;
actions.append(action1);
actions.append(action2);
params.insert("actions", actions);
params.insert("eventDescriptors", eventDescriptorList);
params.insert("stateEvaluator", stateEvaluator1);
params.insert("name", "TestRule");
QVariant response = injectAndWait("Rules.AddRule", params);
RuleId newRuleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toString());
verifyRuleError(response);
// rule 2
qCDebug(dcTests()) << "Adding rule 2";
QVariantMap params2;
QVariantList actions2;
actions2.append(action1);
QVariantList exitActions2;
exitActions2.append(action2);
params2.insert("actions", actions2);
params2.insert("exitActions", exitActions2);
params2.insert("stateEvaluator", stateEvaluator1);
params2.insert("name", "TestRule2");
QVariant response2 = injectAndWait("Rules.AddRule", params2);
RuleId newRuleId2 = RuleId(response2.toMap().value("params").toMap().value("ruleId").toString());
verifyRuleError(response2);
// rule 3
qCDebug(dcTests()) << "Adding rule 3";
QVariantMap params3;
QVariantList actions3;
actions3.append(validActionEventBased);
params3.insert("actions", actions3);
params3.insert("eventDescriptors", validEventDescriptors3);
params3.insert("name", "TestRule3");
QVariant response3 = injectAndWait("Rules.AddRule", params3);
RuleId newRuleId3 = RuleId(response3.toMap().value("params").toMap().value("ruleId").toString());
verifyRuleError(response3);
// rule 4, interface based
qCDebug(dcTests()) << "Adding rule 4";
QVariantMap params4;
params4.insert("name", "TestRule4 - Interface based");
params4.insert("eventDescriptors", eventDescriptorsInterfaces);
params4.insert("stateEvaluator", stateEvaluatorInterfaces);
params4.insert("actions", actionsInterfaces);
QVariant response4 = injectAndWait("Rules.AddRule", params4);
RuleId newRuleId4 = RuleId(response4.toMap().value("params").toMap().value("ruleId").toString());
verifyRuleError(response4);
qCDebug(dcTests()) << "Getting rules";
response = injectAndWait("Rules.GetRules");
QVariantList rules = response.toMap().value("params").toMap().value("ruleDescriptions").toList();
qDebug() << "GetRules before server shutdown:" << response;
qCDebug(dcTests()) << "Restarting server";
restartServer();
response = injectAndWait("Rules.GetRules");
rules = response.toMap().value("params").toMap().value("ruleDescriptions").toList();
QVERIFY2(rules.count() == 4, "There should be exactly four rule.");
QStringList idList;
foreach (const QVariant &ruleDescription, rules) {
idList.append(ruleDescription.toMap().value("id").toString());
}
QVERIFY2(idList.contains(newRuleId.toString()), "Rule 1 should be in ruleIds list.");
QVERIFY2(idList.contains(newRuleId2.toString()), "Rule 2 should be in ruleIds list.");
QVERIFY2(idList.contains(newRuleId3.toString()), "Rule 3 should be in ruleIds list.");
QVERIFY2(idList.contains(newRuleId4.toString()), "Rule 4 should be in ruleIds list.");
// Rule 1
params.clear();
params.insert("ruleId", newRuleId);
response.clear();
response = injectAndWait("Rules.GetRuleDetails", params);
QVariantMap rule1 = response.toMap().value("params").toMap().value("rule").toMap();
QVariantList eventDescriptors = rule1.value("eventDescriptors").toList();
QVERIFY2(eventDescriptors.count() == 2, "There should be exactly 2 eventDescriptors");
foreach (const QVariant &expectedEventDescriptorVariant, eventDescriptorList) {
bool found = false;
foreach (const QVariant &replyEventDescriptorVariant, eventDescriptors) {
if (expectedEventDescriptorVariant.toMap().value("eventTypeId") == replyEventDescriptorVariant.toMap().value("eventTypeId") &&
expectedEventDescriptorVariant.toMap().value("deviceId") == replyEventDescriptorVariant.toMap().value("deviceId")) {
found = true;
qDebug() << endl << replyEventDescriptorVariant << endl << expectedEventDescriptorVariant;
QVERIFY2(replyEventDescriptorVariant == expectedEventDescriptorVariant, "EventDescriptor doesn't match");
}
}
QVERIFY2(found, "missing eventdescriptor");
}
qDebug() << "Rule after loading from config:" << rule1;
QVERIFY2(rule1.value("name").toString() == "TestRule", "Loaded wrong name for rule");
QVariantMap replyStateEvaluator= rule1.value("stateEvaluator").toMap();
QVariantList replyChildEvaluators = replyStateEvaluator.value("childEvaluators").toList();
QCOMPARE(replyChildEvaluators.count(), 3);
QVERIFY2(replyStateEvaluator.value("operator") == "StateOperatorAnd", "There should be the AND operator.");
foreach (const QVariant &childEvaluator, replyChildEvaluators) {
QVERIFY2(childEvaluator.toMap().contains("stateDescriptor"), "StateDescriptor missing in StateEvaluator");
QVariantMap stateDescriptor = childEvaluator.toMap().value("stateDescriptor").toMap();
if (stateDescriptor.contains("deviceId") && stateDescriptor.contains("stateTypeId")) {
QVERIFY2(stateDescriptor.value("deviceId") == m_mockDeviceId, "DeviceId of stateDescriptor does not match");
QVERIFY2(stateDescriptor.value("stateTypeId") == mockIntStateTypeId || stateDescriptor.value("stateTypeId") == mockBoolStateTypeId, "StateTypeId of stateDescriptor doesn't match");
} else if (stateDescriptor.contains("interface") && stateDescriptor.contains("interfaceState")) {
QVERIFY2(stateDescriptor.value("interface") == "battery", "Interface of stateDescriptor does not match");
QVERIFY2(stateDescriptor.value("interfaceState") == "batteryCritical", "InterfaceState of stateDescriptor doesn't match");
} else {
QVERIFY2(false, "StateDescriptor must have either deviceId/stateTypeId or interface/interfaceState.");
}
}
QVariantList replyActions = rule1.value("actions").toList();
foreach (const QVariant &actionVariant, actions) {
bool found = false;
foreach (const QVariant &replyActionVariant, replyActions) {
if (actionVariant.toMap().value("actionTypeId") == replyActionVariant.toMap().value("actionTypeId") &&
actionVariant.toMap().value("deviceId") == replyActionVariant.toMap().value("deviceId")) {
found = true;
// Check rule action params
QVariantList actionParams = actionVariant.toMap().value("ruleActionParams").toList();
QVariantList replyActionParams = replyActionVariant.toMap().value("ruleActionParams").toList();
QVERIFY2(actionParams.count() == replyActionParams.count(), "Not the same list size of action params");
foreach (const QVariant &ruleParam, actionParams) {
QVERIFY(replyActionParams.contains(ruleParam));
}
}
}
QVERIFY2(found, "Action not found after loading from config.");
}
// Rule 2
params.clear();
params.insert("ruleId", newRuleId2);
response.clear();
response = injectAndWait("Rules.GetRuleDetails", params);
QVariantMap rule2 = response.toMap().value("params").toMap().value("rule").toMap();
QVERIFY2(rule2.value("name").toString() == "TestRule2", "Loaded wrong name for rule");
QVariantMap replyStateEvaluator2= rule2.value("stateEvaluator").toMap();
QVariantList replyChildEvaluators2 = replyStateEvaluator.value("childEvaluators").toList();
QVERIFY2(replyStateEvaluator2.value("operator") == "StateOperatorAnd", "There should be the AND operator.");
QCOMPARE(replyChildEvaluators2.count(), 3);
foreach (const QVariant &childEvaluator, replyChildEvaluators2) {
QVERIFY2(childEvaluator.toMap().contains("stateDescriptor"), "StateDescriptor missing in StateEvaluator");
QVariantMap stateDescriptor = childEvaluator.toMap().value("stateDescriptor").toMap();
if (stateDescriptor.contains("deviceId") && stateDescriptor.contains("stateTypeId")) {
QVERIFY2(stateDescriptor.value("deviceId") == m_mockDeviceId, "DeviceId of stateDescriptor does not match");
QVERIFY2(stateDescriptor.value("stateTypeId") == mockIntStateTypeId || stateDescriptor.value("stateTypeId") == mockBoolStateTypeId, "StateTypeId of stateDescriptor doesn't match");
} else if (stateDescriptor.contains("interface") && stateDescriptor.contains("interfaceState")) {
QVERIFY2(stateDescriptor.value("interface") == "battery", "Interface of stateDescriptor does not match");
QVERIFY2(stateDescriptor.value("interfaceState") == "batteryCritical", "InterfaceState of stateDescriptor doesn't match");
} else {
QVERIFY2(false, "StateDescriptor must have either deviceId/stateTypeId or interface/interfaceState.");
}
}
QVariantList replyActions2 = rule2.value("actions").toList();
QVERIFY2(replyActions2.count() == 1, "Rule 2 should have exactly 1 action");
foreach (const QVariant &actionVariant, actions2) {
bool found = false;
foreach (const QVariant &replyActionVariant, replyActions2) {
if (actionVariant.toMap().value("actionTypeId") == replyActionVariant.toMap().value("actionTypeId") &&
actionVariant.toMap().value("deviceId") == replyActionVariant.toMap().value("deviceId")) {
found = true;
// Check rule action params
QVariantList actionParams = actionVariant.toMap().value("ruleActionParams").toList();
QVariantList replyActionParams = replyActionVariant.toMap().value("ruleActionParams").toList();
QVERIFY2(actionParams.count() == replyActionParams.count(), "Not the same list size of action params");
foreach (const QVariant &ruleParam, actionParams) {
QVERIFY(replyActionParams.contains(ruleParam));
}
}
}
QVERIFY2(found, "Action not found after loading from config.");
}
QVariantList replyExitActions2 = rule2.value("exitActions").toList();
QVERIFY2(replyExitActions2.count() == 1, "Rule 2 should have exactly 1 exitAction");
foreach (const QVariant &exitActionVariant, replyExitActions2) {
bool found = false;
foreach (const QVariant &replyActionVariant, replyExitActions2) {
if (exitActionVariant.toMap().value("actionTypeId") == replyActionVariant.toMap().value("actionTypeId") &&
exitActionVariant.toMap().value("deviceId") == replyActionVariant.toMap().value("deviceId")) {
found = true;
// Check rule action params
QVariantList actionParams = exitActionVariant.toMap().value("ruleActionParams").toList();
QVariantList replyActionParams = replyActionVariant.toMap().value("ruleActionParams").toList();
QVERIFY2(actionParams.count() == replyActionParams.count(), "Not the same list size of action params");
foreach (const QVariant &ruleParam, actionParams) {
QVERIFY(replyActionParams.contains(ruleParam));
}
}
}
QVERIFY2(found, "Exit Action not found after loading from config.");
}
// Rule 3
params.clear();
params.insert("ruleId", newRuleId3);
response.clear();
response = injectAndWait("Rules.GetRuleDetails", params);
QVariantMap rule3 = response.toMap().value("params").toMap().value("rule").toMap();
qDebug() << rule3;
QVariantList eventDescriptors3 = rule3.value("eventDescriptors").toList();
QVERIFY2(eventDescriptors3.count() == 1, "There should be exactly 1 eventDescriptor");
QVariantMap eventDescriptor = eventDescriptors3.first().toMap();
QVERIFY2(eventDescriptor.value("eventTypeId").toString() == mockEvent2EventTypeId.toString(), "Loaded the wrong eventTypeId in rule 3");
QVERIFY2(eventDescriptor.value("deviceId").toString() == m_mockDeviceId.toString(), "Loaded the wrong deviceId from eventDescriptor in rule 3");
QVariantList replyExitActions3 = rule3.value("exitActions").toList();
QVERIFY2(replyExitActions3.isEmpty(), "Rule 3 should not have any exitAction");
QVariantList replyActions3 = rule3.value("actions").toList();
QVERIFY2(replyActions3.count() == 1, "Rule 3 should have exactly 1 action");
foreach (const QVariant &actionVariant, actions3) {
bool found = false;
foreach (const QVariant &replyActionVariant, replyActions3) {
if (actionVariant.toMap().value("actionTypeId") == replyActionVariant.toMap().value("actionTypeId") &&
actionVariant.toMap().value("deviceId") == replyActionVariant.toMap().value("deviceId")) {
found = true;
// Check rule action params
QVariantList actionParams = actionVariant.toMap().value("ruleActionParams").toList();
QVariantList replyActionParams = replyActionVariant.toMap().value("ruleActionParams").toList();
QVERIFY2(actionParams.count() == replyActionParams.count(), "Not the same list size of action params");
foreach (const QVariant &ruleParam, actionParams) {
QVERIFY(replyActionParams.contains(ruleParam));
}
}
}
QVERIFY2(found, "Action not found after loading from config.");
}
// Rule 4
params.clear();
params.insert("ruleId", newRuleId4);
response.clear();
response = injectAndWait("Rules.GetRuleDetails", params);
QVariantMap rule4 = response.toMap().value("params").toMap().value("rule").toMap();
qDebug() << rule4;
QVariantList eventDescriptors4 = rule4.value("eventDescriptors").toList();
QVERIFY2(eventDescriptors4.count() == 1, "There should be exactly 1 eventDescriptor");
eventDescriptor = eventDescriptors4.first().toMap();
QVERIFY2(eventDescriptor.value("interface").toString() == "battery", "Loaded the wrong interface name in rule 4");
QVERIFY2(eventDescriptor.value("interfaceEvent").toString() == "batteryCritical", "Loaded the wrong interfaceEvent from eventDescriptor in rule 4");
QCOMPARE(eventDescriptor.value("paramDescriptors").toList().count(), 1);
QVERIFY2(eventDescriptor.value("paramDescriptors").toList().first().toMap().value("paramName").toString() == "batteryCritical", "Loaded wrong ParamDescriptor in rule 4");
QVERIFY2(eventDescriptor.value("paramDescriptors").toList().first().toMap().value("value").toBool() == true, "Loaded wrong ParamDescriptor in rule 3");
QVariantList replyActions4 = rule4.value("actions").toList();
QVERIFY2(replyActions4.count() == 1, "Rule 4 should have exactly 1 action");
foreach (const QVariant &actionVariant, actionsInterfaces) {
bool found = false;
foreach (const QVariant &replyActionVariant, replyActions4) {
if (actionVariant.toMap().value("interface") == replyActionVariant.toMap().value("interface") &&
actionVariant.toMap().value("interfaceAction") == replyActionVariant.toMap().value("interfaceAction")) {
found = true;
// Check rule action params
QVariantList actionParams = actionVariant.toMap().value("ruleActionParams").toList();
QVariantList replyActionParams = replyActionVariant.toMap().value("ruleActionParams").toList();
QVERIFY2(actionParams.count() == replyActionParams.count(), "Not the same list size of action params");
foreach (const QVariant &ruleParam, actionParams) {
QVERIFY(replyActionParams.contains(ruleParam));
}
}
}
QVERIFY2(found, "Action not found after loading from config.");
}
QVariantList replyExitActions4 = rule4.value("exitActions").toList();
QVERIFY2(replyExitActions4.isEmpty(), "Rule 4 should not have any exitAction");
// Remove Rule1
params.clear();
params.insert("ruleId", newRuleId);
response = injectAndWait("Rules.RemoveRule", params);
verifyRuleError(response);
// Remove Rule2
params2.clear();
params2.insert("ruleId", newRuleId2);
response = injectAndWait("Rules.RemoveRule", params2);
verifyRuleError(response);
// Remove Rule2
params3.clear();
params3.insert("ruleId", newRuleId3);
response = injectAndWait("Rules.RemoveRule", params3);
verifyRuleError(response);
restartServer();
response = injectAndWait("Rules.GetRules");
rules = response.toMap().value("params").toMap().value("rules").toList();
QVERIFY2(rules.count() == 0, "There should be no rules.");
}
void TestRules::evaluateEvent()
{
// Add a rule
QVariantMap addRuleParams;
addRuleParams.insert("name", "TestRule");
QVariantList events;
QVariantMap event1;
event1.insert("eventTypeId", mockEvent1EventTypeId);
event1.insert("deviceId", m_mockDeviceId);
events.append(event1);
addRuleParams.insert("eventDescriptors", events);
QVariantList actions;
QVariantMap action;
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
action.insert("deviceId", m_mockDeviceId);
actions.append(action);
addRuleParams.insert("actions", actions);
QVariant response = injectAndWait("Rules.AddRule", addRuleParams);
verifyRuleError(response);
// Trigger an event
QNetworkAccessManager nam;
QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*)));
// trigger event in mock device
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();
verifyRuleExecuted(mockWithoutParamsActionTypeId);
}
void TestRules::evaluateEventParams()
{
// Init bool state to true
QNetworkAccessManager nam;
QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*)));
QNetworkRequest request(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockBoolStateTypeId.toString()).arg("true")));
QNetworkReply *reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
// Add a rule
QVariantMap addRuleParams;
addRuleParams.insert("name", "TestRule");
QVariantList params;
QVariantMap boolParam;
boolParam.insert("paramTypeId", mockBoolStateTypeId);
boolParam.insert("operator", "ValueOperatorEquals");
boolParam.insert("value", true);
params.append(boolParam);
QVariantMap event1;
event1.insert("eventTypeId", mockBoolStateTypeId);
event1.insert("deviceId", m_mockDeviceId);
event1.insert("paramDescriptors", params);
QVariantList events;
events.append(event1);
addRuleParams.insert("eventDescriptors", events);
QVariantList actions;
QVariantMap action;
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
action.insert("deviceId", m_mockDeviceId);
actions.append(action);
addRuleParams.insert("actions", actions);
QVariant response = injectAndWait("Rules.AddRule", addRuleParams);
verifyRuleError(response);
// Trigger a non matching param
spy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockBoolStateTypeId.toString()).arg("false")));
reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
verifyRuleNotExecuted();
// Trigger a matching param
spy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockBoolStateTypeId.toString()).arg("true")));
reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
verifyRuleExecuted(mockWithoutParamsActionTypeId);
// Reset back to false to not mess with other tests
spy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockBoolStateTypeId.toString()).arg("false")));
reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
}
void TestRules::testStateChange() {
// Add a rule
QVariantMap addRuleParams;
QVariantMap stateEvaluator;
QVariantMap stateDescriptor;
stateDescriptor.insert("deviceId", m_mockDeviceId);
stateDescriptor.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorGreaterOrEqual));
stateDescriptor.insert("stateTypeId", mockIntStateTypeId);
stateDescriptor.insert("value", 42);
stateEvaluator.insert("stateDescriptor", stateDescriptor);
addRuleParams.insert("stateEvaluator", stateEvaluator);
addRuleParams.insert("name", "TestRule");
QVariantList actions;
QVariantMap action;
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
action.insert("deviceId", m_mockDeviceId);
actions.append(action);
addRuleParams.insert("actions", actions);
QVariant response = injectAndWait("Rules.AddRule", addRuleParams);
verifyRuleError(response);
// Change the state
QNetworkAccessManager nam;
QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*)));
// state state to 42
qDebug() << "setting mock int state to 42";
QNetworkRequest request(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockIntStateTypeId.toString()).arg(42)));
QNetworkReply *reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
// set state to 45
qDebug() << "setting mock int state to 45";
spy.clear();
request.setUrl(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockIntStateTypeId.toString()).arg(45)));
reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
verifyRuleNotExecuted();
cleanupMockHistory();
// set state to 30
qDebug() << "setting mock int state to 30";
spy.clear();
request.setUrl(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockIntStateTypeId.toString()).arg(30)));
reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
verifyRuleNotExecuted();
cleanupMockHistory();
// set state to 100
qDebug() << "setting mock int state to 100";
spy.clear();
request.setUrl(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockIntStateTypeId.toString()).arg(100)));
reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
verifyRuleExecuted(mockWithoutParamsActionTypeId);
reply->deleteLater();
}
void TestRules::testStateEvaluator_data()
{
QTest::addColumn<DeviceId>("deviceId");
QTest::addColumn<StateTypeId>("stateTypeId");
QTest::addColumn<QVariant>("value");
QTest::addColumn<Types::ValueOperator>("operatorType");
QTest::addColumn<bool>("shouldMatch");
QTest::newRow("invalid stateId") << m_mockDeviceId << StateTypeId::createStateTypeId() << QVariant(10) << Types::ValueOperatorEquals << false;
QTest::newRow("invalid deviceId") << DeviceId::createDeviceId() << mockIntStateTypeId << QVariant(10) << Types::ValueOperatorEquals << false;
QTest::newRow("equals, not matching") << m_mockDeviceId << mockIntStateTypeId << QVariant(7777) << Types::ValueOperatorEquals << false;
QTest::newRow("equals, matching") << m_mockDeviceId << mockIntStateTypeId << QVariant(10) << Types::ValueOperatorEquals << true;
QTest::newRow("not equal, not matching") << m_mockDeviceId << mockIntStateTypeId << QVariant(10) << Types::ValueOperatorNotEquals << false;
QTest::newRow("not equal, matching") << m_mockDeviceId << mockIntStateTypeId << QVariant(7777) << Types::ValueOperatorNotEquals << true;
QTest::newRow("Greater, not matching") << m_mockDeviceId << mockIntStateTypeId << QVariant(7777) << Types::ValueOperatorGreater << false;
QTest::newRow("Greater, matching") << m_mockDeviceId << mockIntStateTypeId << QVariant(2) << Types::ValueOperatorGreater << true;
QTest::newRow("GreaterOrEqual, not matching") << m_mockDeviceId << mockIntStateTypeId << QVariant(7777) << Types::ValueOperatorGreaterOrEqual << false;
QTest::newRow("GreaterOrEqual, matching (greater)") << m_mockDeviceId << mockIntStateTypeId << QVariant(2) << Types::ValueOperatorGreaterOrEqual << true;
QTest::newRow("GreaterOrEqual, matching (equals)") << m_mockDeviceId << mockIntStateTypeId << QVariant(10) << Types::ValueOperatorGreaterOrEqual << true;
QTest::newRow("Less, not matching") << m_mockDeviceId << mockIntStateTypeId << QVariant(2) << Types::ValueOperatorLess << false;
QTest::newRow("Less, matching") << m_mockDeviceId << mockIntStateTypeId << QVariant(7777) << Types::ValueOperatorLess << true;
QTest::newRow("LessOrEqual, not matching") << m_mockDeviceId << mockIntStateTypeId << QVariant(2) << Types::ValueOperatorLessOrEqual << false;
QTest::newRow("LessOrEqual, matching (less)") << m_mockDeviceId << mockIntStateTypeId << QVariant(777) << Types::ValueOperatorLessOrEqual << true;
QTest::newRow("LessOrEqual, matching (equals)") << m_mockDeviceId << mockIntStateTypeId << QVariant(10) << Types::ValueOperatorLessOrEqual << true;
QTest::newRow("Less, not matching, double") << m_mockDeviceId << mockDoubleStateTypeId << QVariant(2.1) << Types::ValueOperatorLess << false;
QTest::newRow("Less, not matching, double as string") << m_mockDeviceId << mockDoubleStateTypeId << QVariant("2.1") << Types::ValueOperatorLess << false;
QTest::newRow("Less, matching, double") << m_mockDeviceId << mockDoubleStateTypeId << QVariant(4.2) << Types::ValueOperatorLess << true;
QTest::newRow("Less, matching, double as string") << m_mockDeviceId << mockDoubleStateTypeId << QVariant("4.2") << Types::ValueOperatorLess << true;
}
void TestRules::testStateEvaluator()
{
QFETCH(DeviceId, deviceId);
QFETCH(StateTypeId, stateTypeId);
QFETCH(QVariant, value);
QFETCH(Types::ValueOperator, operatorType);
QFETCH(bool, shouldMatch);
StateDescriptor descriptor(stateTypeId, deviceId, value, operatorType);
StateEvaluator evaluator(descriptor);
QVERIFY2(evaluator.evaluate() == shouldMatch, shouldMatch ? "State should match" : "State shouldn't match");
}
void TestRules::testStateEvaluator2_data()
{
QTest::addColumn<int>("intValue");
QTest::addColumn<Types::ValueOperator>("intOperator");
QTest::addColumn<bool>("boolValue");
QTest::addColumn<Types::ValueOperator>("boolOperator");
QTest::addColumn<Types::StateOperator>("stateOperator");
QTest::addColumn<bool>("shouldMatch");
QTest::newRow("Y: 10 && false") << 10 << Types::ValueOperatorEquals << false << Types::ValueOperatorEquals << Types::StateOperatorAnd << true;
QTest::newRow("N: 10 && true") << 10 << Types::ValueOperatorEquals << true << Types::ValueOperatorEquals << Types::StateOperatorAnd << false;
QTest::newRow("N: 11 && false") << 11 << Types::ValueOperatorEquals << false << Types::ValueOperatorEquals << Types::StateOperatorAnd << false;
QTest::newRow("Y: 11 || false") << 11 << Types::ValueOperatorEquals << false << Types::ValueOperatorEquals << Types::StateOperatorOr << true;
QTest::newRow("Y: 10 || false") << 10 << Types::ValueOperatorEquals << false << Types::ValueOperatorEquals << Types::StateOperatorOr << true;
QTest::newRow("Y: 10 || true") << 10 << Types::ValueOperatorEquals << true << Types::ValueOperatorEquals << Types::StateOperatorOr << true;
QTest::newRow("N: 11 || true") << 11 << Types::ValueOperatorEquals << true << Types::ValueOperatorEquals << Types::StateOperatorOr << false;
}
void TestRules::testStateEvaluator2()
{
QFETCH(int, intValue);
QFETCH(Types::ValueOperator, intOperator);
QFETCH(bool, boolValue);
QFETCH(Types::ValueOperator, boolOperator);
QFETCH(Types::StateOperator, stateOperator);
QFETCH(bool, shouldMatch);
StateDescriptor descriptor1(mockIntStateTypeId, m_mockDeviceId, intValue, intOperator);
StateEvaluator evaluator1(descriptor1);
StateDescriptor descriptor2(mockBoolStateTypeId, m_mockDeviceId, boolValue, boolOperator);
StateEvaluator evaluator2(descriptor2);
QList<StateEvaluator> childEvaluators;
childEvaluators.append(evaluator1);
childEvaluators.append(evaluator2);
StateEvaluator mainEvaluator(childEvaluators);
mainEvaluator.setOperatorType(stateOperator);
QVERIFY2(mainEvaluator.evaluate() == shouldMatch, shouldMatch ? "State should match" : "State shouldn't match");
}
void TestRules::testStateEvaluator3_data()
{
testStateEvaluator2_data();
}
void TestRules::testStateEvaluator3()
{
QFETCH(int, intValue);
QFETCH(Types::ValueOperator, intOperator);
QFETCH(bool, boolValue);
QFETCH(Types::ValueOperator, boolOperator);
QFETCH(Types::StateOperator, stateOperator);
QFETCH(bool, shouldMatch);
StateDescriptor descriptor1(mockIntStateTypeId, m_mockDeviceId, intValue, intOperator);
StateEvaluator childEvaluator(descriptor1);
QList<StateEvaluator> childEvaluators;
childEvaluators.append(childEvaluator);
StateDescriptor descriptor2(mockBoolStateTypeId, m_mockDeviceId, boolValue, boolOperator);
StateEvaluator mainEvaluator(descriptor2);
mainEvaluator.setChildEvaluators(childEvaluators);
mainEvaluator.setOperatorType(stateOperator);
QVERIFY2(mainEvaluator.evaluate() == shouldMatch, shouldMatch ? "State should match" : "State shouldn't match");
}
void TestRules::testChildEvaluator_data()
{
cleanup();
DeviceId testDeviceId = addDisplayPinDevice();
QVERIFY2(!testDeviceId.isNull(), "Could not add push button device for child evaluators");
enableNotifications();
// Create child evaluators
// 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 stateDescriptorPercentage;
stateDescriptorPercentage.insert("deviceId", testDeviceId);
stateDescriptorPercentage.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorGreaterOrEqual));
stateDescriptorPercentage.insert("stateTypeId", mockDisplayPinPercentageStateTypeId);
stateDescriptorPercentage.insert("value", 50);
QVariantMap stateDescriptorDouble;
stateDescriptorDouble.insert("deviceId", testDeviceId);
stateDescriptorDouble.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals));
stateDescriptorDouble.insert("stateTypeId", mockDisplayPinDoubleActionDoubleParamTypeId);
stateDescriptorDouble.insert("value", 20.5);
QVariantMap stateDescriptorAllowedValues;
stateDescriptorAllowedValues.insert("deviceId", testDeviceId);
stateDescriptorAllowedValues.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals));
stateDescriptorAllowedValues.insert("stateTypeId", mockDisplayPinAllowedValuesStateTypeId);
stateDescriptorAllowedValues.insert("value", "String value 2");
QVariantMap stateDescriptorColor;
stateDescriptorColor.insert("deviceId", testDeviceId);
stateDescriptorColor.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals));
stateDescriptorColor.insert("stateTypeId", mockDisplayPinColorStateTypeId);
stateDescriptorColor.insert("value", "#00FF00");
QVariantMap firstStateEvaluator;
firstStateEvaluator.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorOr));
firstStateEvaluator.insert("childEvaluators", QVariantList() << createStateEvaluatorFromSingleDescriptor(stateDescriptorPercentage) << createStateEvaluatorFromSingleDescriptor(stateDescriptorDouble));
QVariantMap secondStateEvaluator;
secondStateEvaluator.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd));
secondStateEvaluator.insert("childEvaluators", QVariantList() << createStateEvaluatorFromSingleDescriptor(stateDescriptorAllowedValues) << createStateEvaluatorFromSingleDescriptor(stateDescriptorColor));
QVariantMap stateEvaluator;
stateEvaluator.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd));
stateEvaluator.insert("childEvaluators", QVariantList() << firstStateEvaluator << secondStateEvaluator);
// The rule
QVariantMap ruleMap;
ruleMap.insert("name", "Child evaluator rule");
ruleMap.insert("stateEvaluator", stateEvaluator);
ruleMap.insert("actions", QVariantList() << action);
ruleMap.insert("exitActions", QVariantList() << exitAction);
printJson(ruleMap);
// (percentage >= 50 || double == 20.5) && (color == #00FF00 && allowedValue == "String value 2") ? action : exit action
QTest::addColumn<DeviceId>("deviceId");
QTest::addColumn<QVariantMap>("ruleMap");
QTest::addColumn<int>("percentageValue");
QTest::addColumn<double>("doubleValue");
QTest::addColumn<QString>("allowedValue");
QTest::addColumn<QString>("colorValue");
QTest::addColumn<bool>("trigger");
QTest::addColumn<bool>("active");
QTest::newRow("Unchanged | 2 | 2.5 | String value 1 | #FF0000") << testDeviceId << ruleMap << 2 << 2.5 << "String value 1" << "#FF0000" << false << false;
// QTest::newRow("Unchanged | 60 | 2.5 | String value 2 | #FF0000") << testDeviceId << ruleMap << 60 << 2.5 << "String value 2" << "#FF0000" << false << false;
// QTest::newRow("Unchanged | 60 | 20.5 | String value 2 | #FF0000") << testDeviceId << ruleMap << 60 << 20.5 << "String value 2" << "#FF0000" << false << false;
// QTest::newRow("Active | 60 | 20.5 | String value 2 | #00FF00") << testDeviceId << ruleMap << 60 << 20.5 << "String value 2" << "#00FF00" << true << true;
// QTest::newRow("Active | 60 | 20.5 | String value 2 | #00FF00") << testDeviceId << ruleMap << 60 << 20.5 << "String value 2" << "#00FF00" << true << true;
}
void TestRules::testChildEvaluator()
{
QFETCH(DeviceId, deviceId);
QFETCH(QVariantMap, ruleMap);
QFETCH(int, percentageValue);
QFETCH(double, doubleValue);
QFETCH(QString, allowedValue);
QFETCH(QString, colorValue);
QFETCH(bool, trigger);
QFETCH(bool, active);
// Init the states
setWritableStateValue(deviceId, StateTypeId(mockDisplayPinPercentageStateTypeId.toString()), QVariant(0));
setWritableStateValue(deviceId, StateTypeId(mockDisplayPinDoubleActionDoubleParamTypeId.toString()), QVariant(0));
setWritableStateValue(deviceId, StateTypeId(mockDisplayPinAllowedValuesStateTypeId.toString()), QVariant("String value 1"));
setWritableStateValue(deviceId, StateTypeId(mockDisplayPinColorStateTypeId.toString()), QVariant("#000000"));
qCDebug(dcTests()) << "Adding rule";
// Add rule
QVariant response = injectAndWait("Rules.AddRule", ruleMap);
verifyRuleError(response);
RuleId ruleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toString());
// Set the states
qCDebug(dcTests()) << "Setting state 1";
setWritableStateValue(deviceId, StateTypeId(mockDisplayPinPercentageStateTypeId.toString()), QVariant::fromValue(percentageValue));
qCDebug(dcTests()) << "Setting state 2";
setWritableStateValue(deviceId, StateTypeId(mockDisplayPinDoubleActionDoubleParamTypeId.toString()), QVariant::fromValue(doubleValue));
qCDebug(dcTests()) << "Setting state 3";
setWritableStateValue(deviceId, StateTypeId(mockDisplayPinAllowedValuesStateTypeId.toString()), QVariant::fromValue(allowedValue));
qCDebug(dcTests()) << "Setting state 4";
setWritableStateValue(deviceId, StateTypeId(mockDisplayPinColorStateTypeId.toString()), QVariant::fromValue(colorValue));
// Verfiy if the rule executed successfully
// Actions
if (trigger && active) {
qCDebug(dcTests()) << "Checking if actions were executed";
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
}
// Exit actions
if (trigger && !active) {
qCDebug(dcTests()) << "Checking if exit actions were executed";
verifyRuleExecuted(mockWithParamsActionTypeId);
cleanupMockHistory();
}
// Nothing triggert
if (!trigger) {
qCDebug(dcTests()) << "Making sure nothing triggered";
verifyRuleNotExecuted();
}
// REMOVE rule
qCDebug(dcTests()) << "Removing rule";
QVariantMap removeParams;
removeParams.insert("ruleId", ruleId);
response = injectAndWait("Rules.RemoveRule", removeParams);
verifyRuleError(response);
}
void TestRules::enableDisableRule()
{
// Add a rule
QVariantMap addRuleParams;
QVariantList events;
QVariantMap event1;
event1.insert("eventTypeId", mockEvent1EventTypeId);
event1.insert("deviceId", m_mockDeviceId);
events.append(event1);
addRuleParams.insert("eventDescriptors", events);
addRuleParams.insert("name", "TestRule");
QVariantList actions;
QVariantMap action;
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
action.insert("deviceId", m_mockDeviceId);
actions.append(action);
addRuleParams.insert("actions", actions);
QVariant response = injectAndWait("Rules.AddRule", addRuleParams);
verifyRuleError(response);
RuleId id = RuleId(response.toMap().value("params").toMap().value("ruleId").toString());
// Trigger an event
QNetworkAccessManager nam;
QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*)));
// trigger event in mock device
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();
verifyRuleExecuted(mockWithoutParamsActionTypeId);
cleanupMockHistory();
// Now DISABLE the rule invalid ruleId
QVariantMap disableParams;
disableParams.insert("ruleId", QUuid::createUuid().toString());
response = injectAndWait("Rules.DisableRule", disableParams);
verifyRuleError(response, RuleEngine::RuleErrorRuleNotFound);
// Now DISABLE the rule
disableParams.clear();
disableParams.insert("ruleId", id.toString());
response = injectAndWait("Rules.DisableRule", disableParams);
verifyRuleError(response);
// trigger event in mock device
spy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:%1/generateevent?eventtypeid=%2").arg(m_mockDevice1Port).arg(mockEvent1EventTypeId.toString())));
reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
verifyRuleNotExecuted();
cleanupMockHistory();
// Now ENABLE the rule again invald ruleId
QVariantMap enableParams;
enableParams.insert("ruleId", QUuid::createUuid().toString());
response = injectAndWait("Rules.EnableRule", enableParams);
verifyRuleError(response, RuleEngine::RuleErrorRuleNotFound);
// Now ENABLE the rule again
enableParams.clear();
enableParams.insert("ruleId", id.toString());
response = injectAndWait("Rules.EnableRule", enableParams);
verifyRuleError(response);
// trigger event in mock device
spy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:%1/generateevent?eventtypeid=%2").arg(m_mockDevice1Port).arg(mockEvent1EventTypeId.toString())));
reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
verifyRuleExecuted(mockWithoutParamsActionTypeId);
}
void TestRules::testEventBasedAction()
{
// Add a rule
QVariantMap addRuleParams;
QVariantMap eventDescriptor;
eventDescriptor.insert("eventTypeId", mockIntStateTypeId);
eventDescriptor.insert("deviceId", m_mockDeviceId);
addRuleParams.insert("eventDescriptors", QVariantList() << eventDescriptor);
addRuleParams.insert("name", "TestRule");
addRuleParams.insert("enabled", true);
QVariantList actions;
QVariantMap action;
QVariantList ruleActionParams;
QVariantMap param1;
param1.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
param1.insert("eventTypeId", mockIntStateTypeId);
param1.insert("eventParamTypeId", mockIntStateTypeId);
QVariantMap param2;
param2.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId);
param2.insert("value", true);
ruleActionParams.append(param1);
ruleActionParams.append(param2);
action.insert("actionTypeId", mockWithParamsActionTypeId);
action.insert("deviceId", m_mockDeviceId);
action.insert("ruleActionParams", ruleActionParams);
actions.append(action);
addRuleParams.insert("actions", actions);
qDebug() << addRuleParams;
QVariant response = injectAndWait("Rules.AddRule", addRuleParams);
verifyRuleError(response);
// Change the state
QNetworkAccessManager nam;
QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*)));
// state state to 42
qDebug() << "setting mock int state to 42";
QNetworkRequest request(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockIntStateTypeId.toString()).arg(42)));
QNetworkReply *reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
verifyRuleExecuted(mockWithParamsActionTypeId);
// TODO: check if this action was really executed with the int state value 42
}
void TestRules::testEventBasedRuleWithExitAction()
{
QNetworkAccessManager nam;
QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*)));
// Init bool state to true
spy.clear();
QNetworkRequest request(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockBoolStateTypeId.toString()).arg(true)));
QNetworkReply *reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
// Add a rule
QVariantMap addRuleParams;
QVariantMap eventDescriptor;
eventDescriptor.insert("eventTypeId", mockEvent1EventTypeId);
eventDescriptor.insert("deviceId", m_mockDeviceId);
addRuleParams.insert("eventDescriptors", QVariantList() << eventDescriptor);
addRuleParams.insert("name", "TestRule");
addRuleParams.insert("enabled", true);
QVariantMap stateEvaluator;
QVariantMap stateDescriptor;
stateDescriptor.insert("deviceId", m_mockDeviceId);
stateDescriptor.insert("stateTypeId", mockBoolStateTypeId);
stateDescriptor.insert("operator", "ValueOperatorEquals");
stateDescriptor.insert("value", true);
stateEvaluator.insert("stateDescriptor", stateDescriptor);
stateEvaluator.insert("operator", "StateOperatorAnd");
addRuleParams.insert("stateEvaluator", stateEvaluator);
QVariantList actions;
QVariantMap action;
QVariantList ruleActionParams;
QVariantMap param1;
param1.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
param1.insert("value", true);
QVariantMap param2;
param2.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId);
param2.insert("value", true);
ruleActionParams.append(param1);
ruleActionParams.append(param2);
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
action.insert("deviceId", m_mockDeviceId);
actions.append(action);
addRuleParams.insert("actions", actions);
actions.clear();
action.insert("actionTypeId", mockWithParamsActionTypeId);
action.insert("ruleActionParams", ruleActionParams);
actions.append(action);
addRuleParams.insert("exitActions", actions);
qDebug() << addRuleParams;
QVariant response = injectAndWait("Rules.AddRule", addRuleParams);
verifyRuleError(response);
// trigger event
spy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:%1/generateevent?eventtypeid=%2").arg(m_mockDevice1Port).arg(mockEvent1EventTypeId.toString())));
reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
// Verify the actions got executed
verifyRuleExecuted(mockWithoutParamsActionTypeId);
// set bool state to false
spy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockBoolStateTypeId.toString()).arg(false)));
reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
// trigger event
spy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:%1/generateevent?eventtypeid=%2").arg(m_mockDevice1Port).arg(mockEvent1EventTypeId.toString())));
reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
// Verify the exit actions got executed
verifyRuleExecuted(mockWithoutParamsActionTypeId);
}
void TestRules::testStateBasedAction()
{
QNetworkAccessManager nam;
QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*)));
// Init bool state to true
spy.clear();
QNetworkRequest request(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockBoolStateTypeId.toString()).arg(true)));
QNetworkReply *reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
// Init int state to 11
spy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockIntStateTypeId.toString()).arg(11)));
reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
// Add a rule
QVariantMap addRuleParams;
QVariantMap eventDescriptor;
eventDescriptor.insert("eventTypeId", mockEvent1EventTypeId);
eventDescriptor.insert("deviceId", m_mockDeviceId);
addRuleParams.insert("eventDescriptors", QVariantList() << eventDescriptor);
addRuleParams.insert("name", "TestRule");
addRuleParams.insert("enabled", true);
QVariantList actions;
QVariantMap action;
QVariantList ruleActionParams;
QVariantMap param1;
param1.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
param1.insert("stateDeviceId", m_mockDeviceId);
param1.insert("stateTypeId", mockIntStateTypeId);
QVariantMap param2;
param2.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId);
param2.insert("stateDeviceId", m_mockDeviceId);
param2.insert("stateTypeId", mockBoolStateTypeId);
ruleActionParams.append(param1);
ruleActionParams.append(param2);
actions.clear();
action.insert("deviceId", m_mockDeviceId);
action.insert("actionTypeId", mockWithParamsActionTypeId);
action.insert("ruleActionParams", ruleActionParams);
actions.append(action);
addRuleParams.insert("actions", actions);
qCDebug(dcTests) << "Adding rule";
QVariant response = injectAndWait("Rules.AddRule", addRuleParams);
verifyRuleError(response);
// trigger event
spy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:%1/generateevent?eventtypeid=%2").arg(m_mockDevice1Port).arg(mockEvent1EventTypeId.toString())));
reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
LogFilter filter;
filter.addDeviceId(m_mockDeviceId);
filter.addTypeId(mockWithParamsActionTypeId);
QList<LogEntry> entries = NymeaCore::instance()->logEngine()->logEntries(filter);
qCDebug(dcTests()) << "Log entries:" << entries;
// set bool state to false
spy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockBoolStateTypeId.toString()).arg(false)));
reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
// trigger event
spy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:%1/generateevent?eventtypeid=%2").arg(m_mockDevice1Port).arg(mockEvent1EventTypeId.toString())));
reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
entries = NymeaCore::instance()->logEngine()->logEntries(filter);
qCDebug(dcTests()) << "Log entries:" << entries;
}
void TestRules::removePolicyUpdate()
{
// ADD parent device
QVariantMap params;
params.insert("deviceClassId", mockParentDeviceClassId);
params.insert("name", "Parent device");
QSignalSpy addedSpy(NymeaCore::instance()->deviceManager(), &DeviceManager::deviceAdded);
QVariant response = injectAndWait("Devices.AddConfiguredDevice", params);
verifyDeviceError(response);
DeviceId parentDeviceId = DeviceId(response.toMap().value("params").toMap().value("deviceId").toString());
QVERIFY(!parentDeviceId.isNull());
addedSpy.wait();
// find child device
response = injectAndWait("Devices.GetConfiguredDevices");
QVariantList devices = response.toMap().value("params").toMap().value("devices").toList();
DeviceId childDeviceId;
foreach (const QVariant deviceVariant, devices) {
QVariantMap deviceMap = deviceVariant.toMap();
if (deviceMap.value("deviceClassId").toString() == mockChildDeviceClassId.toString()) {
if (deviceMap.value("parentId") == parentDeviceId.toString()) {
//qDebug() << QJsonDocument::fromVariant(deviceVariant).toJson();
childDeviceId = DeviceId(deviceMap.value("id").toString());
}
}
}
QVERIFY2(!childDeviceId.isNull(), "Could not find child device");
// Add rule with child device
QVariantList eventDescriptors;
eventDescriptors.append(createEventDescriptor(childDeviceId, mockChildBoolValueEventTypeId));
eventDescriptors.append(createEventDescriptor(parentDeviceId, mockParentBoolValueEventTypeId));
eventDescriptors.append(createEventDescriptor(m_mockDeviceId, mockEvent1EventTypeId));
params.clear(); response.clear();
params.insert("name", "RemovePolicy");
params.insert("eventDescriptors", eventDescriptors);
params.insert("actions", QVariantList() << createActionWithParams(m_mockDeviceId));
response = injectAndWait("Rules.AddRule", params);
verifyRuleError(response);
RuleId ruleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toString());
QVERIFY2(!ruleId.isNull(), "Could not get ruleId");
// Try to remove child device
params.clear(); response.clear();
params.insert("deviceId", childDeviceId);
response = injectAndWait("Devices.RemoveConfiguredDevice", params);
verifyDeviceError(response, Device::DeviceErrorDeviceIsChild);
// Try to remove child device
params.clear(); response.clear();
params.insert("deviceId", parentDeviceId);
response = injectAndWait("Devices.RemoveConfiguredDevice", params);
verifyDeviceError(response, Device::DeviceErrorDeviceInRule);
// Remove policy
params.clear(); response.clear();
params.insert("deviceId", parentDeviceId);
params.insert("removePolicy", "RemovePolicyUpdate");
response = injectAndWait("Devices.RemoveConfiguredDevice", params);
verifyDeviceError(response);
// get updated rule
params.clear();
params.insert("ruleId", ruleId);
response = injectAndWait("Rules.GetRuleDetails", params);
verifyRuleError(response);
QVariantMap rule = response.toMap().value("params").toMap().value("rule").toMap();
qDebug() << "Updated rule:" << QJsonDocument::fromVariant(rule).toJson();
QVERIFY(rule.value("eventDescriptors").toList().count() == 1);
// REMOVE rule
QVariantMap removeParams;
removeParams.insert("ruleId", ruleId);
response = injectAndWait("Rules.RemoveRule", removeParams);
verifyRuleError(response);
}
void TestRules::removePolicyCascade()
{
// ADD parent device
QVariantMap params;
params.insert("deviceClassId", mockParentDeviceClassId);
params.insert("name", "Parent device");
QSignalSpy addedSpy(NymeaCore::instance()->deviceManager(), &DeviceManager::deviceAdded);
QVariant response = injectAndWait("Devices.AddConfiguredDevice", params);
verifyDeviceError(response);
DeviceId parentDeviceId = DeviceId(response.toMap().value("params").toMap().value("deviceId").toString());
QVERIFY(!parentDeviceId.isNull());
addedSpy.wait();
// find child device
response = injectAndWait("Devices.GetConfiguredDevices");
QVariantList devices = response.toMap().value("params").toMap().value("devices").toList();
DeviceId childDeviceId;
foreach (const QVariant deviceVariant, devices) {
QVariantMap deviceMap = deviceVariant.toMap();
if (deviceMap.value("deviceClassId").toString() == mockChildDeviceClassId.toString()) {
if (deviceMap.value("parentId") == parentDeviceId.toString()) {
//qDebug() << QJsonDocument::fromVariant(deviceVariant).toJson();
childDeviceId = DeviceId(deviceMap.value("id").toString());
}
}
}
QVERIFY2(!childDeviceId.isNull(), "Could not find child device");
// Add rule with child device
QVariantList eventDescriptors;
eventDescriptors.append(createEventDescriptor(childDeviceId, mockChildBoolValueEventTypeId));
eventDescriptors.append(createEventDescriptor(parentDeviceId, mockParentBoolValueEventTypeId));
eventDescriptors.append(createEventDescriptor(m_mockDeviceId, mockEvent1EventTypeId));
params.clear(); response.clear();
params.insert("name", "RemovePolicy");
params.insert("eventDescriptors", eventDescriptors);
params.insert("actions", QVariantList() << createActionWithParams(m_mockDeviceId));
response = injectAndWait("Rules.AddRule", params);
verifyRuleError(response);
RuleId ruleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toString());
QVERIFY2(!ruleId.isNull(), "Could not get ruleId");
// Try to remove child device
params.clear(); response.clear();
params.insert("deviceId", childDeviceId);
response = injectAndWait("Devices.RemoveConfiguredDevice", params);
verifyDeviceError(response, Device::DeviceErrorDeviceIsChild);
// Try to remove child device
params.clear(); response.clear();
params.insert("deviceId", parentDeviceId);
response = injectAndWait("Devices.RemoveConfiguredDevice", params);
verifyDeviceError(response, Device::DeviceErrorDeviceInRule);
// Remove policy
params.clear(); response.clear();
params.insert("deviceId", parentDeviceId);
params.insert("removePolicy", "RemovePolicyCascade");
response = injectAndWait("Devices.RemoveConfiguredDevice", params);
verifyDeviceError(response);
// get updated rule
params.clear();
params.insert("ruleId", ruleId);
response = injectAndWait("Rules.GetRuleDetails", params);
verifyRuleError(response, RuleEngine::RuleErrorRuleNotFound);
}
void TestRules::removePolicyUpdateRendersUselessRule()
{
// ADD parent device
QVariantMap params;
params.insert("deviceClassId", mockParentDeviceClassId);
params.insert("name", "Parent device");
QSignalSpy addedSpy(NymeaCore::instance()->deviceManager(), &DeviceManager::deviceAdded);
QVariant response = injectAndWait("Devices.AddConfiguredDevice", params);
verifyDeviceError(response);
DeviceId parentDeviceId = DeviceId(response.toMap().value("params").toMap().value("deviceId").toString());
QVERIFY(!parentDeviceId.isNull());
addedSpy.wait();
// find child device
qCDebug(dcTests()) << "Gettin devices";
response = injectAndWait("Devices.GetConfiguredDevices");
QVariantList devices = response.toMap().value("params").toMap().value("devices").toList();
DeviceId childDeviceId;
foreach (const QVariant deviceVariant, devices) {
QVariantMap deviceMap = deviceVariant.toMap();
if (deviceMap.value("deviceClassId").toString() == mockChildDeviceClassId.toString()) {
if (deviceMap.value("parentId") == parentDeviceId.toString()) {
//qDebug() << QJsonDocument::fromVariant(deviceVariant).toJson();
childDeviceId = DeviceId(deviceMap.value("id").toString());
}
}
}
QVERIFY2(!childDeviceId.isNull(), "Could not find child device");
// Add rule with child device
QVariantList eventDescriptors;
eventDescriptors.append(createEventDescriptor(childDeviceId, mockChildBoolValueEventTypeId));
eventDescriptors.append(createEventDescriptor(parentDeviceId, mockParentBoolValueEventTypeId));
eventDescriptors.append(createEventDescriptor(m_mockDeviceId, mockEvent1EventTypeId));
params.clear(); response.clear();
params.insert("name", "RemovePolicy");
params.insert("eventDescriptors", eventDescriptors);
QVariantMap action;
action.insert("deviceId", childDeviceId);
action.insert("actionTypeId", mockChildBoolValueActionTypeId);
QVariantMap ruleActionParam;
ruleActionParam.insert("paramTypeId", mockChildBoolValueActionBoolValueParamTypeId);
ruleActionParam.insert("value", true);
action.insert("ruleActionParams", QVariantList() << ruleActionParam);
params.insert("actions", QVariantList() << action);
qCDebug(dcTests()) << "Adding Rule";
response = injectAndWait("Rules.AddRule", params);
verifyRuleError(response);
RuleId ruleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toString());
QVERIFY2(!ruleId.isNull(), "Could not get ruleId");
// Try to remove child device
qCDebug(dcTests()) << "Removing device (expecing failure - device is child)";
params.clear(); response.clear();
params.insert("deviceId", childDeviceId);
response = injectAndWait("Devices.RemoveConfiguredDevice", params);
verifyDeviceError(response, Device::DeviceErrorDeviceIsChild);
// Try to remove child device
qCDebug(dcTests()) << "Removing device (expeciting failure - device in use)";
params.clear(); response.clear();
params.insert("deviceId", parentDeviceId);
response = injectAndWait("Devices.RemoveConfiguredDevice", params);
verifyDeviceError(response, Device::DeviceErrorDeviceInRule);
// Remove policy
qCDebug(dcTests()) << "Removing device with update policy";
params.clear(); response.clear();
params.insert("deviceId", parentDeviceId);
params.insert("removePolicy", "RemovePolicyUpdate");
response = injectAndWait("Devices.RemoveConfiguredDevice", params);
verifyDeviceError(response);
// get updated rule. It should've been deleted given it ended up with no actions
qCDebug(dcTests()) << "Getting details";
params.clear();
params.insert("ruleId", ruleId);
response = injectAndWait("Rules.GetRuleDetails", params);
verifyRuleError(response, RuleEngine::RuleErrorRuleNotFound);
}
void TestRules::testRuleActionParams_data()
{
QVariantMap action;
QVariantList ruleActionParams;
QVariantMap param1;
param1.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
param1.insert("value", 4);
QVariantMap param2;
param2.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId);
param2.insert("value", true);
ruleActionParams.append(param1);
ruleActionParams.append(param2);
action.insert("actionTypeId", mockWithParamsActionTypeId);
action.insert("deviceId", m_mockDeviceId);
action.insert("ruleActionParams", ruleActionParams);
QVariantMap invalidAction1;
invalidAction1.insert("actionTypeId", mockWithParamsActionTypeId);
invalidAction1.insert("deviceId", m_mockDeviceId);
invalidAction1.insert("ruleActionParams", QVariantList() << param2);
QVariantMap invalidAction2;
invalidAction2.insert("actionTypeId", mockWithParamsActionTypeId);
invalidAction2.insert("deviceId", m_mockDeviceId);
invalidAction2.insert("ruleActionParams", QVariantList() << param1);
QTest::addColumn<QVariantMap>("action");
QTest::addColumn<QVariantMap>("exitAction");
QTest::addColumn<RuleEngine::RuleError>("error");
QTest::newRow("valid action params") << action << QVariantMap() << RuleEngine::RuleErrorNoError;
QTest::newRow("valid action and exit action params") << action << action << RuleEngine::RuleErrorNoError;
QTest::newRow("invalid action params1") << invalidAction1 << QVariantMap() << RuleEngine::RuleErrorMissingParameter;
QTest::newRow("invalid action params2") << invalidAction2 << QVariantMap() << RuleEngine::RuleErrorMissingParameter;
QTest::newRow("valid action and invalid exit action params1") << action << invalidAction1 << RuleEngine::RuleErrorMissingParameter;
QTest::newRow("valid action and invalid exit action params2") << action << invalidAction2 << RuleEngine::RuleErrorMissingParameter;
}
void TestRules::testRuleActionParams()
{
QFETCH(QVariantMap, action);
QFETCH(QVariantMap, exitAction);
QFETCH(RuleEngine::RuleError, error);
// Add a rule
QVariantMap addRuleParams;
addRuleParams.insert("name", "TestRule");
addRuleParams.insert("enabled", true);
if (!action.isEmpty())
addRuleParams.insert("actions", QVariantList() << action);
if (!exitAction.isEmpty())
addRuleParams.insert("exitActions", QVariantList() << exitAction);
QVariant response = injectAndWait("Rules.AddRule", addRuleParams);
verifyRuleError(response, error);
}
void TestRules::testRuleActionPAramsFromEventParameter_data() {
QTest::addColumn<QVariantMap>("event");
QTest::addColumn<QVariantMap>("action");
QTest::addColumn<RuleEngine::RuleError>("error");
QVariantMap intEvent;
intEvent.insert("eventTypeId", mockIntStateTypeId);
intEvent.insert("deviceId", m_mockDeviceId);
QVariantMap intAction;
intAction.insert("actionTypeId", mockWithParamsActionTypeId);
intAction.insert("deviceId", m_mockDeviceId);
QVariantList ruleActionParams;
QVariantMap intParam;
intParam.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
intParam.insert("eventTypeId", mockIntStateTypeId);
intParam.insert("eventParamTypeId", mockIntStateTypeId);
ruleActionParams.append(intParam);
QVariantMap boolParam;
boolParam.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId);
boolParam.insert("value", true);
ruleActionParams.append(boolParam);
intAction.insert("ruleActionParams", ruleActionParams);
QVariantMap boolAction;
boolAction.insert("actionTypeId", mockWithParamsActionTypeId);
boolAction.insert("deviceId", m_mockDeviceId);
ruleActionParams.clear();
intParam.clear();
intParam.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
intParam.insert("value", 5);
ruleActionParams.append(intParam);
boolParam.clear();
boolParam.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId);
boolParam.insert("eventTypeId", mockIntStateTypeId);
boolParam.insert("eventParamTypeId", mockIntStateTypeId);
ruleActionParams.append(boolParam);
boolAction.insert("ruleActionParams", ruleActionParams);
QTest::newRow("int -> int") << intEvent << intAction << RuleEngine::RuleErrorNoError;
QTest::newRow("int -> bool") << intEvent << boolAction << RuleEngine::RuleErrorNoError;
}
void TestRules::testRuleActionPAramsFromEventParameter()
{
QFETCH(QVariantMap, event);
QFETCH(QVariantMap, action);
QFETCH(RuleEngine::RuleError, error);
QVariantMap addRuleParams;
addRuleParams.insert("name", "TestRule");
addRuleParams.insert("enabled", true);
addRuleParams.insert("eventDescriptors", QVariantList() << event);
addRuleParams.insert("actions", QVariantList() << action);
QVariant response = injectAndWait("Rules.AddRule", addRuleParams);
verifyRuleError(response, error);
}
void TestRules::testInitStatesActive()
{
// Create a rule to toggle the power state on event 1
QVariantMap params;
params.insert("name", "testrule");
QVariantMap eventDescriptor;
eventDescriptor.insert("deviceId", m_mockDeviceId);
eventDescriptor.insert("eventTypeId", mockEvent1EventTypeId);
QVariantList eventDescriptors;
eventDescriptors.append(eventDescriptor);
params.insert("eventDescriptors", eventDescriptors);
QVariantMap stateEvaluator;
QVariantMap stateDescriptor;
stateDescriptor.insert("stateTypeId", mockPowerStateTypeId);
stateDescriptor.insert("operator", "ValueOperatorEquals");
stateDescriptor.insert("value", false);
stateDescriptor.insert("deviceId", m_mockDeviceId);
stateEvaluator.insert("stateDescriptor", stateDescriptor);
params.insert("stateEvaluator", stateEvaluator);
QVariantList actions;
QVariantMap action;
action.insert("actionTypeId", mockPowerActionTypeId);
action.insert("deviceId", m_mockDeviceId);
QVariantList actionParams;
QVariantMap actionParam;
actionParam.insert("paramTypeId", mockPowerActionPowerParamTypeId);
actionParam.insert("value", true);
actionParams.append(actionParam);
action.insert("ruleActionParams", actionParams);
actions.append(action);
params.insert("actions", actions);
QVariantList exitActions;
QVariantMap exitAction;
exitAction.insert("actionTypeId", mockPowerActionTypeId);
exitAction.insert("deviceId", m_mockDeviceId);
QVariantList exitActionParams;
QVariantMap exitActionParam;
exitActionParam.insert("paramTypeId", mockPowerActionPowerParamTypeId);
exitActionParam.insert("value", false);
exitActionParams.append(exitActionParam);
exitAction.insert("ruleActionParams", exitActionParams);
exitActions.append(exitAction);
params.insert("exitActions", exitActions);
QVariant response = injectAndWait("Rules.AddRule", params);
RuleId ruleId = RuleId::fromUuid(response.toMap().value("params").toMap().value("ruleId").toUuid());
QVERIFY2(!ruleId.isNull(), "Error adding rule");
// Get the current state value, make sure it's false
params.clear();
params.insert("deviceId", m_mockDeviceId);
params.insert("stateTypeId", mockPowerStateTypeId);
response = injectAndWait("Devices.GetStateValue", params);
QVERIFY2(response.toMap().value("params").toMap().value("value").toBool() == false, "State initially true while it should be false");
// Trigger the event
generateEvent(mockEvent1EventTypeId);
// Make sure the value changed after the event has triggered
response = injectAndWait("Devices.GetStateValue", params);
QVERIFY2(response.toMap().value("params").toMap().value("value").toBool() == true, "State is false while it should have changed to true");
// Trigger the event again...
generateEvent(mockEvent1EventTypeId);
// ... and make sure the value changed back to false
response = injectAndWait("Devices.GetStateValue", params);
QVERIFY2(response.toMap().value("params").toMap().value("value").toBool() == false, "State is true while it should have changed to false");
restartServer();
// Make sure the value changed is still false
response = injectAndWait("Devices.GetStateValue", params);
QVERIFY2(response.toMap().value("params").toMap().value("value").toBool() == false, "State is true while it should have changed to false");
// Trigger the event
generateEvent(mockEvent1EventTypeId);
// Make sure the value changed after the event has triggered
response = injectAndWait("Devices.GetStateValue", params);
QVERIFY2(response.toMap().value("params").toMap().value("value").toBool() == true, "State is false while it should have changed to true");
}
void TestRules::testInterfaceBasedEventRule()
{
QNetworkAccessManager nam;
QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*)));
// state battery critical state to false initially
QNetworkRequest request(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockBatteryCriticalStateTypeId.toString()).arg(false)));
QNetworkReply *reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
QVariantMap powerAction;
powerAction.insert("interface", "light");
powerAction.insert("interfaceAction", "power");
QVariantMap powerActionParam;
powerActionParam.insert("paramName", "power");
powerActionParam.insert("value", true);
powerAction.insert("ruleActionParams", QVariantList() << powerActionParam);
QVariantMap lowBatteryEvent;
lowBatteryEvent.insert("interface", "battery");
lowBatteryEvent.insert("interfaceEvent", "batteryCritical");
QVariantMap eventParams;
eventParams.insert("paramName", "batteryCritical");
eventParams.insert("value", true);
eventParams.insert("operator", "ValueOperatorEquals");
lowBatteryEvent.insert("paramDescriptors", QVariantList() << eventParams);
QVariantMap addRuleParams;
addRuleParams.insert("name", "TestInterfaceBasedRule");
addRuleParams.insert("enabled", true);
addRuleParams.insert("actions", QVariantList() << powerAction);
addRuleParams.insert("eventDescriptors", QVariantList() << lowBatteryEvent);
qDebug(dcTests) << "Inserting rule";
QVariant response = injectAndWait("Rules.AddRule", addRuleParams);
QCOMPARE(response.toMap().value("status").toString(), QString("success"));
QCOMPARE(response.toMap().value("params").toMap().value("ruleError").toString(), QString("RuleErrorNoError"));
QVariantMap getRuleParams;
getRuleParams.insert("ruleId", response.toMap().value("params").toMap().value("ruleId"));
qDebug(dcTests) << "Getting rule details";
response = injectAndWait("Rules.GetRuleDetails", getRuleParams);
QCOMPARE(response.toMap().value("params").toMap().value("ruleError").toString(), QString("RuleErrorNoError"));
QCOMPARE(response.toMap().value("params").toMap().value("rule").toMap().value("eventDescriptors").toList().first().toMap().value("interface").toString(), QString("battery"));
QCOMPARE(response.toMap().value("params").toMap().value("rule").toMap().value("eventDescriptors").toList().first().toMap().value("interfaceEvent").toString(), QString("batteryCritical"));
QCOMPARE(response.toMap().value("params").toMap().value("rule").toMap().value("actions").toList().first().toMap().value("interface").toString(), QString("light"));
QCOMPARE(response.toMap().value("params").toMap().value("rule").toMap().value("actions").toList().first().toMap().value("interfaceAction").toString(), QString("power"));
QCOMPARE(response.toMap().value("params").toMap().value("rule").toMap().value("actions").toList().first().toMap().value("ruleActionParams").toList().first().toMap().value("paramName").toString(), QString("power"));
QCOMPARE(response.toMap().value("params").toMap().value("rule").toMap().value("actions").toList().first().toMap().value("ruleActionParams").toList().first().toMap().value("value").toString(), QString("true"));
qDebug(dcTests) << "Clearing action history";
// Change the state to true, action should trigger
spy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:%1/clearactionhistory").arg(m_mockDevice1Port)));
reply = nam.get(request);
qDebug(dcTests) << "Changing battery state -> true";
spy.wait(); spy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockBatteryCriticalStateTypeId.toString()).arg(true)));
reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
verifyRuleExecuted(mockPowerActionTypeId);
qDebug(dcTests) << "Clearing action history";
// Change the state to false, action should not trigger
spy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:%1/clearactionhistory").arg(m_mockDevice1Port)));
reply = nam.get(request);
qDebug(dcTests) << "Changing battery state -> false";
spy.wait(); spy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockBatteryCriticalStateTypeId.toString()).arg(false)));
reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
verifyRuleNotExecuted();
}
void TestRules::testInterfaceBasedStateRule()
{
QNetworkAccessManager nam;
QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*)));
// state battery critical state to false initially
QNetworkRequest request(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockBatteryCriticalStateTypeId.toString()).arg(false)));
QNetworkReply *reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
QVariantMap powerAction;
powerAction.insert("interface", "light");
powerAction.insert("interfaceAction", "power");
QVariantMap powerActionParam;
powerActionParam.insert("paramName", "power");
powerActionParam.insert("value", true);
powerAction.insert("ruleActionParams", QVariantList() << powerActionParam);
QVariantMap lowBatteryState;
lowBatteryState.insert("interface", "battery");
lowBatteryState.insert("interfaceState", "batteryCritical");
QVariantMap stateDescriptor;
stateDescriptor.insert("interface", "battery");
stateDescriptor.insert("interfaceState", "batteryCritical");
stateDescriptor.insert("value", true);
stateDescriptor.insert("operator", "ValueOperatorEquals");
QVariantMap stateEvaluator;
stateEvaluator.insert("stateDescriptor", stateDescriptor);
QVariantMap addRuleParams;
addRuleParams.insert("name", "TestInterfaceBasedStateRule");
addRuleParams.insert("enabled", true);
addRuleParams.insert("stateEvaluator", stateEvaluator);
addRuleParams.insert("actions", QVariantList() << powerAction);
QVariant response = injectAndWait("Rules.AddRule", addRuleParams);
QCOMPARE(response.toMap().value("status").toString(), QString("success"));
QCOMPARE(response.toMap().value("params").toMap().value("ruleError").toString(), QString("RuleErrorNoError"));
QVariantMap getRuleParams;
getRuleParams.insert("ruleId", response.toMap().value("params").toMap().value("ruleId"));
response = injectAndWait("Rules.GetRuleDetails", getRuleParams);
QCOMPARE(response.toMap().value("params").toMap().value("ruleError").toString(), QString("RuleErrorNoError"));
QCOMPARE(response.toMap().value("params").toMap().value("rule").toMap().value("stateEvaluator").toMap().value("stateDescriptor").toMap().value("interface").toString(), QString("battery"));
QCOMPARE(response.toMap().value("params").toMap().value("rule").toMap().value("stateEvaluator").toMap().value("stateDescriptor").toMap().value("interfaceState").toString(), QString("batteryCritical"));
QCOMPARE(response.toMap().value("params").toMap().value("rule").toMap().value("actions").toList().first().toMap().value("interface").toString(), QString("light"));
QCOMPARE(response.toMap().value("params").toMap().value("rule").toMap().value("actions").toList().first().toMap().value("interfaceAction").toString(), QString("power"));
QCOMPARE(response.toMap().value("params").toMap().value("rule").toMap().value("actions").toList().first().toMap().value("ruleActionParams").toList().first().toMap().value("paramName").toString(), QString("power"));
QCOMPARE(response.toMap().value("params").toMap().value("rule").toMap().value("actions").toList().first().toMap().value("ruleActionParams").toList().first().toMap().value("value").toString(), QString("true"));
// Change the state
spy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockBatteryCriticalStateTypeId.toString()).arg(true)));
reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
verifyRuleExecuted(mockPowerActionTypeId);
}
void TestRules::testLoopingRules()
{
QVariantMap powerOnActionParam;
powerOnActionParam.insert("paramTypeId", mockPowerStateTypeId);
powerOnActionParam.insert("value", true);
QVariantMap powerOffActionParam;
powerOffActionParam.insert("paramTypeId", mockPowerStateTypeId);
powerOffActionParam.insert("value", false);
QVariantMap powerOnEventParam = powerOnActionParam;
powerOnEventParam.insert("operator", "ValueOperatorEquals");
QVariantMap powerOffEventParam = powerOffActionParam;
powerOffEventParam.insert("operator", "ValueOperatorEquals");
QVariantMap onEvent;
onEvent.insert("eventTypeId", mockPowerStateTypeId);
onEvent.insert("deviceId", m_mockDeviceId);
onEvent.insert("paramDescriptors", QVariantList() << powerOnEventParam);
QVariantMap offEvent;
offEvent.insert("eventTypeId", mockPowerStateTypeId);
offEvent.insert("deviceId", m_mockDeviceId);
offEvent.insert("paramDescriptors", QVariantList() << powerOffEventParam);
QVariantMap onAction;
onAction.insert("actionTypeId", mockPowerStateTypeId);
onAction.insert("deviceId", m_mockDeviceId);
onAction.insert("ruleActionParams", QVariantList() << powerOnActionParam);
QVariantMap offAction;
offAction.insert("actionTypeId", mockPowerStateTypeId);
offAction.insert("deviceId", m_mockDeviceId);
offAction.insert("ruleActionParams", QVariantList() << powerOffActionParam);
// Add rule 1
QVariantMap addRuleParams;
addRuleParams.insert("name", "Rule off -> on");
addRuleParams.insert("eventDescriptors", QVariantList() << offEvent);
addRuleParams.insert("actions", QVariantList() << onAction);
QVariant response = injectAndWait("Rules.AddRule", addRuleParams);
qWarning() << response;
verifyRuleError(response);
// Add rule 1
addRuleParams.clear();
addRuleParams.insert("name", "Rule on -> off");
addRuleParams.insert("eventDescriptors", QVariantList() << onEvent);
addRuleParams.insert("actions", QVariantList() << offAction);
response = injectAndWait("Rules.AddRule", addRuleParams);
verifyRuleError(response);
cleanupMockHistory();
QVariantMap params;
params.insert("deviceId", m_mockDeviceId);
params.insert("actionTypeId", mockPowerStateTypeId);
params.insert("params", QVariantList() << powerOffActionParam);
response = injectAndWait("Actions.ExecuteAction", params);
verifyRuleExecuted(mockPowerActionTypeId);
cleanupMockHistory();
params.clear();
params.insert("deviceId", m_mockDeviceId);
params.insert("actionTypeId", mockPowerStateTypeId);
params.insert("params", QVariantList() << powerOnActionParam);
response = injectAndWait("Actions.ExecuteAction", params);
verifyRuleExecuted(mockPowerActionTypeId);
// No need to check anything else. This test sets up a binding loop and if the core doesn't catch it it'll crash here.
}
void TestRules::testScene()
{
// Given scenes are rules without stateEvaluator and eventDescriptors, they evaluate to true when asked for "active()"
// This test should catch the case where such a rule might wrongly be exected by evaluating it
// when another state change happens or when a time event is evaluated
NymeaCore::instance()->timeManager()->stopTimer();
QDateTime now = QDateTime::currentDateTime();
NymeaCore::instance()->timeManager()->setTime(now);
QNetworkAccessManager nam;
QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*)));
// state power state to false initially
QNetworkRequest request(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockPowerStateTypeId.toString()).arg(false)));
QNetworkReply *reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
// state battery critical state to false initially
spy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockBatteryCriticalStateTypeId.toString()).arg(false)));
reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
// Add a scene setting power to true
QVariantMap powerAction;
powerAction.insert("deviceId", m_mockDeviceId);
powerAction.insert("actionTypeId", mockPowerStateTypeId);
QVariantMap powerActionParam;
powerActionParam.insert("paramTypeId", mockPowerStateTypeId);
powerActionParam.insert("value", true);
powerAction.insert("ruleActionParams", QVariantList() << powerActionParam);
QVariantMap addRuleParams;
addRuleParams.insert("name", "TestScene");
addRuleParams.insert("enabled", true);
addRuleParams.insert("executable", true);
addRuleParams.insert("actions", QVariantList() << powerAction);
QVariant response = injectAndWait("Rules.AddRule", addRuleParams);
QCOMPARE(response.toMap().value("status").toString(), QString("success"));
QCOMPARE(response.toMap().value("params").toMap().value("ruleError").toString(), QString("RuleErrorNoError"));
// trigger state change on battery critical
spy.clear();
request = QNetworkRequest(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockBatteryCriticalStateTypeId.toString()).arg(true)));
reply = nam.get(request);
spy.wait();
QCOMPARE(spy.count(), 1);
reply->deleteLater();
verifyRuleNotExecuted();
// Now trigger a time change
NymeaCore::instance()->timeManager()->setTime(now.addSecs(1));
verifyRuleNotExecuted();
}
void TestRules::testHousekeeping_data()
{
QTest::addColumn<bool>("testAction");
QTest::addColumn<bool>("testExitAction");
QTest::addColumn<bool>("testStateEvaluator");
QTest::addColumn<bool>("testEventDescriptor");
QTest::newRow("action") << true << false << false << false;
QTest::newRow("exitAction") << false << true << false << false;
QTest::newRow("stateDescriptor") << false << false << true << false;
QTest::newRow("eventDescriptor")<< false << false << false << true;
}
void TestRules::testHousekeeping()
{
QFETCH(bool, testAction);
QFETCH(bool, testExitAction);
QFETCH(bool, testStateEvaluator);
QFETCH(bool, testEventDescriptor);
QVariantMap params;
params.insert("deviceClassId", mockDeviceClassId);
params.insert("name", "TestDeviceToBeRemoved");
QVariantList deviceParams;
QVariantMap httpParam;
httpParam.insert("paramTypeId", mockDeviceHttpportParamTypeId);
httpParam.insert("value", 6667);
deviceParams.append(httpParam);
params.insert("deviceParams", deviceParams);
QVariant response = injectAndWait("Devices.AddConfiguredDevice", params);
DeviceId deviceId = DeviceId::fromUuid(response.toMap().value("params").toMap().value("deviceId").toUuid());
QVERIFY2(!deviceId.isNull(), "Something went wrong creating the device for testing.");
// Create a rule with this device
params.clear();
params.insert("name", "testrule");
if (testEventDescriptor) {
QVariantList eventDescriptors;
QVariantMap eventDescriptor;
eventDescriptor.insert("eventTypeId", mockEvent1EventTypeId);
eventDescriptor.insert("deviceId", testEventDescriptor ? deviceId : m_mockDeviceId);
eventDescriptors.append(eventDescriptor);
params.insert("eventDescriptors", eventDescriptors);
}
QVariantMap stateEvaluator;
QVariantMap stateDescriptor;
stateDescriptor.insert("stateTypeId", mockIntStateTypeId);
stateDescriptor.insert("operator", "ValueOperatorGreater");
stateDescriptor.insert("value", 555);
stateDescriptor.insert("deviceId", testStateEvaluator ? deviceId : m_mockDeviceId);
stateEvaluator.insert("stateDescriptor", stateDescriptor);
params.insert("stateEvaluator", stateEvaluator);
QVariantList actions;
QVariantMap action;
action.insert("actionTypeId", mockWithoutParamsActionTypeId);
action.insert("deviceId", testAction ? deviceId : m_mockDeviceId);
actions.append(action);
params.insert("actions", actions);
if (!testEventDescriptor) {
QVariantList exitActions;
QVariantMap exitAction;
exitAction.insert("actionTypeId", mockWithoutParamsActionTypeId);
exitAction.insert("deviceId", testExitAction ? deviceId : m_mockDeviceId);
exitActions.append(exitAction);
params.insert("exitActions", exitActions);
}
response = injectAndWait("Rules.AddRule", params);
RuleId ruleId = RuleId::fromUuid(response.toMap().value("params").toMap().value("ruleId").toUuid());
// Verfy that the rule has been created successfully and our device is in there.
params.clear();
params.insert("ruleId", ruleId);
response = injectAndWait("Rules.GetRuleDetails", params);
if (testEventDescriptor) {
QVERIFY2(response.toMap().value("params").toMap().value("rule").toMap().value("eventDescriptors").toList().first().toMap().value("deviceId").toUuid().toString() == (testEventDescriptor ? deviceId.toString() : m_mockDeviceId.toString()), "Couldn't find device in eventDescriptor of rule");
}
QVERIFY2(response.toMap().value("params").toMap().value("rule").toMap().value("stateEvaluator").toMap().value("stateDescriptor").toMap().value("deviceId").toUuid().toString() == (testStateEvaluator ? deviceId.toString() : m_mockDeviceId.toString()), "Couldn't find device in stateEvaluator of rule");
QVERIFY2(response.toMap().value("params").toMap().value("rule").toMap().value("actions").toList().first().toMap().value("deviceId").toUuid().toString() == (testAction ? deviceId.toString() : m_mockDeviceId.toString()), "Couldn't find device in actions of rule");
if (!testEventDescriptor) {
QVERIFY2(response.toMap().value("params").toMap().value("rule").toMap().value("exitActions").toList().first().toMap().value("deviceId").toUuid().toString() == (testExitAction ? deviceId.toString() : m_mockDeviceId.toString()), "Couldn't find device in exitActions of rule");
}
// Manually delete this device from config
NymeaSettings settings(NymeaSettings::SettingsRoleDevices);
settings.beginGroup("DeviceConfig");
settings.remove(deviceId.toString());
settings.endGroup();
restartServer();
// Now make sure the appropriate entries with our device have disappeared
response = injectAndWait("Rules.GetRuleDetails", params);
if (testEventDescriptor) {
QVERIFY2(response.toMap().value("params").toMap().value("rule").toMap().value("eventDescriptors").toList().count() == (testEventDescriptor ? 0: 1), "EventDescriptor still in rule... should've been removed by housekeeping.");
}
QVERIFY2(response.toMap().value("params").toMap().value("rule").toMap().value("stateEvaluator").toMap().value("stateDescriptor").toMap().isEmpty() == (testStateEvaluator ? true : false), "StateEvaluator still in rule... should've been removed by housekeeping.");
QVERIFY2(response.toMap().value("params").toMap().value("rule").toMap().value("actions").toList().count() == (testAction ? 0 : 1), "Action still in rule... should've been removed by housekeeping.");
if (!testEventDescriptor) {
QVERIFY2(response.toMap().value("params").toMap().value("rule").toMap().value("exitActions").toList().count() == (testExitAction ? 0: 1), "ExitAction still in rule... should've been removed by housekeeping.");
}
}
#include "testrules.moc"
QTEST_MAIN(TestRules)