From 90622e5edbba9b5becea33eec3ede0fc6516776b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Sat, 14 Mar 2015 21:06:39 +0100 Subject: [PATCH] improove RuleAction logic add tests fix documentation --- libguh/types/ruleactionparam.cpp | 32 ++++-- libguh/types/ruleactionparam.h | 12 ++- server/guhcore.cpp | 12 ++- server/jsonrpc/jsonrpcserver.cpp | 2 +- server/jsonrpc/jsontypes.cpp | 9 +- server/jsonrpc/ruleshandler.cpp | 99 +++++++++++++++--- server/jsonrpc/ruleshandler.h | 4 + server/ruleengine.cpp | 7 +- tests/auto/api.json | 3 +- tests/auto/rules/testrules.cpp | 173 +++++++++++++++++++++++++++---- 10 files changed, 294 insertions(+), 59 deletions(-) diff --git a/libguh/types/ruleactionparam.cpp b/libguh/types/ruleactionparam.cpp index b83da7bd..fcee9aec 100644 --- a/libguh/types/ruleactionparam.cpp +++ b/libguh/types/ruleactionparam.cpp @@ -36,16 +36,18 @@ RuleActionParam::RuleActionParam(const Param ¶m) : m_name(param.name()), m_value(param.value()), - m_eventTypeId(EventTypeId()) + m_eventTypeId(EventTypeId()), + m_eventParamName(QString()) { } -/*! Constructs a \l{RuleActionParam} with the given \a name, \a value and \a eventTypeId. +/*! Constructs a \l{RuleActionParam} with the given \a name, \a value, \a eventTypeId and \a eventParamName. * \sa Param, Event, */ -RuleActionParam::RuleActionParam(const QString &name, const QVariant &value, const EventTypeId &eventTypeId) : +RuleActionParam::RuleActionParam(const QString &name, const QVariant &value, const EventTypeId &eventTypeId, const QString &eventParamName) : m_name(name), m_value(value), - m_eventTypeId(eventTypeId) + m_eventTypeId(eventTypeId), + m_eventParamName(eventParamName) { } @@ -61,6 +63,18 @@ void RuleActionParam::setName(const QString &name) m_name = name; } +/*! Returns the name of the eventParam for this RuleActionParam. */ +QString RuleActionParam::eventParamName() const +{ + return m_eventParamName; +} + +/*! Sets the \a eventParamName of this RuleActionParam. */ +void RuleActionParam::setEventParamName(const QString &eventParamName) +{ + m_eventParamName = eventParamName; +} + /*! Returns the value of this RuleActionParam. */ QVariant RuleActionParam::value() const { @@ -73,10 +87,12 @@ void RuleActionParam::setValue(const QVariant &value) m_value = value; } -/*! Returns true if the name and the value of this RuleActionParam are set.*/ +/*! Returns true if the name and value or the name, eventTypeId and eventParamName of this RuleActionParam are set.*/ bool RuleActionParam::isValid() const { - return !m_name.isEmpty() && m_value.isValid(); + bool validValue = (!m_name.isEmpty() && m_value.isValid() && m_eventTypeId == EventTypeId() && m_eventParamName.isEmpty()); + bool validEvent = (!m_name.isEmpty() && m_eventTypeId != EventTypeId() && !m_eventParamName.isEmpty() && !m_value.isValid()); + return validValue ^ validEvent; } /*! Return the EventTypeId of the \l{Event} with the \l{Param} which will be taken over in the \l{RuleAction}. */ @@ -91,10 +107,10 @@ void RuleActionParam::setEventTypeId(const EventTypeId &eventTypeId) m_eventTypeId = eventTypeId; } -/*! Writes the name, value and eventId of the given \a ruleActionParam to \a dbg. */ +/*! Writes the name, value, eventId and eventParamName of the given \a ruleActionParam to \a dbg. */ QDebug operator<<(QDebug dbg, const RuleActionParam &ruleActionParam) { - dbg.nospace() << "RuleActionParam(Name: " << ruleActionParam.name() << ", Value:" << ruleActionParam.value() << ", EventTypeId:" << ruleActionParam.eventTypeId().toString() << ")"; + dbg.nospace() << "RuleActionParam(Name: " << ruleActionParam.name() << ", Value:" << ruleActionParam.value() << ", EventTypeId:" << ruleActionParam.eventTypeId().toString() << ", EventParamName:" << ruleActionParam.eventParamName() << ")"; return dbg.space(); } diff --git a/libguh/types/ruleactionparam.h b/libguh/types/ruleactionparam.h index 730f6bb5..19ddc079 100644 --- a/libguh/types/ruleactionparam.h +++ b/libguh/types/ruleactionparam.h @@ -26,15 +26,18 @@ #include "param.h" #include "typeutils.h" -class RuleActionParam : public Param +class RuleActionParam { public: RuleActionParam(const Param ¶m); - RuleActionParam(const QString &name = QString(), const QVariant &value = QVariant(), const EventTypeId &eventTypeId = EventTypeId()); + RuleActionParam(const QString &name = QString(), const QVariant &value = QVariant(), const EventTypeId &eventTypeId = EventTypeId(), const QString &eventParamName = QString()); QString name() const; void setName(const QString &name); + QString eventParamName() const; + void setEventParamName(const QString &eventParamName); + QVariant value() const; void setValue(const QVariant &value); @@ -47,11 +50,12 @@ private: QString m_name; QVariant m_value; EventTypeId m_eventTypeId; + QString m_eventParamName; }; -Q_DECLARE_METATYPE(RuleActionParam) -QDebug operator<<(QDebug dbg, const RuleActionParam &ruleActionParams); +Q_DECLARE_METATYPE(RuleActionParam) +QDebug operator<<(QDebug dbg, const RuleActionParam &ruleActionParam); class RuleActionParamList: public QList { diff --git a/server/guhcore.cpp b/server/guhcore.cpp index bd52fb76..33c9ce03 100644 --- a/server/guhcore.cpp +++ b/server/guhcore.cpp @@ -396,18 +396,24 @@ void GuhCore::gotEvent(const Event &event) } } - // Convert event based RuleActions to normal action, depending on the event value - foreach (const RuleAction &ruleAction, eventBasedActions) { + // Set action params, depending on the event value + foreach (RuleAction ruleAction, eventBasedActions) { + RuleActionParamList newParams; foreach (RuleActionParam ruleActionParam, ruleAction.ruleActionParams()) { // if this event param should be taken over in this action if (event.eventTypeId() == ruleActionParam.eventTypeId()) { - QVariant eventValue = event.param(ruleActionParam.name()).value(); + QVariant eventValue = event.params().first().value(); + + // TODO: get param names... // TODO: limits / scale calculation -> actionValue = eventValue * x ruleActionParam.setValue(eventValue); + qDebug() << ruleActionParam.value(); } + newParams.append(ruleActionParam); } + ruleAction.setRuleActionParams(newParams); actions.append(ruleAction); } diff --git a/server/jsonrpc/jsonrpcserver.cpp b/server/jsonrpc/jsonrpcserver.cpp index 1c3ab8f0..840d24ff 100644 --- a/server/jsonrpc/jsonrpcserver.cpp +++ b/server/jsonrpc/jsonrpcserver.cpp @@ -44,7 +44,7 @@ #include #include -#define JSON_PROTOCOL_VERSION 17 +#define JSON_PROTOCOL_VERSION 18 JsonRPCServer::JsonRPCServer(QObject *parent): JsonHandler(parent), diff --git a/server/jsonrpc/jsontypes.cpp b/server/jsonrpc/jsontypes.cpp index 6aead8f6..f07ddd12 100644 --- a/server/jsonrpc/jsontypes.cpp +++ b/server/jsonrpc/jsontypes.cpp @@ -105,6 +105,7 @@ void JsonTypes::init() s_ruleActionParam.insert("name", basicTypeToString(String)); s_ruleActionParam.insert("o:value", basicTypeRef()); s_ruleActionParam.insert("o:eventTypeId", basicTypeToString(Uuid)); + s_ruleActionParam.insert("o:eventParamName", basicTypeToString(String)); // ParamDescriptor s_paramDescriptor.insert("name", basicTypeToString(String)); @@ -355,10 +356,10 @@ QVariantMap JsonTypes::packRuleActionParam(const RuleActionParam &ruleActionPara { QVariantMap variantMap; variantMap.insert("name", ruleActionParam.name()); - // if this ruleaction param has a valid EventTypeId, there is no value if (ruleActionParam.eventTypeId() != EventTypeId()) { variantMap.insert("eventTypeId", ruleActionParam.eventTypeId()); + variantMap.insert("eventParamName", ruleActionParam.eventParamName()); } else { variantMap.insert("value", ruleActionParam.value()); } @@ -635,10 +636,12 @@ RuleActionParam JsonTypes::unpackRuleActionParam(const QVariantMap &ruleActionPa if (ruleActionParamMap.keys().count() == 0) { return RuleActionParam(); } + QString name = ruleActionParamMap.value("name").toString(); QVariant value = ruleActionParamMap.value("value"); - EventTypeId eventTypeId(ruleActionParamMap.value("eventTypeId").toString()); - return RuleActionParam(name, value, eventTypeId); + EventTypeId eventTypeId = EventTypeId(ruleActionParamMap.value("eventTypeId").toString()); + QString eventParamName = ruleActionParamMap.value("eventParamName").toString(); + return RuleActionParam(name, value, eventTypeId, eventParamName); } RuleActionParamList JsonTypes::unpackRuleActionParams(const QVariantList &ruleActionParamList) diff --git a/server/jsonrpc/ruleshandler.cpp b/server/jsonrpc/ruleshandler.cpp index 73c7e19e..f3785392 100644 --- a/server/jsonrpc/ruleshandler.cpp +++ b/server/jsonrpc/ruleshandler.cpp @@ -133,7 +133,7 @@ JsonReply* RulesHandler::AddRule(const QVariantMap ¶ms) if (params.contains("eventDescriptor") || params.contains("eventDescriptorList")) { if (params.contains("exitActions")) { QVariantMap returns; - qWarning() << "The exitActions will never executed if this rule contains any eventDescriptor."; + qWarning() << "The exitActions will never be executed if the rule contains any eventDescriptor."; returns.insert("ruleError", JsonTypes::ruleErrorToString(RuleEngine::RuleErrorInvalidRuleFormat)); return createReply(returns); } @@ -156,11 +156,23 @@ JsonReply* RulesHandler::AddRule(const QVariantMap ¶ms) QList actions; QVariantList actionList = params.value("actions").toList(); + qDebug() << "unpacking actions:" << actionList; foreach (const QVariant &actionVariant, actionList) { QVariantMap actionMap = actionVariant.toMap(); RuleAction action(ActionTypeId(actionMap.value("actionTypeId").toString()), DeviceId(actionMap.value("deviceId").toString())); - qDebug() << "params from json" << actionMap.value("ruleActionParams"); - action.setRuleActionParams(JsonTypes::unpackRuleActionParams(actionMap.value("ruleActionParams").toList())); + qDebug() << "actionParams from json" << actionMap.value("ruleActionParams"); + RuleActionParamList actionParamList = JsonTypes::unpackRuleActionParams(actionMap.value("ruleActionParams").toList()); + qDebug() << "unpacked actionParamList:" << actionParamList; + foreach (const RuleActionParam &ruleActionParam, actionParamList) { + if (!ruleActionParam.isValid()) { + qWarning() << "ERROR: got actionParam with value AND eventTypeId!"; + QVariantMap returns; + returns.insert("ruleError", JsonTypes::ruleErrorToString(RuleEngine::RuleErrorInvalidRuleActionParameter)); + return createReply(returns); + } + } + + action.setRuleActionParams(actionParamList); qDebug() << "params in action" << action.ruleActionParams(); actions.append(action); } @@ -174,21 +186,25 @@ JsonReply* RulesHandler::AddRule(const QVariantMap ¶ms) if (eventDescriptorList.isEmpty()) { QVariantMap returns; qWarning() << "RuleAction" << ruleAction.actionTypeId() << "contains an eventTypeId, but there are no eventDescriptors."; - returns.insert("ruleErorr", JsonTypes::ruleErrorToString(RuleEngine::RuleErrorInvalidRuleActionParameter)); + returns.insert("ruleError", JsonTypes::ruleErrorToString(RuleEngine::RuleErrorInvalidRuleActionParameter)); return createReply(returns); } // now check if this eventType is in the eventDescriptorList of this rule - foreach (const EventDescriptor eventDescriptor, eventDescriptorList) { - if (eventDescriptor.eventTypeId() == ruleActionParam.eventTypeId()) { - // TODO: check if they match - continue; - } else { - // the given eventTypeId is not in the eventDescriptorList - QVariantMap returns; - qWarning() << "eventTypeId from RuleAction" << ruleAction.actionTypeId() << "missing in eventDescriptors."; - returns.insert("ruleErorr", JsonTypes::ruleErrorToString(RuleEngine::RuleErrorInvalidRuleActionParameter)); - return createReply(returns); - } + if (!checkEventDescriptors(eventDescriptorList, ruleActionParam.eventTypeId())) { + QVariantMap returns; + qWarning() << "eventTypeId from RuleAction" << ruleAction.actionTypeId() << "missing in eventDescriptors."; + returns.insert("ruleError", JsonTypes::ruleErrorToString(RuleEngine::RuleErrorInvalidRuleActionParameter)); + return createReply(returns); + } + + // check if the param type of the event and the action match + QVariant::Type eventParamType = getEventParamType(ruleActionParam.eventTypeId(), ruleActionParam.eventParamName()); + QVariant::Type actionParamType = getActionParamType(ruleAction.actionTypeId(), ruleActionParam.name()); + if (eventParamType != actionParamType) { + QVariantMap returns; + qWarning() << "RuleActionParam" << ruleActionParam.name() << " and given event param have not the same type."; + returns.insert("ruleError", JsonTypes::ruleErrorToString(RuleEngine::RuleErrorInvalidRuleActionParameter)); + return createReply(returns); } } } @@ -198,7 +214,7 @@ JsonReply* RulesHandler::AddRule(const QVariantMap ¶ms) QVariantMap returns; if (actions.count() == 0) { - returns.insert("ruleErorr", JsonTypes::ruleErrorToString(RuleEngine::RuleErrorMissingParameter)); + returns.insert("ruleError", JsonTypes::ruleErrorToString(RuleEngine::RuleErrorMissingParameter)); return createReply(returns); } @@ -208,7 +224,13 @@ JsonReply* RulesHandler::AddRule(const QVariantMap ¶ms) foreach (const QVariant &actionVariant, exitActionList) { QVariantMap actionMap = actionVariant.toMap(); RuleAction action(ActionTypeId(actionMap.value("actionTypeId").toString()), DeviceId(actionMap.value("deviceId").toString())); - qDebug() << "params from json" << actionMap.value("ruleActionParams"); + qDebug() << "params from json" << actionMap.value("ruleActionParams"); + if (action.isEventBased()) { + qWarning() << "ERROR: got exitAction with a param value containing an eventTypeId!"; + QVariantMap returns; + returns.insert("ruleError", JsonTypes::ruleErrorToString(RuleEngine::RuleErrorInvalidRuleActionParameter)); + return createReply(returns); + } action.setRuleActionParams(JsonTypes::unpackRuleActionParams(actionMap.value("ruleActionParams").toList())); qDebug() << "params in action" << action.ruleActionParams(); exitActions.append(action); @@ -261,3 +283,46 @@ JsonReply *RulesHandler::DisableRule(const QVariantMap ¶ms) { return createReply(statusToReply(GuhCore::instance()->disableRule(RuleId(params.value("ruleId").toString())))); } + +QVariant::Type RulesHandler::getActionParamType(const ActionTypeId &actionTypeId, const QString ¶mName) +{ + foreach (const DeviceClass &deviceClass, GuhCore::instance()->supportedDevices()) { + foreach (const ActionType &actionType, deviceClass.actionTypes()) { + if (actionType.id() == actionTypeId) { + foreach (const ParamType ¶mType, actionType.paramTypes()) { + if (paramType.name() == paramName) { + return paramType.type(); + } + } + } + } + } + return QVariant::Invalid; +} + +QVariant::Type RulesHandler::getEventParamType(const EventTypeId &eventTypeId, const QString ¶mName) +{ + foreach (const DeviceClass &deviceClass, GuhCore::instance()->supportedDevices()) { + foreach (const EventType &eventType, deviceClass.eventTypes()) { + if (eventType.id() == eventTypeId) { + foreach (const ParamType ¶mType, eventType.paramTypes()) { + // get ParamType of Event + if (paramType.name() == paramName) { + return paramType.type(); + } + } + } + } + } + return QVariant::Invalid; +} + +bool RulesHandler::checkEventDescriptors(const QList eventDescriptors, const EventTypeId &eventTypeId) +{ + foreach (const EventDescriptor eventDescriptor, eventDescriptors) { + if (eventDescriptor.eventTypeId() == eventTypeId) { + return true; + } + } + return false; +} diff --git a/server/jsonrpc/ruleshandler.h b/server/jsonrpc/ruleshandler.h index 81002723..ce5853bb 100644 --- a/server/jsonrpc/ruleshandler.h +++ b/server/jsonrpc/ruleshandler.h @@ -39,6 +39,10 @@ public: Q_INVOKABLE JsonReply* EnableRule(const QVariantMap ¶ms); Q_INVOKABLE JsonReply* DisableRule(const QVariantMap ¶ms); +private: + QVariant::Type getActionParamType(const ActionTypeId &actionTypeId, const QString ¶mName); + QVariant::Type getEventParamType(const EventTypeId &eventTypeId, const QString ¶mName); + bool checkEventDescriptors(const QList eventDescriptors, const EventTypeId &eventTypeId); }; #endif // RULESHANDLER_H diff --git a/server/ruleengine.cpp b/server/ruleengine.cpp index b431fec6..0733980c 100644 --- a/server/ruleengine.cpp +++ b/server/ruleengine.cpp @@ -141,7 +141,7 @@ RuleEngine::RuleEngine(QObject *parent) : foreach (QString paramNameString, settings.childGroups()) { if (paramNameString.startsWith("RuleActionParam-")) { settings.beginGroup(paramNameString); - RuleActionParam param(paramNameString.remove(QRegExp("^RuleActionParam-")), settings.value("value",QVariant()), EventTypeId(settings.value("eventTypeId", EventTypeId()).toString())); + RuleActionParam param(paramNameString.remove(QRegExp("^RuleActionParam-")), settings.value("value",QVariant()), EventTypeId(settings.value("eventTypeId", EventTypeId()).toString()), settings.value("eventParamName", QString()).toString()); params.append(param); settings.endGroup(); } @@ -326,6 +326,7 @@ RuleEngine::RuleError RuleEngine::addRule(const RuleId &ruleId, const QString &n appendRule(rule); emit ruleAdded(rule.id()); + // Save Events / EventDescriptors QSettings settings(m_settingsFile); settings.beginGroup(rule.id().toString()); settings.setValue("name", name); @@ -347,8 +348,10 @@ RuleEngine::RuleError RuleEngine::addRule(const RuleId &ruleId, const QString &n } settings.endGroup(); + // Save StateEvaluator stateEvaluator.dumpToSettings(settings, "stateEvaluator"); + // Save ruleActions settings.beginGroup("ruleActions"); foreach (const RuleAction &action, rule.actions()) { settings.beginGroup(action.actionTypeId().toString()); @@ -357,6 +360,7 @@ RuleEngine::RuleError RuleEngine::addRule(const RuleId &ruleId, const QString &n foreach (const RuleActionParam ¶m, action.ruleActionParams()) { settings.beginGroup("RuleActionParam-" + param.name()); settings.setValue("eventTypeId", param.eventTypeId()); + settings.setValue("eventParamName", param.eventParamName()); settings.setValue("value", param.value()); settings.endGroup(); } @@ -365,6 +369,7 @@ RuleEngine::RuleError RuleEngine::addRule(const RuleId &ruleId, const QString &n settings.endGroup(); + // Save ruleExitActions settings.beginGroup("ruleExitActions"); foreach (const RuleAction &action, rule.exitActions()) { settings.beginGroup(action.actionTypeId().toString()); diff --git a/tests/auto/api.json b/tests/auto/api.json index 371bb789..284ddfc0 100644 --- a/tests/auto/api.json +++ b/tests/auto/api.json @@ -1,4 +1,4 @@ -17 +18 { "methods": { "Actions.ExecuteAction": { @@ -594,6 +594,7 @@ }, "RuleActionParam": { "name": "String", + "o:eventParamName": "String", "o:eventTypeId": "Uuid", "o:value": "$ref:BasicType" }, diff --git a/tests/auto/rules/testrules.cpp b/tests/auto/rules/testrules.cpp index 2d16c829..3d8abcef 100644 --- a/tests/auto/rules/testrules.cpp +++ b/tests/auto/rules/testrules.cpp @@ -123,6 +123,7 @@ void TestRules::verifyRuleNotExecuted() void TestRules::addRemoveRules_data() { + // RuleAction QVariantMap validActionNoParams; validActionNoParams.insert("actionTypeId", mockActionIdNoParams); validActionNoParams.insert("deviceId", m_mockDeviceId); @@ -133,6 +134,7 @@ void TestRules::addRemoveRules_data() invalidAction.insert("deviceId", m_mockDeviceId); invalidAction.insert("ruleActionParams", QVariantList()); + // RuleExitAction QVariantMap validExitActionNoParams; validExitActionNoParams.insert("actionTypeId", mockActionIdNoParams); validExitActionNoParams.insert("deviceId", m_mockDeviceId); @@ -143,12 +145,14 @@ void TestRules::addRemoveRules_data() invalidExitAction.insert("deviceId", m_mockDeviceId); invalidExitAction.insert("ruleActionParams", QVariantList()); + // StateDescriptor QVariantMap stateDescriptor; stateDescriptor.insert("stateTypeId", mockIntStateId); stateDescriptor.insert("deviceId", m_mockDeviceId); stateDescriptor.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorLess)); stateDescriptor.insert("value", "20"); + // StateEvaluator QVariantMap validStateEvaluator; validStateEvaluator.insert("stateDescriptor", stateDescriptor); validStateEvaluator.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd)); @@ -157,6 +161,7 @@ void TestRules::addRemoveRules_data() stateDescriptor.remove("deviceId"); invalidStateEvaluator.insert("stateDescriptor", stateDescriptor); + // EventDescriptor QVariantMap validEventDescriptor1; validEventDescriptor1.insert("eventTypeId", mockEvent1Id); validEventDescriptor1.insert("deviceId", m_mockDeviceId); @@ -173,6 +178,13 @@ void TestRules::addRemoveRules_data() params.append(param1); validEventDescriptor2.insert("paramDescriptors", params); + QVariantMap validEventDescriptor3; + validEventDescriptor3.insert("eventTypeId", mockEvent2Id); + validEventDescriptor3.insert("deviceId", m_mockDeviceId); + validEventDescriptor3.insert("paramDescriptors", QVariantList()); + + + // EventDescriptorList QVariantList eventDescriptorList; eventDescriptorList.append(validEventDescriptor1); eventDescriptorList.append(validEventDescriptor2); @@ -182,6 +194,39 @@ void TestRules::addRemoveRules_data() invalidEventDescriptor.insert("deviceId", DeviceId()); invalidEventDescriptor.insert("paramDescriptors", QVariantList()); + // RuleAction event based + QVariantMap validActionEventBased; + validActionEventBased.insert("actionTypeId", mockActionIdWithParams); + validActionEventBased.insert("deviceId", m_mockDeviceId); + QVariantMap validActionEventBasedParam1; + validActionEventBasedParam1.insert("name", "mockActionParam1"); + validActionEventBasedParam1.insert("eventTypeId", mockEvent2Id); + validActionEventBasedParam1.insert("eventParamName", "mockParamInt"); + QVariantMap validActionEventBasedParam2; + validActionEventBasedParam2.insert("name", "mockActionParam2"); + validActionEventBasedParam2.insert("value", false); + validActionEventBased.insert("ruleActionParams", QVariantList() << validActionEventBasedParam1 << validActionEventBasedParam2); + + QVariantMap invalidActionEventBased; + invalidActionEventBased.insert("actionTypeId", mockActionIdNoParams); + invalidActionEventBased.insert("deviceId", m_mockDeviceId); + validActionEventBasedParam1.insert("value", 10); + invalidActionEventBased.insert("ruleActionParams", QVariantList() << validActionEventBasedParam1); + + QVariantMap invalidActionEventBased2; + invalidActionEventBased2.insert("actionTypeId", mockActionIdWithParams); + invalidActionEventBased2.insert("deviceId", m_mockDeviceId); + QVariantMap invalidActionEventBasedParam2; + invalidActionEventBasedParam2.insert("name", "mockActionParam1"); + invalidActionEventBasedParam2.insert("eventTypeId", mockEvent1Id); + invalidActionEventBasedParam2.insert("eventParamName", "value"); + QVariantMap invalidActionEventBasedParam3; + invalidActionEventBasedParam3.insert("name", "mockActionParam2"); + invalidActionEventBasedParam3.insert("value", 2); + invalidActionEventBased2.insert("ruleActionParams", QVariantList() << invalidActionEventBasedParam2 << invalidActionEventBasedParam3); + + + QTest::addColumn("enabled"); QTest::addColumn("action1"); QTest::addColumn("exitAction1"); @@ -192,20 +237,29 @@ void TestRules::addRemoveRules_data() QTest::addColumn("jsonError"); QTest::addColumn("name"); - QTest::newRow("valid rule. enabled, 1 Action, 1 Exit Action, 1 StateEvaluator, name") << true << validActionNoParams << validExitActionNoParams << QVariantMap() << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorNoError << false << "TestRule"; - QTest::newRow("valid rule. disabled, 1 Action, 1 Exit Action, 1 StateEvaluator, name") << false << validActionNoParams << validExitActionNoParams << QVariantMap() << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorNoError << false << "TestRule"; - QTest::newRow("valid rule. disabled, 1 Action, 1 invalid Exit Action, 1 StateEvaluator, name") << false << validActionNoParams << invalidExitAction << QVariantMap() << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorActionTypeNotFound << false << "TestRule"; - QTest::newRow("invalid rule. 1 Action, 1 Exit Action, 1 EventDescriptor, 1 StateEvaluator, name") << true << validActionNoParams << validExitActionNoParams << validEventDescriptor1 << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorInvalidRuleFormat << false << "TestRule"; - QTest::newRow("invalid rule. 1 Action, 1 Exit Action, eventDescriptorList, 1 StateEvaluator, name") << true << validActionNoParams << validExitActionNoParams << QVariantMap() << eventDescriptorList << validStateEvaluator << RuleEngine::RuleErrorInvalidRuleFormat << false << "TestRule"; + // 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), 1 EventDescriptor, name") << true << invalidActionEventBased << QVariantMap() << validEventDescriptor2 << QVariantList() << QVariantMap() << RuleEngine::RuleErrorInvalidRuleActionParameter << false << "TestRule"; + QTest::newRow("invalid rule. enabled, 1 Action (eventBased), 1 StateEvaluator, name") << true << validActionEventBased << QVariantMap() << QVariantMap() << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorInvalidRuleActionParameter << false << "TestRule"; + QTest::newRow("invalid rule. enabled, 1 Action (eventBased), 1 EventDescriptor, name") << true << validActionEventBased << validActionEventBased << validEventDescriptor2 << QVariantList() << QVariantMap() << RuleEngine::RuleErrorInvalidRuleFormat << false << "TestRule"; + QTest::newRow("invalid rule. enabled, 1 Action, 1 ExitAction (EventBased), name") << true << validActionNoParams << validActionEventBased << validEventDescriptor2 << QVariantList() << QVariantMap() << RuleEngine::RuleErrorInvalidRuleFormat << false << "TestRule"; + // Rules with exit actions + QTest::newRow("valid rule. enabled, 1 Action, 1 Exit Action, 1 StateEvaluator, name") << true << validActionNoParams << validExitActionNoParams << QVariantMap() << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorNoError << true << "TestRule"; + QTest::newRow("valid rule. disabled, 1 Action, 1 Exit Action, 1 StateEvaluator, name") << false << validActionNoParams << validExitActionNoParams << QVariantMap() << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorNoError << true << "TestRule"; + QTest::newRow("invalid rule. disabled, 1 Action, 1 invalid Exit Action, 1 StateEvaluator, name") << false << validActionNoParams << invalidExitAction << QVariantMap() << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorActionTypeNotFound << false << "TestRule"; + QTest::newRow("invalid rule. 1 Action, 1 Exit Action, 1 EventDescriptor, 1 StateEvaluator, name") << true << validActionNoParams << validExitActionNoParams << validEventDescriptor1 << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorInvalidRuleFormat << false << "TestRule"; + QTest::newRow("invalid rule. 1 Action, 1 Exit Action, eventDescriptorList, 1 StateEvaluator, name") << true << validActionNoParams << validExitActionNoParams << QVariantMap() << eventDescriptorList << validStateEvaluator << RuleEngine::RuleErrorInvalidRuleFormat << false << "TestRule"; - QTest::newRow("valid rule. enabled, 1 EventDescriptor, StateEvaluator, 1 Action, name") << true << validActionNoParams << QVariantMap() << validEventDescriptor1 << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorNoError << false << "TestRule"; - QTest::newRow("valid rule. diabled, 1 EventDescriptor, StateEvaluator, 1 Action, name") << false << validActionNoParams << QVariantMap() << validEventDescriptor1 << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorNoError << false << "TestRule"; - QTest::newRow("valid rule. 2 EventDescriptors, 1 Action, name") << true << validActionNoParams << QVariantMap() << QVariantMap() << eventDescriptorList << validStateEvaluator << RuleEngine::RuleErrorNoError << false << "TestRule"; - QTest::newRow("invalid rule: eventDescriptor and eventDescriptorList used") << true << validActionNoParams << QVariantMap() << validEventDescriptor1 << eventDescriptorList << validStateEvaluator << RuleEngine::RuleErrorInvalidParameter << false << "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"; - QTest::newRow("invalid StateDescriptor") << true << validActionNoParams << QVariantMap() << validEventDescriptor1 << QVariantList() << invalidStateEvaluator << RuleEngine::RuleErrorInvalidParameter << true << "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. diabled, 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 rule: eventDescriptor and eventDescriptorList used") << true << validActionNoParams << QVariantMap() << validEventDescriptor1 << eventDescriptorList << validStateEvaluator << RuleEngine::RuleErrorInvalidParameter << false << "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"; + QTest::newRow("invalid StateDescriptor") << true << validActionNoParams << QVariantMap() << validEventDescriptor1 << QVariantList() << invalidStateEvaluator << RuleEngine::RuleErrorInvalidParameter << true << "TestRule"; } void TestRules::addRemoveRules() @@ -380,7 +434,28 @@ void TestRules::loadStoreConfig() action2Params.append(action2Param2); action2.insert("ruleActionParams", action2Params); - // First rule + // RuleAction event based + QVariantMap validActionEventBased; + validActionEventBased.insert("actionTypeId", mockActionIdWithParams); + validActionEventBased.insert("deviceId", m_mockDeviceId); + QVariantMap validActionEventBasedParam1; + validActionEventBasedParam1.insert("name", "mockActionParam1"); + validActionEventBasedParam1.insert("eventTypeId", mockEvent2Id); + validActionEventBasedParam1.insert("eventParamName", "mockParamInt"); + QVariantMap validActionEventBasedParam2; + validActionEventBasedParam2.insert("name", "mockActionParam2"); + validActionEventBasedParam2.insert("value", false); + validActionEventBased.insert("ruleActionParams", QVariantList() << validActionEventBasedParam1 << validActionEventBasedParam2); + + + QVariantList validEventDescriptors3; + QVariantMap validEventDescriptor3; + validEventDescriptor3.insert("eventTypeId", mockEvent2Id); + validEventDescriptor3.insert("deviceId", m_mockDeviceId); + validEventDescriptor3.insert("paramDescriptors", QVariantList()); + validEventDescriptors3.append(validEventDescriptor3); + + // rule 1 QVariantMap params; QVariantList actions; actions.append(action1); @@ -394,7 +469,7 @@ void TestRules::loadStoreConfig() RuleId newRuleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toString()); verifyRuleError(response); - // Second rule + // rule 2 QVariantMap params2; QVariantList actions2; actions2.append(action1); @@ -409,19 +484,33 @@ void TestRules::loadStoreConfig() RuleId newRuleId2 = RuleId(response2.toMap().value("params").toMap().value("ruleId").toString()); verifyRuleError(response2); + // rule 3 + QVariantMap params3; + QVariantList actions3; + actions3.append(validActionEventBased); + params3.insert("actions", actions3); + params3.insert("eventDescriptorList", validEventDescriptors3); + params3.insert("name", "TestRule3"); + QVariant response3 = injectAndWait("Rules.AddRule", params3); + + RuleId newRuleId3 = RuleId(response3.toMap().value("params").toMap().value("ruleId").toString()); + verifyRuleError(response3); + restartServer(); response = injectAndWait("Rules.GetRules"); QVariantList rules = response.toMap().value("params").toMap().value("ruleIds").toList(); - QVERIFY2(rules.count() == 2, "There should be exactly two rule."); + QVERIFY2(rules.count() == 3, "There should be exactly three rule."); QVERIFY2(rules.contains(newRuleId.toString()), "Rule 1 should be in ruleIds list."); QVERIFY2(rules.contains(newRuleId2.toString()), "Rule 2 should be in ruleIds list."); + QVERIFY2(rules.contains(newRuleId3.toString()), "Rule 3 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(); @@ -454,10 +543,6 @@ void TestRules::loadStoreConfig() } QVariantList replyActions = rule1.value("actions").toList(); - qDebug() << "----------------------------------------------"; - qDebug() << rule1; - qDebug() << "----------------------------------------------"; - foreach (const QVariant &actionVariant, actions) { bool found = false; foreach (const QVariant &replyActionVariant, replyActions) { @@ -474,9 +559,10 @@ void TestRules::loadStoreConfig() 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(); @@ -530,16 +616,61 @@ void TestRules::loadStoreConfig() 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 shoud be exactly 1 eventDescriptor"); + QVariantMap eventDescriptor = eventDescriptors3.first().toMap(); + QVERIFY2(eventDescriptor.value("eventTypeId").toString() == mockEvent2Id.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; + QJsonDocument bDoc = QJsonDocument::fromVariant(actionVariant); + QString bString = bDoc.toJson(); + QJsonDocument aDoc = QJsonDocument::fromVariant(replyActionVariant); + QString aString = aDoc.toJson(); + QVERIFY2(actionVariant == replyActionVariant, QString("Action doesn't match after loading from config.\nBefore storing: %1\nAfter storing:%2").arg(bString).arg(aString).toUtf8().data()); + } + } + QVERIFY2(found, "Action not found after loading from config."); + } + + // 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");