This a) makes the log db threaded by using QtConcurrent to run queries in a different thread but still keeps ordering of the queries and always only allows a single query at a time (QSql is not threadsafe). This fixes removeDevice calls failing if we take more than $jsonprc_timeout to clean a deleted device from the DB and keeps nymead responsive during that too. b) generally improces performance of the system by not requiring operations (emitting events, changing states) to wait for the sync log db entry to be made. c) drops some of the houskeeping code on nymea startup. While this will still do log db housekeeping if the DB exceeds maxDbSize, it will not run housekeeping on the DB any more at application startup. Reasoning for this is that there have been reports of rules/log entries beimg destroyed if a plugin can't be found at application startup. Given our general direction of working towards more dynamic plugin loading, this might happen more often in the future and we sure don't want to destroy rules etc when we just temporarily miss a plugin. d) tries to fix issue #226 by rotating the DB not only when it fails to open initially, but also when it fails to insert new entries.
3222 lines
147 KiB
C++
3222 lines
147 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"
|
|
#include "jsonrpc/jsonhandler.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);
|
|
|
|
inline void verifyRuleError(const QVariant &response, RuleEngine::RuleError error = RuleEngine::RuleErrorNoError) {
|
|
verifyError(response, "ruleError", enumValueName(error));
|
|
}
|
|
inline void verifyDeviceError(const QVariant &response, Device::DeviceError error = Device::DeviceErrorNoError) {
|
|
verifyError(response, "deviceError", enumValueName(error));
|
|
}
|
|
|
|
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)
|
|
{
|
|
enableNotifications({"Devices"});
|
|
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", enumValueName(Types::ValueOperatorLess));
|
|
stateDescriptor.insert("value", 25);
|
|
|
|
// StateEvaluator
|
|
QVariantMap stateEvaluator;
|
|
stateEvaluator.insert("stateDescriptor", stateDescriptor);
|
|
stateEvaluator.insert("operator", enumValueName(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"
|
|
"JsonRpc.debug=true\n"
|
|
"MockDevice.*=true");
|
|
}
|
|
|
|
void TestRules::addRemoveRules_data()
|
|
{
|
|
// RuleAction
|
|
QVariantMap validActionNoParams;
|
|
validActionNoParams.insert("actionTypeId", mockWithoutParamsActionTypeId);
|
|
validActionNoParams.insert("deviceId", m_mockDeviceId);
|
|
|
|
QVariantMap invalidAction;
|
|
invalidAction.insert("actionTypeId", ActionTypeId("f32c7efb-38b6-4576-a496-c75bbb23132f"));
|
|
invalidAction.insert("deviceId", m_mockDeviceId);
|
|
|
|
// RuleExitAction
|
|
QVariantMap validExitActionNoParams;
|
|
validExitActionNoParams.insert("actionTypeId", mockWithoutParamsActionTypeId);
|
|
validExitActionNoParams.insert("deviceId", m_mockDeviceId);
|
|
|
|
QVariantMap invalidExitAction;
|
|
invalidExitAction.insert("actionTypeId", ActionTypeId("f32c7efb-38b6-4576-a496-c75bbb23132f"));
|
|
invalidExitAction.insert("deviceId", m_mockDeviceId);
|
|
|
|
// StateDescriptor
|
|
QVariantMap stateDescriptor;
|
|
stateDescriptor.insert("stateTypeId", mockIntStateTypeId);
|
|
stateDescriptor.insert("deviceId", m_mockDeviceId);
|
|
stateDescriptor.insert("operator", enumValueName(Types::ValueOperatorLess));
|
|
stateDescriptor.insert("value", 20);
|
|
|
|
// StateEvaluator
|
|
QVariantMap validStateEvaluator;
|
|
validStateEvaluator.insert("stateDescriptor", stateDescriptor);
|
|
validStateEvaluator.insert("operator", enumValueName(Types::StateOperatorAnd));
|
|
|
|
QVariantMap invalidStateEvaluator;
|
|
stateDescriptor.remove("deviceId");
|
|
invalidStateEvaluator.insert("stateDescriptor", stateDescriptor);
|
|
|
|
// EventDescriptor
|
|
QVariantMap validEventDescriptor1;
|
|
validEventDescriptor1.insert("eventTypeId", mockEvent1EventTypeId);
|
|
validEventDescriptor1.insert("deviceId", m_mockDeviceId);
|
|
|
|
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", enumValueName(Types::ValueOperatorEquals));
|
|
params.append(param1);
|
|
validEventDescriptor2.insert("paramDescriptors", params);
|
|
|
|
QVariantMap validEventDescriptor3;
|
|
validEventDescriptor3.insert("eventTypeId", mockEvent2EventTypeId);
|
|
validEventDescriptor3.insert("deviceId", m_mockDeviceId);
|
|
|
|
// EventDescriptorList
|
|
QVariantList eventDescriptorList;
|
|
eventDescriptorList.append(validEventDescriptor1);
|
|
eventDescriptorList.append(validEventDescriptor2);
|
|
|
|
QVariantMap invalidEventDescriptor;
|
|
invalidEventDescriptor.insert("eventTypeId", mockEvent1EventTypeId);
|
|
invalidEventDescriptor.insert("deviceId", DeviceId("2c4825c8-dfb9-4ba4-bd0e-1d827d945d41"));
|
|
|
|
// 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", ParamTypeId("7dbf5266-5179-4e09-ac31-631cc63f1d7b"));
|
|
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 invalid 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, invalid rule format") << 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::RuleErrorDeviceNotFound << 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);
|
|
}
|
|
qCDebug(dcTests()) << "Calling with params:" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson());
|
|
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,
|
|
QString("Event descriptor doesn't match:\nExpected: %1\nGot: %2")
|
|
.arg(QString(QJsonDocument::fromVariant(eventDescriptor).toJson()))
|
|
.arg(QString(QJsonDocument::fromVariant(eventDescriptors.first().toMap()).toJson())).toUtf8());
|
|
} 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,
|
|
QString("Actions don't match.\nExpected: %1\nGot: %2")
|
|
.arg(QString(QJsonDocument::fromVariant(actions).toJson()))
|
|
.arg(QString(QJsonDocument::fromVariant(replyActions).toJson()))
|
|
.toUtf8());
|
|
|
|
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);
|
|
|
|
QVariantMap invalidAction;
|
|
invalidAction.insert("actionTypeId", ActionTypeId());
|
|
invalidAction.insert("deviceId", m_mockDeviceId);
|
|
|
|
// RuleExitAction
|
|
QVariantMap validExitActionNoParams;
|
|
validExitActionNoParams.insert("actionTypeId", mockWithoutParamsActionTypeId);
|
|
validExitActionNoParams.insert("deviceId", m_mockDeviceId);
|
|
|
|
QVariantMap invalidExitAction;
|
|
invalidExitAction.insert("actionTypeId", ActionTypeId());
|
|
invalidExitAction.insert("deviceId", m_mockDeviceId);
|
|
|
|
// StateDescriptor
|
|
QVariantMap stateDescriptor;
|
|
stateDescriptor.insert("stateTypeId", mockIntStateTypeId);
|
|
stateDescriptor.insert("deviceId", m_mockDeviceId);
|
|
stateDescriptor.insert("operator", enumValueName(Types::ValueOperatorLess));
|
|
stateDescriptor.insert("value", 20);
|
|
|
|
// StateEvaluator
|
|
QVariantMap validStateEvaluator;
|
|
validStateEvaluator.insert("stateDescriptor", stateDescriptor);
|
|
validStateEvaluator.insert("operator", enumValueName(Types::StateOperatorAnd));
|
|
|
|
QVariantMap invalidStateEvaluator;
|
|
stateDescriptor.remove("deviceId");
|
|
invalidStateEvaluator.insert("stateDescriptor", stateDescriptor);
|
|
|
|
// EventDescriptor
|
|
QVariantMap validEventDescriptor1;
|
|
validEventDescriptor1.insert("eventTypeId", mockEvent1EventTypeId);
|
|
validEventDescriptor1.insert("deviceId", m_mockDeviceId);
|
|
|
|
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", enumValueName(Types::ValueOperatorEquals));
|
|
params.append(param1);
|
|
validEventDescriptor2.insert("paramDescriptors", params);
|
|
|
|
QVariantMap validEventDescriptor3;
|
|
validEventDescriptor3.insert("eventTypeId", mockEvent2EventTypeId);
|
|
validEventDescriptor3.insert("deviceId", m_mockDeviceId);
|
|
|
|
// EventDescriptorList
|
|
QVariantList eventDescriptorList;
|
|
eventDescriptorList.append(validEventDescriptor1);
|
|
eventDescriptorList.append(validEventDescriptor2);
|
|
|
|
QVariantMap invalidEventDescriptor;
|
|
invalidEventDescriptor.insert("eventTypeId", mockEvent1EventTypeId);
|
|
invalidEventDescriptor.insert("deviceId", DeviceId());
|
|
|
|
// 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", ParamTypeId("2c4825c8-dfb9-4ba4-bd0e-1d827d945d41"));
|
|
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);
|
|
QVariantMap eventDescriptor2;
|
|
eventDescriptor2.insert("eventTypeId", mockEvent2EventTypeId);
|
|
eventDescriptor2.insert("deviceId", m_mockDeviceId);
|
|
QVariantMap eventParam1;
|
|
eventParam1.insert("paramTypeId", mockEvent2EventIntParamParamTypeId);
|
|
eventParam1.insert("value", 3);
|
|
eventParam1.insert("operator", enumValueName(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", enumValueName(Types::ValueOperatorEquals));
|
|
stateDescriptor1.insert("stateTypeId", mockIntStateTypeId);
|
|
stateDescriptor1.insert("value", 1);
|
|
QVariantMap stateDescriptor2;
|
|
stateDescriptor2.insert("deviceId", m_mockDeviceId);
|
|
stateDescriptor2.insert("operator", enumValueName(Types::ValueOperatorEquals));
|
|
stateDescriptor2.insert("stateTypeId", mockBoolStateTypeId);
|
|
stateDescriptor2.insert("value", true);
|
|
QVariantMap stateEvaluator1;
|
|
stateEvaluator1.insert("stateDescriptor", stateDescriptor1);
|
|
stateEvaluator1.insert("operator", enumValueName(Types::StateOperatorAnd));
|
|
QVariantMap stateEvaluator2;
|
|
stateEvaluator2.insert("stateDescriptor", stateDescriptor2);
|
|
stateEvaluator2.insert("operator", enumValueName(Types::StateOperatorAnd));
|
|
QVariantList childEvaluators;
|
|
childEvaluators.append(stateEvaluator1);
|
|
childEvaluators.append(stateEvaluator2);
|
|
stateEvaluator0.insert("childEvaluators", childEvaluators);
|
|
stateEvaluator0.insert("operator", enumValueName(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
|
|
enableNotifications({"Rules"});
|
|
|
|
// 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,
|
|
QString("Event descriptor doesn't match.\nExpected:%1\nGot:%2")
|
|
.arg(QString(QJsonDocument::fromVariant(eventDescriptor).toJson()))
|
|
.arg(QString(QJsonDocument::fromVariant(eventDescriptors.first().toMap()).toJson())).toUtf8());
|
|
} 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,
|
|
QString("Actions don't match.\nExpected: %1\nGot: %2")
|
|
.arg(QString(QJsonDocument::fromVariant(actions).toJson()))
|
|
.arg(QString(QJsonDocument::fromVariant(replyActions).toJson()))
|
|
.toUtf8());
|
|
|
|
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().toUuid().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);
|
|
|
|
QVariantMap eventDescriptor2;
|
|
eventDescriptor2.insert("eventTypeId", mockEvent2EventTypeId);
|
|
eventDescriptor2.insert("deviceId", m_mockDeviceId);
|
|
QVariantList eventParamDescriptors;
|
|
QVariantMap eventParam1;
|
|
eventParam1.insert("paramTypeId", mockEvent2EventIntParamParamTypeId);
|
|
eventParam1.insert("value", 3);
|
|
eventParam1.insert("operator", enumValueName(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", enumValueName(Types::ValueOperatorEquals));
|
|
stateDescriptor2.insert("stateTypeId", mockIntStateTypeId);
|
|
stateDescriptor2.insert("value", 1);
|
|
QVariantMap stateEvaluator2;
|
|
stateEvaluator2.insert("stateDescriptor", stateDescriptor2);
|
|
stateEvaluator2.insert("operator", enumValueName(Types::StateOperatorAnd));
|
|
|
|
QVariantMap stateDescriptor3;
|
|
stateDescriptor3.insert("deviceId", m_mockDeviceId);
|
|
stateDescriptor3.insert("operator", enumValueName(Types::ValueOperatorEquals));
|
|
stateDescriptor3.insert("stateTypeId", mockBoolStateTypeId);
|
|
stateDescriptor3.insert("value", true);
|
|
|
|
QVariantMap stateEvaluator3;
|
|
stateEvaluator3.insert("stateDescriptor", stateDescriptor3);
|
|
stateEvaluator3.insert("operator", enumValueName(Types::StateOperatorAnd));
|
|
|
|
QVariantMap stateDescriptor4;
|
|
stateDescriptor4.insert("interface", "battery");
|
|
stateDescriptor4.insert("interfaceState", "batteryCritical");
|
|
stateDescriptor4.insert("operator", enumValueName(Types::ValueOperatorEquals));
|
|
stateDescriptor4.insert("value", true);
|
|
|
|
QVariantMap stateEvaluator4;
|
|
stateEvaluator4.insert("stateDescriptor", stateDescriptor4);
|
|
stateEvaluator4.insert("operator", enumValueName(Types::StateOperatorAnd));
|
|
|
|
childEvaluators.append(stateEvaluator2);
|
|
childEvaluators.append(stateEvaluator3);
|
|
childEvaluators.append(stateEvaluator4);
|
|
stateEvaluator1.insert("childEvaluators", childEvaluators);
|
|
stateEvaluator1.insert("operator", enumValueName(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);
|
|
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,
|
|
QString("EventDescriptor doesn't match.\nExpected: %1\nGot: %2")
|
|
.arg(QString(QJsonDocument::fromVariant(expectedEventDescriptorVariant).toJson()))
|
|
.arg(QString(QJsonDocument::fromVariant(replyEventDescriptorVariant).toJson()))
|
|
.toUtf8());
|
|
}
|
|
}
|
|
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", enumValueName(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({"Rules"});
|
|
|
|
// 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", enumValueName(Types::ValueOperatorGreaterOrEqual));
|
|
stateDescriptorPercentage.insert("stateTypeId", mockDisplayPinPercentageStateTypeId);
|
|
stateDescriptorPercentage.insert("value", 50);
|
|
|
|
QVariantMap stateDescriptorDouble;
|
|
stateDescriptorDouble.insert("deviceId", testDeviceId);
|
|
stateDescriptorDouble.insert("operator", enumValueName(Types::ValueOperatorEquals));
|
|
stateDescriptorDouble.insert("stateTypeId", mockDisplayPinDoubleActionDoubleParamTypeId);
|
|
stateDescriptorDouble.insert("value", 20.5);
|
|
|
|
QVariantMap stateDescriptorAllowedValues;
|
|
stateDescriptorAllowedValues.insert("deviceId", testDeviceId);
|
|
stateDescriptorAllowedValues.insert("operator", enumValueName(Types::ValueOperatorEquals));
|
|
stateDescriptorAllowedValues.insert("stateTypeId", mockDisplayPinAllowedValuesStateTypeId);
|
|
stateDescriptorAllowedValues.insert("value", "String value 2");
|
|
|
|
QVariantMap stateDescriptorColor;
|
|
stateDescriptorColor.insert("deviceId", testDeviceId);
|
|
stateDescriptorColor.insert("operator", enumValueName(Types::ValueOperatorEquals));
|
|
stateDescriptorColor.insert("stateTypeId", mockDisplayPinColorStateTypeId);
|
|
stateDescriptorColor.insert("value", "#00FF00");
|
|
|
|
QVariantMap firstStateEvaluator;
|
|
firstStateEvaluator.insert("operator", enumValueName(Types::StateOperatorOr));
|
|
firstStateEvaluator.insert("childEvaluators", QVariantList() << createStateEvaluatorFromSingleDescriptor(stateDescriptorPercentage) << createStateEvaluatorFromSingleDescriptor(stateDescriptorDouble));
|
|
|
|
QVariantMap secondStateEvaluator;
|
|
secondStateEvaluator.insert("operator", enumValueName(Types::StateOperatorAnd));
|
|
secondStateEvaluator.insert("childEvaluators", QVariantList() << createStateEvaluatorFromSingleDescriptor(stateDescriptorAllowedValues) << createStateEvaluatorFromSingleDescriptor(stateDescriptorColor));
|
|
|
|
QVariantMap stateEvaluator;
|
|
stateEvaluator.insert("operator", enumValueName(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);
|
|
|
|
LogEngineFetchJob *job = NymeaCore::instance()->logEngine()->logEntries(filter);
|
|
QSignalSpy fetchSpy(job, &LogEngineFetchJob::finished);
|
|
fetchSpy.wait();
|
|
QList<LogEntry> entries = job->results();
|
|
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();
|
|
|
|
job = NymeaCore::instance()->logEngine()->logEntries(filter);
|
|
QSignalSpy fetchSpy2(job, &LogEngineFetchJob::finished);
|
|
fetchSpy2.wait();
|
|
entries = job->results();
|
|
|
|
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);
|
|
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)
|