From 774452ff7c46e259b3596cf50fe23fb7967e23df Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Tue, 26 Mar 2019 12:21:29 +0100 Subject: [PATCH 1/5] Add support for state based rule action params --- libnymea-core/jsonrpc/jsontypes.cpp | 25 ++- libnymea-core/nymeacore.cpp | 78 +++++++-- libnymea-core/ruleengine.cpp | 239 +++++++++++++++------------ libnymea-core/time/timeeventitem.cpp | 2 +- libnymea-core/time/timeeventitem.h | 2 +- libnymea/types/ruleaction.cpp | 16 +- libnymea/types/ruleaction.h | 1 + libnymea/types/ruleactionparam.cpp | 148 +++++++++++++---- libnymea/types/ruleactionparam.h | 29 +++- tests/auto/rules/testrules.cpp | 95 ++++++++++- 10 files changed, 467 insertions(+), 168 deletions(-) diff --git a/libnymea-core/jsonrpc/jsontypes.cpp b/libnymea-core/jsonrpc/jsontypes.cpp index f8b87dc6..8e1727ac 100644 --- a/libnymea-core/jsonrpc/jsontypes.cpp +++ b/libnymea-core/jsonrpc/jsontypes.cpp @@ -188,6 +188,8 @@ void JsonTypes::init() s_ruleActionParam.insert("o:value", basicTypeRef()); s_ruleActionParam.insert("o:eventTypeId", basicTypeToString(Uuid)); s_ruleActionParam.insert("o:eventParamTypeId", basicTypeToString(Uuid)); + s_ruleActionParam.insert("o:deviceId", basicTypeToString(Uuid)); + s_ruleActionParam.insert("o:stateTypeId", basicTypeToString(Uuid)); // ParamDescriptor s_paramDescriptor.insert("o:paramTypeId", basicTypeToString(Uuid)); @@ -612,10 +614,13 @@ QVariantMap JsonTypes::packRuleActionParam(const RuleActionParam &ruleActionPara } else { variantMap.insert("paramName", ruleActionParam.paramName()); } - // if this ruleaction param has a valid EventTypeId, there is no value - if (ruleActionParam.eventTypeId() != EventTypeId()) { + + if (ruleActionParam.isEventBased()) { variantMap.insert("eventTypeId", ruleActionParam.eventTypeId().toString()); variantMap.insert("eventParamTypeId", ruleActionParam.eventParamTypeId().toString()); + } else if (ruleActionParam.isStateBased()) { + variantMap.insert("deviceId", ruleActionParam.deviceId().toString()); + variantMap.insert("stateTypeId", ruleActionParam.stateTypeId().toString()); } else { variantMap.insert("value", ruleActionParam.value()); } @@ -1429,13 +1434,19 @@ RuleActionParam JsonTypes::unpackRuleActionParam(const QVariantMap &ruleActionPa ParamTypeId paramTypeId = ParamTypeId(ruleActionParamMap.value("paramTypeId").toString()); QString paramName = ruleActionParamMap.value("paramName").toString(); - QVariant value = ruleActionParamMap.value("value"); - EventTypeId eventTypeId = EventTypeId(ruleActionParamMap.value("eventTypeId").toString()); - ParamTypeId eventParamTypeId = ParamTypeId(ruleActionParamMap.value("eventParamTypeId").toString()); + + RuleActionParam param; if (paramTypeId.isNull()) { - return RuleActionParam(paramName, value, eventTypeId, eventParamTypeId); + param = RuleActionParam(paramName); + } else { + param = RuleActionParam(paramTypeId); } - return RuleActionParam(paramTypeId, value, eventTypeId, eventParamTypeId); + param.setValue(ruleActionParamMap.value("value")); + param.setEventTypeId(EventTypeId(ruleActionParamMap.value("eventTypeId").toString())); + param.setEventParamTypeId(ParamTypeId(ruleActionParamMap.value("eventParamTypeId").toString())); + param.setDeviceId(DeviceId(ruleActionParamMap.value("deviceId").toString())); + param.setStateTypeId(StateTypeId(ruleActionParamMap.value("stateTypeId").toString())); + return param; } /*! Returns a \l{RuleActionParamList} created from the given \a ruleActionParamList. */ diff --git a/libnymea-core/nymeacore.cpp b/libnymea-core/nymeacore.cpp index ea9ebff1..e2b402b7 100644 --- a/libnymea-core/nymeacore.cpp +++ b/libnymea-core/nymeacore.cpp @@ -438,31 +438,85 @@ void NymeaCore::executeRuleActions(const QList ruleActions) QList actions; foreach (const RuleAction &ruleAction, ruleActions) { if (ruleAction.type() == RuleAction::TypeDevice) { - actions.append(ruleAction.toAction()); + Device *device = m_deviceManager->findConfiguredDevice(ruleAction.deviceId()); + ActionTypeId actionTypeId = ruleAction.actionTypeId(); + ParamList params; + bool ok = true; + foreach (const RuleActionParam &ruleActionParam, ruleAction.ruleActionParams()) { + if (ruleActionParam.isValueBased()) { + params.append(Param(ruleActionParam.paramTypeId(), ruleActionParam.value())); + } else if (ruleActionParam.isStateBased()) { + Device *stateDevice = m_deviceManager->findConfiguredDevice(ruleActionParam.deviceId()); + if (!stateDevice) { + qCWarning(dcRuleEngine()) << "Cannot find device" << ruleActionParam.deviceId() << "required by rule action" << ruleAction.id(); + ok = false; + break; + } + DeviceClass stateDeviceClass = m_deviceManager->findDeviceClass(stateDevice->deviceClassId()); + if (!stateDeviceClass.hasStateType(ruleActionParam.stateTypeId())) { + qCWarning(dcRuleEngine()) << "Device" << device->name() << device->id() << "does not have a state type" << ruleActionParam.stateTypeId(); + ok = false; + break; + } + params.append(Param(ruleActionParam.paramTypeId(), stateDevice->stateValue(ruleActionParam.stateTypeId()))); + } + } + if (!ok) { + qCWarning(dcRuleEngine()) << "Not executing rule action" << ruleAction.id(); + continue; + } + Action action(actionTypeId, device->id()); + action.setParams(params); + actions.append(action); } else { QList devices = m_deviceManager->findConfiguredDevices(ruleAction.interface()); foreach (Device* device, devices) { - DeviceClass dc = m_deviceManager->findDeviceClass(device->deviceClassId()); - ActionType at = dc.actionTypes().findByName(ruleAction.interfaceAction()); - if (at.id().isNull()) { + DeviceClass deviceClass = m_deviceManager->findDeviceClass(device->deviceClassId()); + ActionType actionType = deviceClass.actionTypes().findByName(ruleAction.interfaceAction()); + if (actionType.id().isNull()) { qCWarning(dcRuleEngine()) << "Error creating Action. The given DeviceClass does not implement action:" << ruleAction.interfaceAction(); continue; } - Action action = Action(at.id(), device->id()); + ParamList params; - foreach (const RuleActionParam &rap, ruleAction.ruleActionParams()) { - ParamType pt = at.paramTypes().findByName(rap.paramName()); - if (pt.id().isNull()) { - qCWarning(dcRuleEngine()) << "Error creating Action. Failed to match interface param type to DeviceClass paramtype."; + bool ok = true; + foreach (const RuleActionParam &ruleActionParam, ruleAction.ruleActionParams()) { + ParamType paramType = actionType.paramTypes().findByName(ruleActionParam.paramName()); + if (paramType.id().isNull()) { + qCWarning(dcRuleEngine()) << "Error creating Action. The given ActionType does not have a parameter:" << ruleActionParam.paramName(); + ok = false; continue; } - params.append(Param(pt.id(), rap.value())); + if (ruleActionParam.isValueBased()) { + params.append(Param(paramType.id(), ruleActionParam.value())); + } else if (ruleActionParam.isStateBased()) { + Device *stateDevice = m_deviceManager->findConfiguredDevice(ruleActionParam.deviceId()); + if (!stateDevice) { + qCWarning(dcRuleEngine()) << "Cannot find device" << ruleActionParam.deviceId() << "required by rule action" << ruleAction.id(); + ok = false; + break; + } + DeviceClass stateDeviceClass = m_deviceManager->findDeviceClass(stateDevice->deviceClassId()); + if (!stateDeviceClass.hasStateType(ruleActionParam.stateTypeId())) { + qCWarning(dcRuleEngine()) << "Device" << device->name() << device->id() << "does not have a state type" << ruleActionParam.stateTypeId(); + ok = false; + break; + } + params.append(Param(paramType.id(), stateDevice->stateValue(ruleActionParam.stateTypeId()))); + } } + if (!ok) { + qCWarning(dcRuleEngine()) << "Not executing rule action" << ruleAction.id(); + continue; + } + + Action action = Action(actionType.id(), device->id()); action.setParams(params); actions.append(action); } } } + foreach (const Action &action, actions) { qCDebug(dcRuleEngine) << "Executing action" << action.actionTypeId() << action.params(); DeviceManager::DeviceError status = executeAction(action); @@ -652,9 +706,7 @@ void NymeaCore::gotEvent(const Event &event) foreach (RuleActionParam ruleActionParam, ruleAction.ruleActionParams()) { // if this event param should be taken over in this action if (event.eventTypeId() == ruleActionParam.eventTypeId()) { - QVariant eventValue = event.params().first().value(); - - // TODO: get param names...when an event has more than one parameter + QVariant eventValue = event.params().paramValue(ruleActionParam.eventParamTypeId()); // TODO: limits / scale calculation -> actionValue = eventValue * x // something like a EventParamDescriptor diff --git a/libnymea-core/ruleengine.cpp b/libnymea-core/ruleengine.cpp index 3edbbe28..dc9b870c 100644 --- a/libnymea-core/ruleengine.cpp +++ b/libnymea-core/ruleengine.cpp @@ -401,55 +401,6 @@ RuleEngine::RuleError RuleEngine::addRule(const Rule &rule, bool fromEdit) return RuleErrorActionTypeNotFound; } - // check possible eventTypeIds in params - if (action.isEventBased()) { - foreach (const RuleActionParam &ruleActionParam, action.ruleActionParams()) { - if (ruleActionParam.eventTypeId() != EventTypeId()) { - // We have an eventTypeId - if (rule.eventDescriptors().isEmpty()) { - qCWarning(dcRuleEngine) << "Cannot create rule. RuleAction" << action.actionTypeId() << "contains an eventTypeId, but there are no eventDescriptors."; - return RuleErrorInvalidRuleActionParameter; - } - - // now check if this eventType is in the eventDescriptorList of this rule - if (!checkEventDescriptors(rule.eventDescriptors(), ruleActionParam.eventTypeId())) { - qCWarning(dcRuleEngine) << "Cannot create rule. EventTypeId from RuleAction" << action.actionTypeId() << "not in eventDescriptors."; - return RuleErrorInvalidRuleActionParameter; - } - - // check if the param type of the event and the action match - QVariant::Type eventParamType = getEventParamType(ruleActionParam.eventTypeId(), ruleActionParam.eventParamTypeId()); - QVariant v(eventParamType); - QVariant::Type actionParamType = getActionParamType(action.actionTypeId(), ruleActionParam.paramTypeId()); - if (eventParamType != actionParamType && !v.canConvert(actionParamType)) { - qCWarning(dcRuleEngine) << "Cannot create rule. RuleActionParam" << ruleActionParam.paramTypeId().toString() << " and given event param " << ruleActionParam.eventParamTypeId().toString() << "have not the same type:"; - qCWarning(dcRuleEngine) << " -> actionParamType:" << actionParamType; - qCWarning(dcRuleEngine) << " -> eventParamType:" << eventParamType; - return RuleErrorTypesNotMatching; - } - } - } - } else { - // verify action params - foreach (const ActionType &actionType, deviceClass.actionTypes()) { - if (actionType.id() == action.actionTypeId()) { - ParamList finalParams = action.toAction().params(); - DeviceManager::DeviceError paramCheck = NymeaCore::instance()->deviceManager()->verifyParams(actionType.paramTypes(), finalParams); - if (paramCheck != DeviceManager::DeviceErrorNoError) { - qCWarning(dcRuleEngine) << "Cannot create rule. Got an invalid actionParam."; - return RuleErrorInvalidRuleActionParameter; - } - } - } - } - - foreach (const RuleActionParam &ruleActionParam, action.ruleActionParams()) { - if (!ruleActionParam.isValid()) { - qCWarning(dcRuleEngine) << "Cannot create rule. Got an actionParam with \"value\" AND \"eventTypeId\"."; - return RuleEngine::RuleErrorInvalidRuleActionParameter; - } - } - } else { // Is TypeInterface Interface iface = NymeaCore::instance()->deviceManager()->supportedInterfaces().findByName(action.interface()); if (!iface.isValid()) { @@ -471,77 +422,145 @@ RuleEngine::RuleError RuleEngine::addRule(const Rule &rule, bool fromEdit) return RuleError::RuleErrorInvalidParameter; } } - // TODO: Check params + } + + foreach (const RuleActionParam &ruleActionParam, action.ruleActionParams()) { + if (ruleActionParam.isEventBased()) { + // We have an eventTypeId, see if the rule actually has such a event + if (rule.eventDescriptors().isEmpty() || !checkEventDescriptors(rule.eventDescriptors(), ruleActionParam.eventTypeId())) { + qCWarning(dcRuleEngine) << "Cannot create rule. EventTypeId from RuleAction" << action.actionTypeId() << "not in eventDescriptors."; + return RuleErrorInvalidRuleActionParameter; + } + + // check if the param type of the event and the action match + QVariant::Type eventParamType = getEventParamType(ruleActionParam.eventTypeId(), ruleActionParam.eventParamTypeId()); + QVariant v(eventParamType); + QVariant::Type actionParamType = getActionParamType(action.actionTypeId(), ruleActionParam.paramTypeId()); + if (eventParamType != actionParamType && !v.canConvert(static_cast(actionParamType))) { + qCWarning(dcRuleEngine) << "Cannot create rule. RuleActionParam" << ruleActionParam.paramTypeId().toString() << " and given event param " << ruleActionParam.eventParamTypeId().toString() << "have not the same type:"; + qCWarning(dcRuleEngine) << " -> actionParamType:" << actionParamType; + qCWarning(dcRuleEngine) << " -> eventParamType:" << eventParamType; + return RuleErrorTypesNotMatching; + } + } else if (ruleActionParam.isStateBased()) { + Device *d = NymeaCore::instance()->deviceManager()->findConfiguredDevice(ruleActionParam.deviceId()); + if (!d) { + qCWarning(dcRuleEngine()) << "Cannot create Rule. DeviceId from RuleAction" << action.actionTypeId() << "not found in system."; + return RuleErrorDeviceNotFound; + } + DeviceClass stateDeviceClass = NymeaCore::instance()->deviceManager()->findDeviceClass(d->deviceClassId()); + StateType stateType = stateDeviceClass.stateTypes().findById(ruleActionParam.stateTypeId()); + QVariant::Type actionParamType = getActionParamType(action.actionTypeId(), ruleActionParam.paramTypeId()); + QVariant v(stateType.type()); + if (actionParamType != stateType.type() && !v.canConvert(static_cast(actionParamType))) { + qCWarning(dcRuleEngine) << "Cannot create rule. RuleActionParam" << ruleActionParam.paramTypeId().toString() << " and given state based param " << ruleActionParam.stateTypeId().toString() << "have not the same type:"; + qCWarning(dcRuleEngine) << " -> actionParamType:" << actionParamType; + qCWarning(dcRuleEngine) << " -> stateType:" << stateType.type(); + return RuleErrorTypesNotMatching; + } + } else { + if (ruleActionParam.value().isNull()) { + qCDebug(dcRuleEngine()) << "Cannot create rule. No param value given for action:" << ruleActionParam.paramTypeId().toString(); + return RuleErrorInvalidRuleActionParameter; + } + QVariant::Type actionParamType = getActionParamType(action.actionTypeId(), ruleActionParam.paramTypeId()); + if (ruleActionParam.value().type() != actionParamType && !ruleActionParam.value().canConvert(static_cast(actionParamType))) { + qCDebug(dcRuleEngine()) << "Cannot create rule. Given param value for action" << ruleActionParam.paramTypeId().toString() << "does not match type"; + return RuleErrorInvalidRuleActionParameter; + } + } + } + + foreach (const RuleActionParam &ruleActionParam, action.ruleActionParams()) { + if (!ruleActionParam.isValid()) { + qCWarning(dcRuleEngine) << "Cannot create rule. There must be only one out of \"value\", \"eventTypeId/eventParamTypeID\" or \"deviceId/stateTypeId\"."; + return RuleEngine::RuleErrorInvalidRuleActionParameter; + } } } // Check exit actions - foreach (const RuleAction &ruleAction, rule.exitActions()) { - if (!ruleAction.isValid()) { + foreach (const RuleAction &ruleExitAction, rule.exitActions()) { + if (!ruleExitAction.isValid()) { qWarning(dcRuleEngine()) << "Exit Action is incomplete. It must have either actionTypeId and deviceId, or interface and interfaceAction"; return RuleErrorActionTypeNotFound; } - if (ruleAction.type() == RuleAction::TypeDevice) { - Device *device = NymeaCore::instance()->deviceManager()->findConfiguredDevice(ruleAction.deviceId()); + if (ruleExitAction.type() == RuleAction::TypeDevice) { + Device *device = NymeaCore::instance()->deviceManager()->findConfiguredDevice(ruleExitAction.deviceId()); if (!device) { - qCWarning(dcRuleEngine) << "Cannot create rule. No configured device for exit action with actionTypeId" << ruleAction.actionTypeId(); + qCWarning(dcRuleEngine) << "Cannot create rule. No configured device for exit action with actionTypeId" << ruleExitAction.actionTypeId(); return RuleErrorDeviceNotFound; } DeviceClass deviceClass = NymeaCore::instance()->deviceManager()->findDeviceClass(device->deviceClassId()); - if (!deviceClass.hasActionType(ruleAction.actionTypeId())) { - qCWarning(dcRuleEngine) << "Cannot create rule. Device " + device->name() + " has no action type:" << ruleAction.actionTypeId(); + if (!deviceClass.hasActionType(ruleExitAction.actionTypeId())) { + qCWarning(dcRuleEngine) << "Cannot create rule. Device " + device->name() + " has no action type:" << ruleExitAction.actionTypeId(); return RuleErrorActionTypeNotFound; } - // verify action params - foreach (const ActionType &actionType, deviceClass.actionTypes()) { - if (actionType.id() == ruleAction.actionTypeId()) { - ParamList finalParams = ruleAction.toAction().params(); - DeviceManager::DeviceError paramCheck = NymeaCore::instance()->deviceManager()->verifyParams(actionType.paramTypes(), finalParams); - if (paramCheck != DeviceManager::DeviceErrorNoError) { - qCWarning(dcRuleEngine) << "Cannot create rule. Got an invalid exit actionParam."; - return RuleErrorInvalidRuleActionParameter; - } - } - } - - // Exit action can never be event based. - if (ruleAction.isEventBased()) { - qCWarning(dcRuleEngine) << "Cannot create rule. Got exitAction with an actionParam containing an eventTypeId. "; - return RuleErrorInvalidRuleActionParameter; - } - - foreach (const RuleActionParam &ruleActionParam, ruleAction.ruleActionParams()) { - if (!ruleActionParam.isValid()) { - qCWarning(dcRuleEngine) << "Cannot create rule. Got an actionParam with \"value\" AND \"eventTypeId\"."; - return RuleEngine::RuleErrorInvalidRuleActionParameter; - } - } - } else { // Is TypeInterface - Interface iface = NymeaCore::instance()->deviceManager()->supportedInterfaces().findByName(ruleAction.interface()); + Interface iface = NymeaCore::instance()->deviceManager()->supportedInterfaces().findByName(ruleExitAction.interface()); if (!iface.isValid()) { - qCWarning(dcRuleEngine()) << "Cannot create rule. No such interface:" << ruleAction.interface(); + qCWarning(dcRuleEngine()) << "Cannot create rule. No such interface:" << ruleExitAction.interface(); return RuleError::RuleErrorInterfaceNotFound; } - ActionType ifaceActionType = iface.actionTypes().findByName(ruleAction.interfaceAction()); + ActionType ifaceActionType = iface.actionTypes().findByName(ruleExitAction.interfaceAction()); if (ifaceActionType.name().isEmpty()) { - qCWarning(dcRuleEngine()) << "Cannot create rule. Interface" << iface.name() << "does not implement action" << ruleAction.interfaceAction(); + qCWarning(dcRuleEngine()) << "Cannot create rule. Interface" << iface.name() << "does not implement action" << ruleExitAction.interfaceAction(); return RuleError::RuleErrorActionTypeNotFound; } foreach (const ParamType &ifaceActionParamType, ifaceActionType.paramTypes()) { - if (!ruleAction.ruleActionParams().hasParam(ifaceActionParamType.name())) { - qCWarning(dcRuleEngine()) << "Cannot create rule. Interface action" << iface.name() << ":" << ruleAction.interfaceAction() << "requires a" << ifaceActionParamType.name() << "param of type" << QVariant::typeToName(ifaceActionParamType.type()); + if (!ruleExitAction.ruleActionParams().hasParam(ifaceActionParamType.name())) { + qCWarning(dcRuleEngine()) << "Cannot create rule. Interface action" << iface.name() << ":" << ruleExitAction.interfaceAction() << "requires a" << ifaceActionParamType.name() << "param of type" << QVariant::typeToName(ifaceActionParamType.type()); return RuleError::RuleErrorMissingParameter; } - if (!ruleAction.ruleActionParam(ifaceActionParamType.name()).value().canConvert(ifaceActionParamType.type())) { - qCWarning(dcRuleEngine()) << "Cannot create rule. Interface action parameter" << iface.name() << ":" << ruleAction.interfaceAction() << ":" << ifaceActionParamType.name() << "has wrong type. Expected" << QVariant::typeToName(ifaceActionParamType.type()); + if (!ruleExitAction.ruleActionParam(ifaceActionParamType.name()).value().canConvert(ifaceActionParamType.type())) { + qCWarning(dcRuleEngine()) << "Cannot create rule. Interface action parameter" << iface.name() << ":" << ruleExitAction.interfaceAction() << ":" << ifaceActionParamType.name() << "has wrong type. Expected" << QVariant::typeToName(ifaceActionParamType.type()); return RuleError::RuleErrorInvalidParameter; } } - // TODO: Check params + } + + foreach (const RuleActionParam &ruleActionParam, ruleExitAction.ruleActionParams()) { + if (ruleActionParam.isEventBased()) { + // We have an eventTypeId, see if the rule actually has such a event + qCWarning(dcRuleEngine) << "Cannot create rule. Exit actions cannot be event based."; + return RuleErrorInvalidRuleActionParameter; + } else if (ruleActionParam.isStateBased()) { + Device *d = NymeaCore::instance()->deviceManager()->findConfiguredDevice(ruleActionParam.deviceId()); + if (!d) { + qCWarning(dcRuleEngine()) << "Cannot create Rule. DeviceId from RuleAction" << ruleExitAction.actionTypeId() << "not found in system."; + return RuleErrorDeviceNotFound; + } + DeviceClass stateDeviceClass = NymeaCore::instance()->deviceManager()->findDeviceClass(d->deviceClassId()); + StateType stateType = stateDeviceClass.stateTypes().findById(ruleActionParam.stateTypeId()); + QVariant::Type actionParamType = getActionParamType(ruleExitAction.actionTypeId(), ruleActionParam.paramTypeId()); + QVariant v(stateType.type()); + if (actionParamType != stateType.type() && !v.canConvert(static_cast(actionParamType))) { + qCWarning(dcRuleEngine) << "Cannot create rule. RuleActionParam" << ruleActionParam.paramTypeId().toString() << " and given state based param " << ruleActionParam.stateTypeId().toString() << "have not the same type:"; + qCWarning(dcRuleEngine) << " -> actionParamType:" << actionParamType; + qCWarning(dcRuleEngine) << " -> stateType:" << stateType.type(); + return RuleErrorTypesNotMatching; + } + } else { + if (ruleActionParam.value().isNull()) { + qCDebug(dcRuleEngine()) << "Cannot create rule. No param value given for action:" << ruleActionParam.paramTypeId().toString(); + return RuleErrorInvalidRuleActionParameter; + } + QVariant::Type actionParamType = getActionParamType(ruleExitAction.actionTypeId(), ruleActionParam.paramTypeId()); + if (ruleActionParam.value().type() != actionParamType && !ruleActionParam.value().canConvert(static_cast(actionParamType))) { + qCDebug(dcRuleEngine()) << "Cannot create rule. Given param value for action" << ruleActionParam.paramTypeId().toString() << "does not match type"; + return RuleErrorInvalidRuleActionParameter; + } + } + } + + foreach (const RuleActionParam &ruleActionParam, ruleExitAction.ruleActionParams()) { + if (!ruleActionParam.isValid()) { + qCWarning(dcRuleEngine) << "Cannot create rule. There must be only one out of \"value\", \"eventTypeId/eventParamTypeID\" or \"deviceId/stateTypeId\"."; + return RuleEngine::RuleErrorInvalidRuleActionParameter; + } } } @@ -698,9 +717,9 @@ RuleEngine::RuleError RuleEngine::disableRule(const RuleId &ruleId) */ RuleEngine::RuleError RuleEngine::executeActions(const RuleId &ruleId) { - // check if rule exits + // check if rule exists if (!m_rules.contains(ruleId)) { - qCWarning(dcRuleEngine) << "Not executing rule actions: rule not found."; + qCWarning(dcRuleEngine) << "Not executing rule actions: Rule not found."; return RuleErrorRuleNotFound; } @@ -1203,11 +1222,14 @@ void RuleEngine::saveRule(const Rule &rule) } else { settings.beginGroup("RuleActionParam-" + param.paramName()); } - settings.setValue("valueType", (int)param.value().type()); + settings.setValue("valueType", static_cast(param.value().type())); settings.setValue("value", param.value()); - if (param.eventTypeId() != EventTypeId()) { + if (param.isEventBased()) { settings.setValue("eventTypeId", param.eventTypeId().toString()); settings.setValue("eventParamTypeId", param.eventParamTypeId()); + } else if (param.isStateBased()) { + settings.setValue("deviceId", param.deviceId().toString()); + settings.setValue("stateTypeId", param.stateTypeId()); } settings.endGroup(); } @@ -1276,7 +1298,7 @@ void RuleEngine::init() QList weekDays; QList monthDays; - RepeatingOption::RepeatingMode mode = (RepeatingOption::RepeatingMode)settings.value("mode", 0).toInt(); + RepeatingOption::RepeatingMode mode = static_cast(settings.value("mode", 0).toInt()); // Load weekDays int weekDaysCount = settings.beginReadArray("weekDays"); @@ -1313,7 +1335,7 @@ void RuleEngine::init() QList weekDays; QList monthDays; - RepeatingOption::RepeatingMode mode = (RepeatingOption::RepeatingMode)settings.value("mode", 0).toInt(); + RepeatingOption::RepeatingMode mode = static_cast(settings.value("mode", 0).toInt()); // Load weekDays int weekDaysCount = settings.beginReadArray("weekDays"); @@ -1414,6 +1436,8 @@ void RuleEngine::init() QString strippedParamTypeIdString = paramTypeIdString.remove(QRegExp("^RuleActionParam-")); EventTypeId eventTypeId = EventTypeId(settings.value("eventTypeId", EventTypeId()).toString()); ParamTypeId eventParamTypeId = ParamTypeId(settings.value("eventParamTypeId", ParamTypeId()).toString()); + DeviceId deviceId = DeviceId(settings.value("deviceId", DeviceId()).toString()); + StateTypeId stateTypeId = StateTypeId(settings.value("stateTypeId", StateTypeId()).toString()); QVariant value = settings.value("value"); if (settings.contains("valueType")) { QVariant::Type valueType = (QVariant::Type)settings.value("valueType").toInt(); @@ -1427,19 +1451,20 @@ void RuleEngine::init() } } + RuleActionParam param; if (!ParamTypeId(strippedParamTypeIdString).isNull()) { - RuleActionParam param(ParamTypeId(strippedParamTypeIdString), - value, - eventTypeId, - eventParamTypeId); - params.append(param); + // By ParamTypeId + param = RuleActionParam(ParamTypeId(strippedParamTypeIdString), value); } else { - RuleActionParam param(strippedParamTypeIdString, - value, - eventTypeId, - eventParamTypeId); - params.append(param); + // By param name + param = RuleActionParam(strippedParamTypeIdString, value); } + param.setEventTypeId(eventTypeId); + param.setEventParamTypeId(eventParamTypeId); + param.setDeviceId(deviceId); + param.setStateTypeId(stateTypeId); + params.append(param); + params.append(param); settings.endGroup(); } } diff --git a/libnymea-core/time/timeeventitem.cpp b/libnymea-core/time/timeeventitem.cpp index 3ef56957..b4fa53f8 100644 --- a/libnymea-core/time/timeeventitem.cpp +++ b/libnymea-core/time/timeeventitem.cpp @@ -48,7 +48,7 @@ QDateTime TimeEventItem::dateTime() const } /*! Sets the dateTime of this \l{TimeEventItem} to the given \a timeStamp. */ -void TimeEventItem::setDateTime(const int &timeStamp) +void TimeEventItem::setDateTime(const uint &timeStamp) { m_dateTime = QDateTime::fromTime_t(timeStamp); } diff --git a/libnymea-core/time/timeeventitem.h b/libnymea-core/time/timeeventitem.h index c91f0be2..60a2a82a 100644 --- a/libnymea-core/time/timeeventitem.h +++ b/libnymea-core/time/timeeventitem.h @@ -33,7 +33,7 @@ public: TimeEventItem(); QDateTime dateTime() const; - void setDateTime(const int &timeStamp); + void setDateTime(const uint &timeStamp); QTime time() const; void setTime(const QTime &time); diff --git a/libnymea/types/ruleaction.cpp b/libnymea/types/ruleaction.cpp index 17feaffd..08882ccd 100644 --- a/libnymea/types/ruleaction.cpp +++ b/libnymea/types/ruleaction.cpp @@ -99,7 +99,17 @@ RuleAction::Type RuleAction::type() const bool RuleAction::isEventBased() const { foreach (const RuleActionParam ¶m, m_ruleActionParams) { - if (param.eventTypeId() != EventTypeId()) { + if (param.isEventBased()) { + return true; + } + } + return false; +} + +bool RuleAction::isStateBased() const +{ + foreach (const RuleActionParam ¶m, m_ruleActionParams) { + if (param.isStateBased()) { return true; } } @@ -167,7 +177,7 @@ RuleActionParam RuleAction::ruleActionParam(const ParamTypeId &ruleActionParamTy return ruleActionParam; } } - return RuleActionParam(QString()); + return RuleActionParam(); } /*! Returns the \l{RuleActionParam} of this RuleAction with the given \a ruleActionParamName. @@ -180,7 +190,7 @@ RuleActionParam RuleAction::ruleActionParam(const QString &ruleActionParamName) return ruleActionParam; } } - return RuleActionParam(QString()); + return RuleActionParam(); } /*! Copy the data to a \l{RuleAction} from an \a other rule action. */ diff --git a/libnymea/types/ruleaction.h b/libnymea/types/ruleaction.h index 75b6d72d..98dee3b9 100644 --- a/libnymea/types/ruleaction.h +++ b/libnymea/types/ruleaction.h @@ -45,6 +45,7 @@ public: Type type() const; bool isEventBased() const; + bool isStateBased() const; Action toAction() const; diff --git a/libnymea/types/ruleactionparam.cpp b/libnymea/types/ruleactionparam.cpp index a60943de..91737fae 100644 --- a/libnymea/types/ruleactionparam.cpp +++ b/libnymea/types/ruleactionparam.cpp @@ -32,6 +32,21 @@ A RuleActionParam allows rules to take over an \l{Event} parameter into a rule \l{RuleAction}. + RuleActionParams are identified by either paramTypeId or paramName (for interface based actions). + + The parameter value can either be a static \l{value}, a pair of \l{EventTypeId} and \l{ParamTypeId} or a pair of + \l{DeviceId} and \l{StateTypeId}. + + When composing the actual Param for the executeAction() call the value is generated as follows: + - Static value params are filled with \l{RuleActionParam::paramTypeId()} and the \l{RuleActionParam::value()} + - Event based actions are filled with \l{RuleActionParam::paramTypeId()} and the param value of the event that triggered this rule, identified by \l{RuleActionParam::eventTypeId()} and \l{RuleActionParam::eventParamTypeId()} + - State based actions are filled with \l{RuleActionParam::paramTypeId()} and the current value of the state identified by \l{RuleActionParam::deviceId()} and \l{RuleActionParam::stateTypeId()} + + If the param types are not matching, nymea will do a best effort to cast the values. E.g. a RuleActionParam for + a param of type "string" and a state of type "int" would cast the integer to a string which would always work. + However, the other way round, having a parameter requiring an "int" value, and reading the value from a state of type + "string" might work, if the string does only hold numbers but would fail. + \sa nymeaserver::Rule, RuleAction, */ @@ -41,33 +56,68 @@ * \sa Param, */ RuleActionParam::RuleActionParam(const Param ¶m) : m_paramTypeId(param.paramTypeId()), - m_value(param.value()), - m_eventTypeId(EventTypeId()), - m_eventParamTypeId(ParamTypeId()) + m_value(param.value()) { } -/*! Constructs a \l{RuleActionParam} with the given \a paramTypeId, \a value, \a eventTypeId and \a eventParamTypeId. +/*! Constructs a \l{RuleActionParam} with the given \a paramTypeId and \a value. * \sa Param, Event, */ -RuleActionParam::RuleActionParam(const ParamTypeId ¶mTypeId, const QVariant &value, const EventTypeId &eventTypeId, const ParamTypeId &eventParamTypeId) : +RuleActionParam::RuleActionParam(const ParamTypeId ¶mTypeId, const QVariant &value): + m_paramTypeId(paramTypeId), + m_value(value) +{ + +} + +/*! Constructs a \l{RuleActionParam} with the given \a paramTypeId, \a eventTypeId and \a eventParamTypeId. + * \sa Param, Event, */ +RuleActionParam::RuleActionParam(const ParamTypeId ¶mTypeId, const EventTypeId &eventTypeId, const ParamTypeId &eventParamTypeId): m_paramTypeId(paramTypeId), - m_value(value), m_eventTypeId(eventTypeId), m_eventParamTypeId(eventParamTypeId) { + } -/*! Constructs a \l{RuleActionParam} with the given \a paramName, \a value, \a eventTypeId and \a eventParamTypeId. +/*! Constructs a \l{RuleActionParam} with the given \a paramTypeId, \a deviceId and \a stateTypeId. * \sa Param, Event, */ -RuleActionParam::RuleActionParam(const QString ¶mName, const QVariant &value, const EventTypeId &eventTypeId, const ParamTypeId &eventParamTypeId): +RuleActionParam::RuleActionParam(const ParamTypeId ¶mTypeId, const DeviceId &deviceId, const StateTypeId &stateTypeId): + m_paramTypeId(paramTypeId), + m_deviceId(deviceId), + m_stateTypeId(stateTypeId) +{ + +} + +/*! Constructs a \l{RuleActionParam} with the given \a paramName and \a value. + * \sa Param, Event, */ +RuleActionParam::RuleActionParam(const QString ¶mName, const QVariant &value): + m_paramName(paramName), + m_value(value) +{ + +} + +/*! Constructs a \l{RuleActionParam} with the given \a paramName, \a eventTypeId and \a eventParamTypeId. + * \sa Param, Event, */ +RuleActionParam::RuleActionParam(const QString ¶mName, const EventTypeId &eventTypeId, const ParamTypeId &eventParamTypeId): m_paramName(paramName), - m_value(value), m_eventTypeId(eventTypeId), m_eventParamTypeId(eventParamTypeId) { } +/*! Constructs a \l{RuleActionParam} with the given \a paramName, \a deviceId and \a stateTypeId. + * \sa Param, Event, */ +RuleActionParam::RuleActionParam(const QString ¶mName, const DeviceId &deviceId, const StateTypeId &stateTypeId): + m_paramName(paramName), + m_deviceId(deviceId), + m_stateTypeId(stateTypeId) +{ + +} + /*! Returns the \l ParamTypeId of this \l RuleActionParam. */ ParamTypeId RuleActionParam::paramTypeId() const { @@ -80,18 +130,6 @@ QString RuleActionParam::paramName() const return m_paramName; } -/*! Returns the eventParamTypeId of this RuleActionParam. */ -ParamTypeId RuleActionParam::eventParamTypeId() const -{ - return m_eventParamTypeId; -} - -/*! Sets the \a eventParamTypeId of this RuleActionParam. */ -void RuleActionParam::setEventParamTypeId(const ParamTypeId &eventParamTypeId) -{ - m_eventParamTypeId = eventParamTypeId; -} - /*! Returns the value of this RuleActionParam. */ QVariant RuleActionParam::value() const { @@ -104,14 +142,6 @@ void RuleActionParam::setValue(const QVariant &value) m_value = value; } -/*! Returns true if the \tt{(paramTypeId AND value) XOR (paramTypeId AND eventTypeId AND eventParamName)} of this RuleActionParam are set.*/ -bool RuleActionParam::isValid() const -{ - bool validValue = (!m_paramTypeId.isNull() && m_value.isValid() && m_eventTypeId.isNull() && m_eventParamTypeId.isNull()); - bool validEvent = (!m_paramTypeId.isNull() && !m_value.isValid() && !m_eventTypeId.isNull() && !m_eventParamTypeId.isNull()); - return validValue ^ validEvent; -} - /*! Return the EventTypeId of the \l{Event} with the \l{Param} which will be taken over in the \l{RuleAction}. */ EventTypeId RuleActionParam::eventTypeId() const { @@ -124,6 +154,66 @@ void RuleActionParam::setEventTypeId(const EventTypeId &eventTypeId) m_eventTypeId = eventTypeId; } +/*! Returns the eventParamTypeId of this RuleActionParam. */ +ParamTypeId RuleActionParam::eventParamTypeId() const +{ + return m_eventParamTypeId; +} + +/*! Sets the \a eventParamTypeId of this RuleActionParam. */ +void RuleActionParam::setEventParamTypeId(const ParamTypeId &eventParamTypeId) +{ + m_eventParamTypeId = eventParamTypeId; +} + +/*! Returns the deviceId identifying the device to use a state value from. */ +DeviceId RuleActionParam::deviceId() const +{ + return m_deviceId; +} + +/*! Sets the deviceId identifying the device to use a state value from. */ +void RuleActionParam::setDeviceId(const DeviceId &deviceId) +{ + m_deviceId = deviceId; +} + +/*! Returns the stateTypeId identifying the state to use the value. */ +StateTypeId RuleActionParam::stateTypeId() const +{ + return m_stateTypeId; +} + +/*! Sets the stateTypeId identifying the state to use the value from. */ +void RuleActionParam::setStateTypeId(const StateTypeId &stateTypeId) +{ + m_stateTypeId = stateTypeId; +} + +/*! Returns true if the \tt{(paramTypeId AND value) XOR (paramTypeId AND eventTypeId AND eventParamName)} of this RuleActionParam are set.*/ +bool RuleActionParam::isValid() const +{ + if (m_paramTypeId.isNull() && m_paramName.isNull()) { + return false; + } + return isValueBased() ^ isEventBased() ^ isStateBased(); +} + +bool RuleActionParam::isValueBased() const +{ + return !m_value.isNull(); +} + +bool RuleActionParam::isEventBased() const +{ + return !m_eventTypeId.isNull() && !m_eventParamTypeId.isNull(); +} + +bool RuleActionParam::isStateBased() const +{ + return !m_deviceId.isNull() && !m_stateTypeId.isNull(); +} + /*! Writes the paramTypeId, value, eventId and eventParamTypeId of the given \a ruleActionParam to \a dbg. */ QDebug operator<<(QDebug dbg, const RuleActionParam &ruleActionParam) { diff --git a/libnymea/types/ruleactionparam.h b/libnymea/types/ruleactionparam.h index ad07b1e8..efbfd71f 100644 --- a/libnymea/types/ruleactionparam.h +++ b/libnymea/types/ruleactionparam.h @@ -36,29 +36,46 @@ class LIBNYMEA_EXPORT RuleActionParam { public: RuleActionParam(const Param ¶m = Param()); - RuleActionParam(const ParamTypeId ¶mTypeId, const QVariant &value = QVariant(), const EventTypeId &eventTypeId = EventTypeId(), const ParamTypeId &eventParamTypeId = ParamTypeId()); - RuleActionParam(const QString ¶mName, const QVariant &value = QVariant(), const EventTypeId &eventTypeId = EventTypeId(), const ParamTypeId &eventParamTypeId = ParamTypeId()); + RuleActionParam(const ParamTypeId ¶mTypeId, const QVariant &value = QVariant()); + RuleActionParam(const ParamTypeId ¶mTypeId, const EventTypeId &eventTypeId, const ParamTypeId &eventParamTypeId); + RuleActionParam(const ParamTypeId ¶mTypeId, const DeviceId &deviceId, const StateTypeId &stateTypeId); + RuleActionParam(const QString ¶mName, const QVariant &value = QVariant()); + RuleActionParam(const QString ¶mName, const EventTypeId &eventTypeId, const ParamTypeId &eventParamTypeId); + RuleActionParam(const QString ¶mName, const DeviceId &deviceId, const StateTypeId &stateTypeId); ParamTypeId paramTypeId() const; QString paramName() const; - ParamTypeId eventParamTypeId() const; - void setEventParamTypeId(const ParamTypeId &eventParamTypeId); + bool isValid() const; + bool isValueBased() const; + bool isEventBased() const; + bool isStateBased() const; QVariant value() const; void setValue(const QVariant &value); - bool isValid() const; - EventTypeId eventTypeId() const; void setEventTypeId(const EventTypeId &eventTypeId); + ParamTypeId eventParamTypeId() const; + void setEventParamTypeId(const ParamTypeId &eventParamTypeId); + + DeviceId deviceId() const; + void setDeviceId(const DeviceId &deviceId); + + StateTypeId stateTypeId() const; + void setStateTypeId(const StateTypeId &stateTypeId); + private: ParamTypeId m_paramTypeId; QString m_paramName; QVariant m_value; + EventTypeId m_eventTypeId; ParamTypeId m_eventParamTypeId; + + DeviceId m_deviceId; + StateTypeId m_stateTypeId; }; Q_DECLARE_METATYPE(RuleActionParam) diff --git a/tests/auto/rules/testrules.cpp b/tests/auto/rules/testrules.cpp index 03d29bed..c4efee05 100644 --- a/tests/auto/rules/testrules.cpp +++ b/tests/auto/rules/testrules.cpp @@ -93,9 +93,10 @@ private slots: void enableDisableRule(); void testEventBasedAction(); - void testEventBasedRuleWithExitAction(); + void testStateBasedAction(); + void removePolicyUpdate(); void removePolicyCascade(); void removePolicyUpdateRendersUselessRule(); @@ -2214,6 +2215,98 @@ void TestRules::testEventBasedRuleWithExitAction() } +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(mockBoolStateId.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(mockIntStateId.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", mockEvent1Id); + 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", mockActionParam1ParamTypeId); + param1.insert("deviceId", m_mockDeviceId); + param1.insert("stateTypeId", mockIntStateId); + QVariantMap param2; + param2.insert("paramTypeId", mockActionParam2ParamTypeId); + param2.insert("deviceId", m_mockDeviceId); + param2.insert("stateTypeId", mockBoolStateId); + ruleActionParams.append(param1); + ruleActionParams.append(param2); + + actions.clear(); + action.insert("deviceId", m_mockDeviceId); + action.insert("actionTypeId", mockActionIdWithParams); + action.insert("ruleActionParams", ruleActionParams); + actions.append(action); + addRuleParams.insert("actions", 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(mockEvent1Id.toString()))); + reply = nam.get(request); + spy.wait(); + QCOMPARE(spy.count(), 1); + reply->deleteLater(); + + LogFilter filter; + filter.addDeviceId(m_mockDeviceId); + filter.addTypeId(mockActionIdWithParams); + QList entries = NymeaCore::instance()->logEngine()->logEntries(filter); + qCDebug(dcTests()) << "Log entries:" << entries; + + // set bool state to false + spy.clear(); + request = QNetworkRequest(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockBoolStateId.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(mockEvent1Id.toString()))); + reply = nam.get(request); + spy.wait(); + QCOMPARE(spy.count(), 1); + reply->deleteLater(); + + entries = NymeaCore::instance()->logEngine()->logEntries(filter); + qCDebug(dcTests()) << "Log entries:" << entries; + + +} + void TestRules::removePolicyUpdate() { // ADD parent device From 6afe3e5161deac19dc31185fd16ed4a911d40445 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Wed, 27 Mar 2019 01:05:59 +0100 Subject: [PATCH 2/5] fixup api --- libnymea-core/jsonrpc/jsontypes.cpp | 24 +++++++-------- libnymea-core/nymeacore.cpp | 8 ++--- libnymea-core/ruleengine.cpp | 48 ++++++++++++++--------------- libnymea/types/ruleactionparam.cpp | 22 ++++++------- libnymea/types/ruleactionparam.h | 10 +++--- 5 files changed, 56 insertions(+), 56 deletions(-) diff --git a/libnymea-core/jsonrpc/jsontypes.cpp b/libnymea-core/jsonrpc/jsontypes.cpp index 8e1727ac..ae91456c 100644 --- a/libnymea-core/jsonrpc/jsontypes.cpp +++ b/libnymea-core/jsonrpc/jsontypes.cpp @@ -188,7 +188,7 @@ void JsonTypes::init() s_ruleActionParam.insert("o:value", basicTypeRef()); s_ruleActionParam.insert("o:eventTypeId", basicTypeToString(Uuid)); s_ruleActionParam.insert("o:eventParamTypeId", basicTypeToString(Uuid)); - s_ruleActionParam.insert("o:deviceId", basicTypeToString(Uuid)); + s_ruleActionParam.insert("o:stateDeviceId", basicTypeToString(Uuid)); s_ruleActionParam.insert("o:stateTypeId", basicTypeToString(Uuid)); // ParamDescriptor @@ -619,7 +619,7 @@ QVariantMap JsonTypes::packRuleActionParam(const RuleActionParam &ruleActionPara variantMap.insert("eventTypeId", ruleActionParam.eventTypeId().toString()); variantMap.insert("eventParamTypeId", ruleActionParam.eventParamTypeId().toString()); } else if (ruleActionParam.isStateBased()) { - variantMap.insert("deviceId", ruleActionParam.deviceId().toString()); + variantMap.insert("stateDeviceId", ruleActionParam.stateDeviceId().toString()); variantMap.insert("stateTypeId", ruleActionParam.stateTypeId().toString()); } else { variantMap.insert("value", ruleActionParam.value()); @@ -1444,7 +1444,7 @@ RuleActionParam JsonTypes::unpackRuleActionParam(const QVariantMap &ruleActionPa param.setValue(ruleActionParamMap.value("value")); param.setEventTypeId(EventTypeId(ruleActionParamMap.value("eventTypeId").toString())); param.setEventParamTypeId(ParamTypeId(ruleActionParamMap.value("eventParamTypeId").toString())); - param.setDeviceId(DeviceId(ruleActionParamMap.value("deviceId").toString())); + param.setStateDeviceId(DeviceId(ruleActionParamMap.value("stateDeviceId").toString())); param.setStateTypeId(StateTypeId(ruleActionParamMap.value("stateTypeId").toString())); return param; } @@ -1466,7 +1466,7 @@ ParamDescriptor JsonTypes::unpackParamDescriptor(const QVariantMap ¶mMap) QMetaObject metaObject = Types::staticMetaObject; int enumIndex = metaObject.indexOfEnumerator("ValueOperator"); QMetaEnum metaEnum = metaObject.enumerator(enumIndex); - Types::ValueOperator valueOperator = (Types::ValueOperator)metaEnum.keyToValue(operatorString.toLatin1().data()); + Types::ValueOperator valueOperator = static_cast(metaEnum.keyToValue(operatorString.toLatin1().data())); if (paramMap.contains("paramTypeId")) { ParamDescriptor param = ParamDescriptor(ParamTypeId(paramMap.value("paramTypeId").toString()), paramMap.value("value")); @@ -1507,7 +1507,7 @@ StateEvaluator JsonTypes::unpackStateEvaluator(const QVariantMap &stateEvaluator { StateEvaluator ret(unpackStateDescriptor(stateEvaluatorMap.value("stateDescriptor").toMap())); if (stateEvaluatorMap.contains("operator")) { - ret.setOperatorType((Types::StateOperator)s_stateOperator.indexOf(stateEvaluatorMap.value("operator").toString())); + ret.setOperatorType(static_cast(s_stateOperator.indexOf(stateEvaluatorMap.value("operator").toString()))); } else { ret.setOperatorType(Types::StateOperatorAnd); } @@ -1528,7 +1528,7 @@ StateDescriptor JsonTypes::unpackStateDescriptor(const QVariantMap &stateDescrip QString interface(stateDescriptorMap.value("interface").toString()); QString interfaceState(stateDescriptorMap.value("interfaceState").toString()); QVariant value = stateDescriptorMap.value("value"); - Types::ValueOperator operatorType = (Types::ValueOperator)s_valueOperator.indexOf(stateDescriptorMap.value("operator").toString()); + Types::ValueOperator operatorType = static_cast(s_valueOperator.indexOf(stateDescriptorMap.value("operator").toString())); if (!deviceId.isNull() && !stateTypeId.isNull()) { StateDescriptor stateDescriptor(stateTypeId, deviceId, value, operatorType); return stateDescriptor; @@ -1547,10 +1547,10 @@ LogFilter JsonTypes::unpackLogFilter(const QVariantMap &logFilterMap) QVariantMap timeFilterMap = timeFilter.toMap(); QDateTime startDate; QDateTime endDate; if (timeFilterMap.contains("startDate")) - startDate = QDateTime::fromTime_t(timeFilterMap.value("startDate").toInt()); + startDate = QDateTime::fromTime_t(timeFilterMap.value("startDate").toUInt()); if (timeFilterMap.contains("endDate")) - endDate = QDateTime::fromTime_t(timeFilterMap.value("endDate").toInt()); + endDate = QDateTime::fromTime_t(timeFilterMap.value("endDate").toUInt()); filter.addTimeFilter(startDate, endDate); } @@ -1559,19 +1559,19 @@ LogFilter JsonTypes::unpackLogFilter(const QVariantMap &logFilterMap) if (logFilterMap.contains("loggingSources")) { QVariantList loggingSources = logFilterMap.value("loggingSources").toList(); foreach (const QVariant &source, loggingSources) { - filter.addLoggingSource((Logging::LoggingSource)s_loggingSource.indexOf(source.toString())); + filter.addLoggingSource(static_cast(s_loggingSource.indexOf(source.toString()))); } } if (logFilterMap.contains("loggingLevels")) { QVariantList loggingLevels = logFilterMap.value("loggingLevels").toList(); foreach (const QVariant &level, loggingLevels) { - filter.addLoggingLevel((Logging::LoggingLevel)s_loggingLevel.indexOf(level.toString())); + filter.addLoggingLevel(static_cast(s_loggingLevel.indexOf(level.toString()))); } } if (logFilterMap.contains("eventTypes")) { QVariantList eventTypes = logFilterMap.value("eventTypes").toList(); foreach (const QVariant &eventType, eventTypes) { - filter.addLoggingEventType((Logging::LoggingEventType)s_loggingEventType.indexOf(eventType.toString())); + filter.addLoggingEventType(static_cast(s_loggingEventType.indexOf(eventType.toString()))); } } if (logFilterMap.contains("typeIds")) { @@ -1605,7 +1605,7 @@ LogFilter JsonTypes::unpackLogFilter(const QVariantMap &logFilterMap) /*! Returns a \l{RepeatingOption} created from the given \a repeatingOptionMap. */ RepeatingOption JsonTypes::unpackRepeatingOption(const QVariantMap &repeatingOptionMap) { - RepeatingOption::RepeatingMode mode = (RepeatingOption::RepeatingMode)s_repeatingMode.indexOf(repeatingOptionMap.value("mode").toString()); + RepeatingOption::RepeatingMode mode = static_cast(s_repeatingMode.indexOf(repeatingOptionMap.value("mode").toString())); QList weekDays; if (repeatingOptionMap.contains("weekDays")) { diff --git a/libnymea-core/nymeacore.cpp b/libnymea-core/nymeacore.cpp index e2b402b7..377382d9 100644 --- a/libnymea-core/nymeacore.cpp +++ b/libnymea-core/nymeacore.cpp @@ -446,9 +446,9 @@ void NymeaCore::executeRuleActions(const QList ruleActions) if (ruleActionParam.isValueBased()) { params.append(Param(ruleActionParam.paramTypeId(), ruleActionParam.value())); } else if (ruleActionParam.isStateBased()) { - Device *stateDevice = m_deviceManager->findConfiguredDevice(ruleActionParam.deviceId()); + Device *stateDevice = m_deviceManager->findConfiguredDevice(ruleActionParam.stateDeviceId()); if (!stateDevice) { - qCWarning(dcRuleEngine()) << "Cannot find device" << ruleActionParam.deviceId() << "required by rule action" << ruleAction.id(); + qCWarning(dcRuleEngine()) << "Cannot find device" << ruleActionParam.stateDeviceId() << "required by rule action" << ruleAction.id(); ok = false; break; } @@ -490,9 +490,9 @@ void NymeaCore::executeRuleActions(const QList ruleActions) if (ruleActionParam.isValueBased()) { params.append(Param(paramType.id(), ruleActionParam.value())); } else if (ruleActionParam.isStateBased()) { - Device *stateDevice = m_deviceManager->findConfiguredDevice(ruleActionParam.deviceId()); + Device *stateDevice = m_deviceManager->findConfiguredDevice(ruleActionParam.stateDeviceId()); if (!stateDevice) { - qCWarning(dcRuleEngine()) << "Cannot find device" << ruleActionParam.deviceId() << "required by rule action" << ruleAction.id(); + qCWarning(dcRuleEngine()) << "Cannot find device" << ruleActionParam.stateDeviceId() << "required by rule action" << ruleAction.id(); ok = false; break; } diff --git a/libnymea-core/ruleengine.cpp b/libnymea-core/ruleengine.cpp index dc9b870c..524fca02 100644 --- a/libnymea-core/ruleengine.cpp +++ b/libnymea-core/ruleengine.cpp @@ -414,11 +414,11 @@ RuleEngine::RuleError RuleEngine::addRule(const Rule &rule, bool fromEdit) } foreach (const ParamType &ifaceActionParamType, ifaceActionType.paramTypes()) { if (!action.ruleActionParams().hasParam(ifaceActionParamType.name())) { - qCWarning(dcRuleEngine()) << "Cannot create rule. Interface action" << iface.name() << ":" << action.interfaceAction() << "requires a" << ifaceActionParamType.name() << "param of type" << QVariant::typeToName(ifaceActionParamType.type()); + qCWarning(dcRuleEngine()) << "Cannot create rule. Interface action" << iface.name() << ":" << action.interfaceAction() << "requires a" << ifaceActionParamType.name() << "param of type" << QVariant::typeToName(static_cast(ifaceActionParamType.type())); return RuleError::RuleErrorMissingParameter; } - if (!action.ruleActionParam(ifaceActionParamType.name()).value().canConvert(ifaceActionParamType.type())) { - qCWarning(dcRuleEngine()) << "Cannot create rule. Interface action parameter" << iface.name() << ":" << action.interfaceAction() << ":" << ifaceActionParamType.name() << "has wrong type. Expected" << QVariant::typeToName(ifaceActionParamType.type()); + if (!action.ruleActionParam(ifaceActionParamType.name()).value().canConvert(static_cast(ifaceActionParamType.type()))) { + qCWarning(dcRuleEngine()) << "Cannot create rule. Interface action parameter" << iface.name() << ":" << action.interfaceAction() << ":" << ifaceActionParamType.name() << "has wrong type. Expected" << QVariant::typeToName(static_cast(ifaceActionParamType.type())); return RuleError::RuleErrorInvalidParameter; } } @@ -443,7 +443,7 @@ RuleEngine::RuleError RuleEngine::addRule(const Rule &rule, bool fromEdit) return RuleErrorTypesNotMatching; } } else if (ruleActionParam.isStateBased()) { - Device *d = NymeaCore::instance()->deviceManager()->findConfiguredDevice(ruleActionParam.deviceId()); + Device *d = NymeaCore::instance()->deviceManager()->findConfiguredDevice(ruleActionParam.stateDeviceId()); if (!d) { qCWarning(dcRuleEngine()) << "Cannot create Rule. DeviceId from RuleAction" << action.actionTypeId() << "not found in system."; return RuleErrorDeviceNotFound; @@ -512,11 +512,11 @@ RuleEngine::RuleError RuleEngine::addRule(const Rule &rule, bool fromEdit) } foreach (const ParamType &ifaceActionParamType, ifaceActionType.paramTypes()) { if (!ruleExitAction.ruleActionParams().hasParam(ifaceActionParamType.name())) { - qCWarning(dcRuleEngine()) << "Cannot create rule. Interface action" << iface.name() << ":" << ruleExitAction.interfaceAction() << "requires a" << ifaceActionParamType.name() << "param of type" << QVariant::typeToName(ifaceActionParamType.type()); + qCWarning(dcRuleEngine()) << "Cannot create rule. Interface action" << iface.name() << ":" << ruleExitAction.interfaceAction() << "requires a" << ifaceActionParamType.name() << "param of type" << QVariant::typeToName(static_cast(ifaceActionParamType.type())); return RuleError::RuleErrorMissingParameter; } - if (!ruleExitAction.ruleActionParam(ifaceActionParamType.name()).value().canConvert(ifaceActionParamType.type())) { - qCWarning(dcRuleEngine()) << "Cannot create rule. Interface action parameter" << iface.name() << ":" << ruleExitAction.interfaceAction() << ":" << ifaceActionParamType.name() << "has wrong type. Expected" << QVariant::typeToName(ifaceActionParamType.type()); + if (!ruleExitAction.ruleActionParam(ifaceActionParamType.name()).value().canConvert(static_cast(ifaceActionParamType.type()))) { + qCWarning(dcRuleEngine()) << "Cannot create rule. Interface action parameter" << iface.name() << ":" << ruleExitAction.interfaceAction() << ":" << ifaceActionParamType.name() << "has wrong type. Expected" << QVariant::typeToName(static_cast(ifaceActionParamType.type())); return RuleError::RuleErrorInvalidParameter; } } @@ -528,7 +528,7 @@ RuleEngine::RuleError RuleEngine::addRule(const Rule &rule, bool fromEdit) qCWarning(dcRuleEngine) << "Cannot create rule. Exit actions cannot be event based."; return RuleErrorInvalidRuleActionParameter; } else if (ruleActionParam.isStateBased()) { - Device *d = NymeaCore::instance()->deviceManager()->findConfiguredDevice(ruleActionParam.deviceId()); + Device *d = NymeaCore::instance()->deviceManager()->findConfiguredDevice(ruleActionParam.stateDeviceId()); if (!d) { qCWarning(dcRuleEngine()) << "Cannot create Rule. DeviceId from RuleAction" << ruleExitAction.actionTypeId() << "not found in system."; return RuleErrorDeviceNotFound; @@ -1192,7 +1192,7 @@ void RuleEngine::saveRule(const Rule &rule) } else { settings.beginGroup("ParamDescriptor-" + paramDescriptor.paramName()); } - settings.setValue("valueType", (int)paramDescriptor.value().type()); + settings.setValue("valueType", static_cast(paramDescriptor.value().type())); settings.setValue("value", paramDescriptor.value()); settings.setValue("operator", paramDescriptor.operatorType()); settings.endGroup(); @@ -1228,7 +1228,7 @@ void RuleEngine::saveRule(const Rule &rule) settings.setValue("eventTypeId", param.eventTypeId().toString()); settings.setValue("eventParamTypeId", param.eventParamTypeId()); } else if (param.isStateBased()) { - settings.setValue("deviceId", param.deviceId().toString()); + settings.setValue("stateDeviceId", param.stateDeviceId().toString()); settings.setValue("stateTypeId", param.stateTypeId()); } settings.endGroup(); @@ -1256,7 +1256,7 @@ void RuleEngine::saveRule(const Rule &rule) } else { settings.beginGroup("RuleActionParam-" + param.paramName()); } - settings.setValue("valueType", (int)param.value().type()); + settings.setValue("valueType", static_cast(param.value().type())); settings.setValue("value", param.value()); settings.endGroup(); } @@ -1383,24 +1383,24 @@ void RuleEngine::init() QVariant value = settings.value("value"); if (settings.contains("valueType")) { - QVariant::Type valueType = (QVariant::Type)settings.value("valueType").toInt(); + QVariant::Type valueType = static_cast(settings.value("valueType").toInt()); // Note: only warn, and continue with the QVariant guessed type if (valueType == QVariant::Invalid) { qCWarning(dcRuleEngine()) << name << idString << "Could not load the value type of the param descriptor" << strippedGroupName << ". The value type will be guessed by QVariant."; - } else if (!value.canConvert(valueType)) { + } else if (!value.canConvert(static_cast(valueType))) { qCWarning(dcRuleEngine()) << "Error loading rule" << name << idString << ". Could not convert the param descriptor value" << value << "to the stored type" << valueType; } else { - value.convert(valueType); + value.convert(static_cast(valueType)); } } if (!ParamTypeId(strippedGroupName).isNull()) { ParamDescriptor paramDescriptor(ParamTypeId(strippedGroupName), value); - paramDescriptor.setOperatorType((Types::ValueOperator)settings.value("operator").toInt()); + paramDescriptor.setOperatorType(static_cast(settings.value("operator").toInt())); params.append(paramDescriptor); } else { ParamDescriptor paramDescriptor(strippedGroupName, value); - paramDescriptor.setOperatorType((Types::ValueOperator)settings.value("operator").toInt()); + paramDescriptor.setOperatorType(static_cast(settings.value("operator").toInt())); params.append(paramDescriptor); } settings.endGroup(); @@ -1436,18 +1436,18 @@ void RuleEngine::init() QString strippedParamTypeIdString = paramTypeIdString.remove(QRegExp("^RuleActionParam-")); EventTypeId eventTypeId = EventTypeId(settings.value("eventTypeId", EventTypeId()).toString()); ParamTypeId eventParamTypeId = ParamTypeId(settings.value("eventParamTypeId", ParamTypeId()).toString()); - DeviceId deviceId = DeviceId(settings.value("deviceId", DeviceId()).toString()); + DeviceId stateDeviceId = DeviceId(settings.value("stateDeviceId", DeviceId()).toString()); StateTypeId stateTypeId = StateTypeId(settings.value("stateTypeId", StateTypeId()).toString()); QVariant value = settings.value("value"); if (settings.contains("valueType")) { - QVariant::Type valueType = (QVariant::Type)settings.value("valueType").toInt(); + QVariant::Type valueType = static_cast(settings.value("valueType").toInt()); // Note: only warn, and continue with the QVariant guessed type if (valueType == QVariant::Invalid) { qCWarning(dcRuleEngine()) << name << idString << "Could not load the value type of the rule action param " << strippedParamTypeIdString << ". The value type will be guessed by QVariant."; - } else if (!value.canConvert(valueType)) { + } else if (!value.canConvert(static_cast(valueType))) { qCWarning(dcRuleEngine()) << "Error loading rule" << name << idString << ". Could not convert the rule action param value" << value << "to the stored type" << valueType; } else { - value.convert(valueType); + value.convert(static_cast(valueType)); } } @@ -1461,7 +1461,7 @@ void RuleEngine::init() } param.setEventTypeId(eventTypeId); param.setEventParamTypeId(eventParamTypeId); - param.setDeviceId(deviceId); + param.setStateDeviceId(stateDeviceId); param.setStateTypeId(stateTypeId); params.append(param); params.append(param); @@ -1496,14 +1496,14 @@ void RuleEngine::init() QString strippedParamTypeIdString = paramTypeIdString.remove(QRegExp("^RuleActionParam-")); QVariant value = settings.value("value"); if (settings.contains("valueType")) { - QVariant::Type valueType = (QVariant::Type)settings.value("valueType").toInt(); + QVariant::Type valueType = static_cast(settings.value("valueType").toInt()); // Note: only warn, and continue with the QVariant guessed type if (valueType == QVariant::Invalid) { qCWarning(dcRuleEngine()) << name << idString << "Could not load the value type of the rule action param " << strippedParamTypeIdString << ". The value type will be guessed by QVariant."; - } else if (!value.canConvert(valueType)) { + } else if (!value.canConvert(static_cast(valueType))) { qCWarning(dcRuleEngine()) << "Error loading rule" << name << idString << ". Could not convert the rule action param value" << value << "to the stored type" << valueType; } else { - value.convert(valueType); + value.convert(static_cast(valueType)); } } diff --git a/libnymea/types/ruleactionparam.cpp b/libnymea/types/ruleactionparam.cpp index 91737fae..31c92b50 100644 --- a/libnymea/types/ruleactionparam.cpp +++ b/libnymea/types/ruleactionparam.cpp @@ -79,11 +79,11 @@ RuleActionParam::RuleActionParam(const ParamTypeId ¶mTypeId, const EventType } -/*! Constructs a \l{RuleActionParam} with the given \a paramTypeId, \a deviceId and \a stateTypeId. +/*! Constructs a \l{RuleActionParam} with the given \a paramTypeId, \a stateDeviceId and \a stateTypeId. * \sa Param, Event, */ -RuleActionParam::RuleActionParam(const ParamTypeId ¶mTypeId, const DeviceId &deviceId, const StateTypeId &stateTypeId): +RuleActionParam::RuleActionParam(const ParamTypeId ¶mTypeId, const DeviceId &stateDeviceId, const StateTypeId &stateTypeId): m_paramTypeId(paramTypeId), - m_deviceId(deviceId), + m_stateDeviceId(stateDeviceId), m_stateTypeId(stateTypeId) { @@ -108,11 +108,11 @@ RuleActionParam::RuleActionParam(const QString ¶mName, const EventTypeId &ev } -/*! Constructs a \l{RuleActionParam} with the given \a paramName, \a deviceId and \a stateTypeId. +/*! Constructs a \l{RuleActionParam} with the given \a paramName, \a stateDeviceId and \a stateTypeId. * \sa Param, Event, */ -RuleActionParam::RuleActionParam(const QString ¶mName, const DeviceId &deviceId, const StateTypeId &stateTypeId): +RuleActionParam::RuleActionParam(const QString ¶mName, const DeviceId &stateDeviceId, const StateTypeId &stateTypeId): m_paramName(paramName), - m_deviceId(deviceId), + m_stateDeviceId(stateDeviceId), m_stateTypeId(stateTypeId) { @@ -167,15 +167,15 @@ void RuleActionParam::setEventParamTypeId(const ParamTypeId &eventParamTypeId) } /*! Returns the deviceId identifying the device to use a state value from. */ -DeviceId RuleActionParam::deviceId() const +DeviceId RuleActionParam::stateDeviceId() const { - return m_deviceId; + return m_stateDeviceId; } /*! Sets the deviceId identifying the device to use a state value from. */ -void RuleActionParam::setDeviceId(const DeviceId &deviceId) +void RuleActionParam::setStateDeviceId(const DeviceId &stateDeviceId) { - m_deviceId = deviceId; + m_stateDeviceId = stateDeviceId; } /*! Returns the stateTypeId identifying the state to use the value. */ @@ -211,7 +211,7 @@ bool RuleActionParam::isEventBased() const bool RuleActionParam::isStateBased() const { - return !m_deviceId.isNull() && !m_stateTypeId.isNull(); + return !m_stateDeviceId.isNull() && !m_stateTypeId.isNull(); } /*! Writes the paramTypeId, value, eventId and eventParamTypeId of the given \a ruleActionParam to \a dbg. */ diff --git a/libnymea/types/ruleactionparam.h b/libnymea/types/ruleactionparam.h index efbfd71f..20257546 100644 --- a/libnymea/types/ruleactionparam.h +++ b/libnymea/types/ruleactionparam.h @@ -38,10 +38,10 @@ public: RuleActionParam(const Param ¶m = Param()); RuleActionParam(const ParamTypeId ¶mTypeId, const QVariant &value = QVariant()); RuleActionParam(const ParamTypeId ¶mTypeId, const EventTypeId &eventTypeId, const ParamTypeId &eventParamTypeId); - RuleActionParam(const ParamTypeId ¶mTypeId, const DeviceId &deviceId, const StateTypeId &stateTypeId); + RuleActionParam(const ParamTypeId ¶mTypeId, const DeviceId &stateDeviceId, const StateTypeId &stateTypeId); RuleActionParam(const QString ¶mName, const QVariant &value = QVariant()); RuleActionParam(const QString ¶mName, const EventTypeId &eventTypeId, const ParamTypeId &eventParamTypeId); - RuleActionParam(const QString ¶mName, const DeviceId &deviceId, const StateTypeId &stateTypeId); + RuleActionParam(const QString ¶mName, const DeviceId &stateDeviceId, const StateTypeId &stateTypeId); ParamTypeId paramTypeId() const; QString paramName() const; @@ -60,8 +60,8 @@ public: ParamTypeId eventParamTypeId() const; void setEventParamTypeId(const ParamTypeId &eventParamTypeId); - DeviceId deviceId() const; - void setDeviceId(const DeviceId &deviceId); + DeviceId stateDeviceId() const; + void setStateDeviceId(const DeviceId &deviceId); StateTypeId stateTypeId() const; void setStateTypeId(const StateTypeId &stateTypeId); @@ -74,7 +74,7 @@ private: EventTypeId m_eventTypeId; ParamTypeId m_eventParamTypeId; - DeviceId m_deviceId; + DeviceId m_stateDeviceId; StateTypeId m_stateTypeId; }; From 5fcfe1a11c9609b0fec1511e7d8478376983f75a Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Thu, 28 Mar 2019 13:04:27 +0100 Subject: [PATCH 3/5] Update removeConfiguredDevice to update rules as appropriate --- libnymea-core/ruleengine.cpp | 33 ++++++++++++++++++++++++++++++++- tests/auto/rules/testrules.cpp | 1 - 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/libnymea-core/ruleengine.cpp b/libnymea-core/ruleengine.cpp index 524fca02..be772004 100644 --- a/libnymea-core/ruleengine.cpp +++ b/libnymea-core/ruleengine.cpp @@ -809,6 +809,15 @@ QList RuleEngine::findRules(const DeviceId &deviceId) const offending = true; break; } + foreach (const RuleActionParam &ruleActionParam, action.ruleActionParams()) { + if (ruleActionParam.stateDeviceId() == deviceId) { + offending = true; + break; + } + } + if (offending) { + break; + } } } @@ -818,6 +827,15 @@ QList RuleEngine::findRules(const DeviceId &deviceId) const offending = true; break; } + foreach (const RuleActionParam &ruleActionParam, action.ruleActionParams()) { + if (ruleActionParam.stateDeviceId() == deviceId) { + offending = true; + break; + } + } + if (offending) { + break; + } } } @@ -886,6 +904,13 @@ void RuleEngine::removeDeviceFromRule(const RuleId &id, const DeviceId &deviceId for (int i = 0; i < actions.count(); i++) { if (actions.at(i).deviceId() == deviceId) { removeIndexes.append(i); + continue; + } + foreach (const RuleActionParam ¶m, actions.at(i).ruleActionParams()) { + if (param.stateDeviceId() == deviceId) { + removeIndexes.append(i); + break; + } } } while (removeIndexes.count() > 0) { @@ -897,6 +922,13 @@ void RuleEngine::removeDeviceFromRule(const RuleId &id, const DeviceId &deviceId for (int i = 0; i < exitActions.count(); i++) { if (exitActions.at(i).deviceId() == deviceId) { removeIndexes.append(i); + continue; + } + foreach (const RuleActionParam ¶m, exitActions.at(i).ruleActionParams()) { + if (param.stateDeviceId() == deviceId) { + removeIndexes.append(i); + break; + } } } while (removeIndexes.count() > 0) { @@ -1464,7 +1496,6 @@ void RuleEngine::init() param.setStateDeviceId(stateDeviceId); param.setStateTypeId(stateTypeId); params.append(param); - params.append(param); settings.endGroup(); } } diff --git a/tests/auto/rules/testrules.cpp b/tests/auto/rules/testrules.cpp index c4efee05..ced4bc1e 100644 --- a/tests/auto/rules/testrules.cpp +++ b/tests/auto/rules/testrules.cpp @@ -119,7 +119,6 @@ private slots: void testHousekeeping_data(); void testHousekeeping(); - }; void TestRules::cleanupMockHistory() { From 694d78225dee5f81f5c83c8af2da89785fe8f871 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sun, 7 Apr 2019 20:40:38 +0200 Subject: [PATCH 4/5] update api --- tests/auto/api.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/auto/api.json b/tests/auto/api.json index 09637c65..4ad90a2a 100644 --- a/tests/auto/api.json +++ b/tests/auto/api.json @@ -1553,6 +1553,8 @@ "o:eventTypeId": "Uuid", "o:paramName": "String", "o:paramTypeId": "Uuid", + "o:stateDeviceId": "Uuid", + "o:stateTypeId": "Uuid", "o:value": "$ref:BasicType" }, "RuleDescription": { From 299052d2f7ccc9666b6ec30bdbfcfd16a1f55fe7 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sun, 7 Apr 2019 23:15:13 +0200 Subject: [PATCH 5/5] Fix processing of rule action params and make tests pass again --- libnymea-core/ruleengine.cpp | 308 ++++++++++++----------------- libnymea-core/ruleengine.h | 4 +- libnymea/types/actiontype.h | 2 +- libnymea/types/eventdescriptor.cpp | 5 + libnymea/types/eventdescriptor.h | 1 + tests/auto/rules/testrules.cpp | 32 ++- 6 files changed, 164 insertions(+), 188 deletions(-) diff --git a/libnymea-core/ruleengine.cpp b/libnymea-core/ruleengine.cpp index be772004..e73752de 100644 --- a/libnymea-core/ruleengine.cpp +++ b/libnymea-core/ruleengine.cpp @@ -383,184 +383,18 @@ RuleEngine::RuleError RuleEngine::addRule(const Rule &rule, bool fromEdit) // Check actions - foreach (const RuleAction &action, rule.actions()) { - if (!action.isValid()) { - qWarning(dcRuleEngine()) << "Action is incomplete. It must have either actionTypeId and deviceId, or interface and interfaceAction"; - return RuleErrorActionTypeNotFound; - } - if (action.type() == RuleAction::TypeDevice) { - Device *device = NymeaCore::instance()->deviceManager()->findConfiguredDevice(action.deviceId()); - if (!device) { - qCWarning(dcRuleEngine) << "Cannot create rule. No configured device for action with actionTypeId" << action.actionTypeId(); - return RuleErrorDeviceNotFound; - } - - DeviceClass deviceClass = NymeaCore::instance()->deviceManager()->findDeviceClass(device->deviceClassId()); - if (!deviceClass.hasActionType(action.actionTypeId())) { - qCWarning(dcRuleEngine) << "Cannot create rule. Device " + device->name() + " has no action type:" << action.actionTypeId(); - return RuleErrorActionTypeNotFound; - } - - } else { // Is TypeInterface - Interface iface = NymeaCore::instance()->deviceManager()->supportedInterfaces().findByName(action.interface()); - if (!iface.isValid()) { - qCWarning(dcRuleEngine()) << "Cannot create rule. No such interface:" << action.interface(); - return RuleError::RuleErrorInterfaceNotFound; - } - ActionType ifaceActionType = iface.actionTypes().findByName(action.interfaceAction()); - if (ifaceActionType.name().isEmpty()) { - qCWarning(dcRuleEngine()) << "Cannot create rule. Interface" << iface.name() << "does not implement action" << action.interfaceAction(); - return RuleError::RuleErrorActionTypeNotFound; - } - foreach (const ParamType &ifaceActionParamType, ifaceActionType.paramTypes()) { - if (!action.ruleActionParams().hasParam(ifaceActionParamType.name())) { - qCWarning(dcRuleEngine()) << "Cannot create rule. Interface action" << iface.name() << ":" << action.interfaceAction() << "requires a" << ifaceActionParamType.name() << "param of type" << QVariant::typeToName(static_cast(ifaceActionParamType.type())); - return RuleError::RuleErrorMissingParameter; - } - if (!action.ruleActionParam(ifaceActionParamType.name()).value().canConvert(static_cast(ifaceActionParamType.type()))) { - qCWarning(dcRuleEngine()) << "Cannot create rule. Interface action parameter" << iface.name() << ":" << action.interfaceAction() << ":" << ifaceActionParamType.name() << "has wrong type. Expected" << QVariant::typeToName(static_cast(ifaceActionParamType.type())); - return RuleError::RuleErrorInvalidParameter; - } - } - } - - foreach (const RuleActionParam &ruleActionParam, action.ruleActionParams()) { - if (ruleActionParam.isEventBased()) { - // We have an eventTypeId, see if the rule actually has such a event - if (rule.eventDescriptors().isEmpty() || !checkEventDescriptors(rule.eventDescriptors(), ruleActionParam.eventTypeId())) { - qCWarning(dcRuleEngine) << "Cannot create rule. EventTypeId from RuleAction" << action.actionTypeId() << "not in eventDescriptors."; - return RuleErrorInvalidRuleActionParameter; - } - - // check if the param type of the event and the action match - QVariant::Type eventParamType = getEventParamType(ruleActionParam.eventTypeId(), ruleActionParam.eventParamTypeId()); - QVariant v(eventParamType); - QVariant::Type actionParamType = getActionParamType(action.actionTypeId(), ruleActionParam.paramTypeId()); - if (eventParamType != actionParamType && !v.canConvert(static_cast(actionParamType))) { - qCWarning(dcRuleEngine) << "Cannot create rule. RuleActionParam" << ruleActionParam.paramTypeId().toString() << " and given event param " << ruleActionParam.eventParamTypeId().toString() << "have not the same type:"; - qCWarning(dcRuleEngine) << " -> actionParamType:" << actionParamType; - qCWarning(dcRuleEngine) << " -> eventParamType:" << eventParamType; - return RuleErrorTypesNotMatching; - } - } else if (ruleActionParam.isStateBased()) { - Device *d = NymeaCore::instance()->deviceManager()->findConfiguredDevice(ruleActionParam.stateDeviceId()); - if (!d) { - qCWarning(dcRuleEngine()) << "Cannot create Rule. DeviceId from RuleAction" << action.actionTypeId() << "not found in system."; - return RuleErrorDeviceNotFound; - } - DeviceClass stateDeviceClass = NymeaCore::instance()->deviceManager()->findDeviceClass(d->deviceClassId()); - StateType stateType = stateDeviceClass.stateTypes().findById(ruleActionParam.stateTypeId()); - QVariant::Type actionParamType = getActionParamType(action.actionTypeId(), ruleActionParam.paramTypeId()); - QVariant v(stateType.type()); - if (actionParamType != stateType.type() && !v.canConvert(static_cast(actionParamType))) { - qCWarning(dcRuleEngine) << "Cannot create rule. RuleActionParam" << ruleActionParam.paramTypeId().toString() << " and given state based param " << ruleActionParam.stateTypeId().toString() << "have not the same type:"; - qCWarning(dcRuleEngine) << " -> actionParamType:" << actionParamType; - qCWarning(dcRuleEngine) << " -> stateType:" << stateType.type(); - return RuleErrorTypesNotMatching; - } - } else { - if (ruleActionParam.value().isNull()) { - qCDebug(dcRuleEngine()) << "Cannot create rule. No param value given for action:" << ruleActionParam.paramTypeId().toString(); - return RuleErrorInvalidRuleActionParameter; - } - QVariant::Type actionParamType = getActionParamType(action.actionTypeId(), ruleActionParam.paramTypeId()); - if (ruleActionParam.value().type() != actionParamType && !ruleActionParam.value().canConvert(static_cast(actionParamType))) { - qCDebug(dcRuleEngine()) << "Cannot create rule. Given param value for action" << ruleActionParam.paramTypeId().toString() << "does not match type"; - return RuleErrorInvalidRuleActionParameter; - } - } - } - - foreach (const RuleActionParam &ruleActionParam, action.ruleActionParams()) { - if (!ruleActionParam.isValid()) { - qCWarning(dcRuleEngine) << "Cannot create rule. There must be only one out of \"value\", \"eventTypeId/eventParamTypeID\" or \"deviceId/stateTypeId\"."; - return RuleEngine::RuleErrorInvalidRuleActionParameter; - } + foreach (const RuleAction &ruleAction, rule.actions()) { + RuleError ruleActionError = checkRuleAction(ruleAction, rule); + if (ruleActionError != RuleErrorNoError) { + return ruleActionError; } } // Check exit actions foreach (const RuleAction &ruleExitAction, rule.exitActions()) { - if (!ruleExitAction.isValid()) { - qWarning(dcRuleEngine()) << "Exit Action is incomplete. It must have either actionTypeId and deviceId, or interface and interfaceAction"; - return RuleErrorActionTypeNotFound; - } - - if (ruleExitAction.type() == RuleAction::TypeDevice) { - Device *device = NymeaCore::instance()->deviceManager()->findConfiguredDevice(ruleExitAction.deviceId()); - if (!device) { - qCWarning(dcRuleEngine) << "Cannot create rule. No configured device for exit action with actionTypeId" << ruleExitAction.actionTypeId(); - return RuleErrorDeviceNotFound; - } - - DeviceClass deviceClass = NymeaCore::instance()->deviceManager()->findDeviceClass(device->deviceClassId()); - if (!deviceClass.hasActionType(ruleExitAction.actionTypeId())) { - qCWarning(dcRuleEngine) << "Cannot create rule. Device " + device->name() + " has no action type:" << ruleExitAction.actionTypeId(); - return RuleErrorActionTypeNotFound; - } - - } else { // Is TypeInterface - Interface iface = NymeaCore::instance()->deviceManager()->supportedInterfaces().findByName(ruleExitAction.interface()); - if (!iface.isValid()) { - qCWarning(dcRuleEngine()) << "Cannot create rule. No such interface:" << ruleExitAction.interface(); - return RuleError::RuleErrorInterfaceNotFound; - } - ActionType ifaceActionType = iface.actionTypes().findByName(ruleExitAction.interfaceAction()); - if (ifaceActionType.name().isEmpty()) { - qCWarning(dcRuleEngine()) << "Cannot create rule. Interface" << iface.name() << "does not implement action" << ruleExitAction.interfaceAction(); - return RuleError::RuleErrorActionTypeNotFound; - } - foreach (const ParamType &ifaceActionParamType, ifaceActionType.paramTypes()) { - if (!ruleExitAction.ruleActionParams().hasParam(ifaceActionParamType.name())) { - qCWarning(dcRuleEngine()) << "Cannot create rule. Interface action" << iface.name() << ":" << ruleExitAction.interfaceAction() << "requires a" << ifaceActionParamType.name() << "param of type" << QVariant::typeToName(static_cast(ifaceActionParamType.type())); - return RuleError::RuleErrorMissingParameter; - } - if (!ruleExitAction.ruleActionParam(ifaceActionParamType.name()).value().canConvert(static_cast(ifaceActionParamType.type()))) { - qCWarning(dcRuleEngine()) << "Cannot create rule. Interface action parameter" << iface.name() << ":" << ruleExitAction.interfaceAction() << ":" << ifaceActionParamType.name() << "has wrong type. Expected" << QVariant::typeToName(static_cast(ifaceActionParamType.type())); - return RuleError::RuleErrorInvalidParameter; - } - } - } - - foreach (const RuleActionParam &ruleActionParam, ruleExitAction.ruleActionParams()) { - if (ruleActionParam.isEventBased()) { - // We have an eventTypeId, see if the rule actually has such a event - qCWarning(dcRuleEngine) << "Cannot create rule. Exit actions cannot be event based."; - return RuleErrorInvalidRuleActionParameter; - } else if (ruleActionParam.isStateBased()) { - Device *d = NymeaCore::instance()->deviceManager()->findConfiguredDevice(ruleActionParam.stateDeviceId()); - if (!d) { - qCWarning(dcRuleEngine()) << "Cannot create Rule. DeviceId from RuleAction" << ruleExitAction.actionTypeId() << "not found in system."; - return RuleErrorDeviceNotFound; - } - DeviceClass stateDeviceClass = NymeaCore::instance()->deviceManager()->findDeviceClass(d->deviceClassId()); - StateType stateType = stateDeviceClass.stateTypes().findById(ruleActionParam.stateTypeId()); - QVariant::Type actionParamType = getActionParamType(ruleExitAction.actionTypeId(), ruleActionParam.paramTypeId()); - QVariant v(stateType.type()); - if (actionParamType != stateType.type() && !v.canConvert(static_cast(actionParamType))) { - qCWarning(dcRuleEngine) << "Cannot create rule. RuleActionParam" << ruleActionParam.paramTypeId().toString() << " and given state based param " << ruleActionParam.stateTypeId().toString() << "have not the same type:"; - qCWarning(dcRuleEngine) << " -> actionParamType:" << actionParamType; - qCWarning(dcRuleEngine) << " -> stateType:" << stateType.type(); - return RuleErrorTypesNotMatching; - } - } else { - if (ruleActionParam.value().isNull()) { - qCDebug(dcRuleEngine()) << "Cannot create rule. No param value given for action:" << ruleActionParam.paramTypeId().toString(); - return RuleErrorInvalidRuleActionParameter; - } - QVariant::Type actionParamType = getActionParamType(ruleExitAction.actionTypeId(), ruleActionParam.paramTypeId()); - if (ruleActionParam.value().type() != actionParamType && !ruleActionParam.value().canConvert(static_cast(actionParamType))) { - qCDebug(dcRuleEngine()) << "Cannot create rule. Given param value for action" << ruleActionParam.paramTypeId().toString() << "does not match type"; - return RuleErrorInvalidRuleActionParameter; - } - } - } - - foreach (const RuleActionParam &ruleActionParam, ruleExitAction.ruleActionParams()) { - if (!ruleActionParam.isValid()) { - qCWarning(dcRuleEngine) << "Cannot create rule. There must be only one out of \"value\", \"eventTypeId/eventParamTypeID\" or \"deviceId/stateTypeId\"."; - return RuleEngine::RuleErrorInvalidRuleActionParameter; - } + RuleError ruleActionError = checkRuleAction(ruleExitAction, rule); + if (ruleActionError != RuleErrorNoError) { + return ruleActionError; } } @@ -1074,15 +908,133 @@ bool RuleEngine::containsState(const StateEvaluator &stateEvaluator, const Event return false; } -bool RuleEngine::checkEventDescriptors(const QList eventDescriptors, const EventTypeId &eventTypeId) +RuleEngine::RuleError RuleEngine::checkRuleAction(const RuleAction &ruleAction, const Rule &rule) { - foreach (const EventDescriptor eventDescriptor, eventDescriptors) { - if (eventDescriptor.eventTypeId() == eventTypeId) { - return true; + if (!ruleAction.isValid()) { + qWarning(dcRuleEngine()) << "Action is incomplete. It must have either actionTypeId and deviceId, or interface and interfaceAction"; + return RuleErrorActionTypeNotFound; + } + + ActionType actionType; + if (ruleAction.type() == RuleAction::TypeDevice) { + Device *device = NymeaCore::instance()->deviceManager()->findConfiguredDevice(ruleAction.deviceId()); + if (!device) { + qCWarning(dcRuleEngine) << "Cannot create rule. No configured device for action with actionTypeId" << ruleAction.actionTypeId(); + return RuleErrorDeviceNotFound; + } + + DeviceClass deviceClass = NymeaCore::instance()->deviceManager()->findDeviceClass(device->deviceClassId()); + if (!deviceClass.hasActionType(ruleAction.actionTypeId())) { + qCWarning(dcRuleEngine) << "Cannot create rule. Device " + device->name() + " has no action type:" << ruleAction.actionTypeId(); + return RuleErrorActionTypeNotFound; + } + + actionType = deviceClass.actionTypes().findById(ruleAction.actionTypeId()); + } else if (ruleAction.type() == RuleAction::TypeInterface) { + Interface iface = NymeaCore::instance()->deviceManager()->supportedInterfaces().findByName(ruleAction.interface()); + if (!iface.isValid()) { + qCWarning(dcRuleEngine()) << "Cannot create rule. No such interface:" << ruleAction.interface(); + return RuleError::RuleErrorInterfaceNotFound; + } + actionType = iface.actionTypes().findByName(ruleAction.interfaceAction()); + if (actionType.name().isEmpty()) { + qCWarning(dcRuleEngine()) << "Cannot create rule. Interface" << iface.name() << "does not implement action" << ruleAction.interfaceAction(); + return RuleError::RuleErrorActionTypeNotFound; + } + } else { + return RuleErrorActionTypeNotFound; + } + + // Verify given params + foreach (const RuleActionParam &ruleActionParam, ruleAction.ruleActionParams()) { + RuleError ruleActionParamError = checkRuleActionParam(ruleActionParam, actionType, rule); + if (ruleActionParamError != RuleErrorNoError) { + return ruleActionParamError; } } - return false; + // Verify all required params are given + foreach (const ParamType ¶mType, actionType.paramTypes()) { + bool found = false; + foreach (const RuleActionParam &ruleActionParam, ruleAction.ruleActionParams()) { + if (ruleActionParam.paramTypeId() == paramType.id() + || ruleActionParam.paramName() == paramType.name()) { + found = true; + break; + } + } + if (!found) { + return RuleErrorMissingParameter; + } + } + + return RuleErrorNoError; +} + +RuleEngine::RuleError RuleEngine::checkRuleActionParam(const RuleActionParam &ruleActionParam, const ActionType &actionType, const Rule &rule) +{ + // Check param identifier (either paramTypeId or paramName) + ParamType paramType; + if (!ruleActionParam.paramTypeId().isNull()) { + paramType = actionType.paramTypes().findById(ruleActionParam.paramTypeId()); + } else if (!ruleActionParam.paramName().isEmpty()) { + paramType = actionType.paramTypes().findByName(ruleActionParam.paramName()); + } else { + return RuleErrorInvalidRuleActionParameter; + } + + if (ruleActionParam.isEventBased()) { + // We have an eventTypeId, see if the rule actually has such a event + bool found = false; + foreach (const EventDescriptor &ed, rule.eventDescriptors()) { + if (ed.eventTypeId() == ruleActionParam.eventTypeId()) { + found = true; + } + } + if (!found) { + qCWarning(dcRuleEngine) << "Cannot create rule. EventTypeId" << ruleActionParam.eventTypeId() << "not found in rule's eventDescriptors."; + return RuleErrorInvalidRuleActionParameter; + } + + // check if the param type of the event and the action match + QVariant::Type eventParamType = getEventParamType(ruleActionParam.eventTypeId(), ruleActionParam.eventParamTypeId()); + QVariant v(eventParamType); + if (eventParamType != paramType.type() && !v.canConvert(static_cast(paramType.type()))) { + qCWarning(dcRuleEngine) << "Cannot create rule. RuleActionParam" << ruleActionParam.paramTypeId().toString() << " and given event param " << ruleActionParam.eventParamTypeId().toString() << "have not the same type:"; + qCWarning(dcRuleEngine) << " -> actionParamType:" << paramType.type(); + qCWarning(dcRuleEngine) << " -> eventParamType:" << eventParamType; + return RuleErrorTypesNotMatching; + } + } else if (ruleActionParam.isStateBased()) { + Device *d = NymeaCore::instance()->deviceManager()->findConfiguredDevice(ruleActionParam.stateDeviceId()); + if (!d) { + qCWarning(dcRuleEngine()) << "Cannot create Rule. DeviceId from RuleActionParam" << ruleActionParam.paramTypeId() << "not found in system."; + return RuleErrorDeviceNotFound; + } + DeviceClass stateDeviceClass = NymeaCore::instance()->deviceManager()->findDeviceClass(d->deviceClassId()); + StateType stateType = stateDeviceClass.stateTypes().findById(ruleActionParam.stateTypeId()); + QVariant::Type actionParamType = getActionParamType(actionType.id(), ruleActionParam.paramTypeId()); + QVariant v(stateType.type()); + if (actionParamType != stateType.type() && !v.canConvert(static_cast(actionParamType))) { + qCWarning(dcRuleEngine) << "Cannot create rule. RuleActionParam" << ruleActionParam.paramTypeId().toString() << " and given state based param " << ruleActionParam.stateTypeId().toString() << "have not the same type:"; + qCWarning(dcRuleEngine) << " -> actionParamType:" << actionParamType; + qCWarning(dcRuleEngine) << " -> stateType:" << stateType.type(); + return RuleErrorTypesNotMatching; + } + } else { // Is value based + if (ruleActionParam.value().isNull()) { + qCDebug(dcRuleEngine()) << "Cannot create rule. No param value given for action:" << ruleActionParam.paramTypeId().toString(); + return RuleErrorInvalidRuleActionParameter; + } + if (paramType.type() != ruleActionParam.value().type() && !ruleActionParam.value().canConvert(static_cast(paramType.type()))) { + qCWarning(dcRuleEngine) << "Cannot create rule. RuleActionParam" << ruleActionParam.paramTypeId().toString() << " and given state based param " << ruleActionParam.stateTypeId().toString() << "have not the same type:"; + qCWarning(dcRuleEngine) << " -> actionParamType:" << paramType.type(); + qCWarning(dcRuleEngine) << " -> stateType:" << ruleActionParam.value().type(); + return RuleErrorTypesNotMatching; + } + } + + return RuleErrorNoError; } QVariant::Type RuleEngine::getActionParamType(const ActionTypeId &actionTypeId, const ParamTypeId ¶mTypeId) diff --git a/libnymea-core/ruleengine.h b/libnymea-core/ruleengine.h index a5aa8219..40369712 100644 --- a/libnymea-core/ruleengine.h +++ b/libnymea-core/ruleengine.h @@ -104,7 +104,9 @@ private: bool containsEvent(const Rule &rule, const Event &event, const DeviceClassId &deviceClassId); bool containsState(const StateEvaluator &stateEvaluator, const Event &stateChangeEvent); - bool checkEventDescriptors(const QList eventDescriptors, const EventTypeId &eventTypeId); + RuleError checkRuleAction(const RuleAction &ruleAction, const Rule &rule); + RuleError checkRuleActionParam(const RuleActionParam &ruleActionParam, const ActionType &actionType, const Rule &rule); + QVariant::Type getActionParamType(const ActionTypeId &actionTypeId, const ParamTypeId ¶mTypeId); QVariant::Type getEventParamType(const EventTypeId &eventTypeId, const ParamTypeId ¶mTypeId); diff --git a/libnymea/types/actiontype.h b/libnymea/types/actiontype.h index 09eb7a25..09853a36 100644 --- a/libnymea/types/actiontype.h +++ b/libnymea/types/actiontype.h @@ -33,7 +33,7 @@ class LIBNYMEA_EXPORT ActionType { public: - ActionType(const ActionTypeId &id); + ActionType(const ActionTypeId &id = ActionTypeId()); ActionTypeId id() const; diff --git a/libnymea/types/eventdescriptor.cpp b/libnymea/types/eventdescriptor.cpp index 690f69b1..f0a2b117 100644 --- a/libnymea/types/eventdescriptor.cpp +++ b/libnymea/types/eventdescriptor.cpp @@ -49,6 +49,11 @@ #include "eventdescriptor.h" +EventDescriptor::EventDescriptor() +{ + +} + /*! Constructs an EventDescriptor describing an \l{Event} with the given \a eventTypeId, \a deviceId and the given \a paramDescriptors. */ EventDescriptor::EventDescriptor(const EventTypeId &eventTypeId, const DeviceId &deviceId, const QList ¶mDescriptors): m_eventTypeId(eventTypeId), diff --git a/libnymea/types/eventdescriptor.h b/libnymea/types/eventdescriptor.h index e1e88294..97e98f79 100644 --- a/libnymea/types/eventdescriptor.h +++ b/libnymea/types/eventdescriptor.h @@ -41,6 +41,7 @@ public: TypeInterface }; + EventDescriptor(); EventDescriptor(const EventTypeId &eventTypeId, const DeviceId &deviceId, const QList ¶mDescriptors = QList()); EventDescriptor(const QString &interface, const QString &interfaceEvent, const QList ¶mDescriptors = QList()); diff --git a/tests/auto/rules/testrules.cpp b/tests/auto/rules/testrules.cpp index ced4bc1e..f86d3a0d 100644 --- a/tests/auto/rules/testrules.cpp +++ b/tests/auto/rules/testrules.cpp @@ -1149,7 +1149,6 @@ void TestRules::loadStoreConfig() QVariantMap action2; action2.insert("actionTypeId", mockActionIdWithParams); - qDebug() << "got action id" << mockActionIdWithParams; action2.insert("deviceId", m_mockDeviceId); QVariantList action2Params; QVariantMap action2Param1; @@ -1221,6 +1220,7 @@ void TestRules::loadStoreConfig() actionsInterfaces.append(actionInterfaces); // rule 1 + qCDebug(dcTests()) << "Adding rule 1"; QVariantMap params; QVariantList actions; actions.append(action1); @@ -1235,6 +1235,7 @@ void TestRules::loadStoreConfig() verifyRuleError(response); // rule 2 + qCDebug(dcTests()) << "Adding rule 2"; QVariantMap params2; QVariantList actions2; actions2.append(action1); @@ -1250,6 +1251,7 @@ void TestRules::loadStoreConfig() verifyRuleError(response2); // rule 3 + qCDebug(dcTests()) << "Adding rule 3"; QVariantMap params3; QVariantList actions3; actions3.append(validActionEventBased); @@ -1262,6 +1264,7 @@ void TestRules::loadStoreConfig() verifyRuleError(response3); // rule 4, interface based + qCDebug(dcTests()) << "Adding rule 4"; QVariantMap params4; params4.insert("name", "TestRule4 - Interface based"); params4.insert("eventDescriptors", eventDescriptorsInterfaces); @@ -1272,10 +1275,12 @@ void TestRules::loadStoreConfig() 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"); @@ -2249,11 +2254,11 @@ void TestRules::testStateBasedAction() QVariantList ruleActionParams; QVariantMap param1; param1.insert("paramTypeId", mockActionParam1ParamTypeId); - param1.insert("deviceId", m_mockDeviceId); + param1.insert("stateDeviceId", m_mockDeviceId); param1.insert("stateTypeId", mockIntStateId); QVariantMap param2; param2.insert("paramTypeId", mockActionParam2ParamTypeId); - param2.insert("deviceId", m_mockDeviceId); + param2.insert("stateDeviceId", m_mockDeviceId); param2.insert("stateTypeId", mockBoolStateId); ruleActionParams.append(param1); ruleActionParams.append(param2); @@ -2265,7 +2270,7 @@ void TestRules::testStateBasedAction() actions.append(action); addRuleParams.insert("actions", actions); - qDebug() << addRuleParams; + qCDebug(dcTests) << "Adding rule"; QVariant response = injectAndWait("Rules.AddRule", addRuleParams); verifyRuleError(response); @@ -2469,6 +2474,7 @@ void TestRules::removePolicyUpdateRendersUselessRule() params.insert("deviceClassId", mockParentDeviceClassId); params.insert("name", "Parent device"); + qCDebug(dcTests()) << "Adding device"; QVariant response = injectAndWait("Devices.AddConfiguredDevice", params); verifyDeviceError(response); @@ -2476,6 +2482,7 @@ void TestRules::removePolicyUpdateRendersUselessRule() QVERIFY(!parentDeviceId.isNull()); // find child device + qCDebug(dcTests()) << "Gettin devices"; response = injectAndWait("Devices.GetConfiguredDevices"); QVariantList devices = response.toMap().value("params").toMap().value("devices").toList(); @@ -2506,26 +2513,34 @@ void TestRules::removePolicyUpdateRendersUselessRule() QVariantMap action; action.insert("deviceId", childDeviceId); action.insert("actionTypeId", mockParentChildActionId); + QVariantMap ruleActionParam; + ruleActionParam.insert("paramTypeId", mockParentChildActionId); + 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, DeviceManager::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, DeviceManager::DeviceErrorDeviceInRule); // Remove policy + qCDebug(dcTests()) << "Removing device with update policy"; params.clear(); response.clear(); params.insert("deviceId", parentDeviceId); params.insert("removePolicy", "RemovePolicyUpdate"); @@ -2533,6 +2548,7 @@ void TestRules::removePolicyUpdateRendersUselessRule() 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); @@ -2572,10 +2588,10 @@ void TestRules::testRuleActionParams_data() 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::RuleErrorInvalidRuleActionParameter; - QTest::newRow("invalid action params2") << invalidAction2 << QVariantMap() << RuleEngine::RuleErrorInvalidRuleActionParameter; - QTest::newRow("valid action and invalid exit action params1") << action << invalidAction1 << RuleEngine::RuleErrorInvalidRuleActionParameter; - QTest::newRow("valid action and invalid exit action params2") << action << invalidAction2 << RuleEngine::RuleErrorInvalidRuleActionParameter; + 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()