more work on rules

disallow removing a device if a rule still refers to it unless
parameters contain information on what to do with those rules.
pull/135/head
Michael Zanetti 2014-06-22 21:46:31 +02:00
parent cd67ab567b
commit be90f47f63
14 changed files with 311 additions and 49 deletions

View File

@ -78,9 +78,37 @@ QList<DeviceClass> GuhCore::supportedDevices(const VendorId &vendorId) const
return m_deviceManager->supportedDevices(vendorId);
}
QPair<DeviceManager::DeviceError, QString> GuhCore::removeConfiguredDevice(const DeviceId &deviceId)
QPair<DeviceManager::DeviceError, QString> GuhCore::removeConfiguredDevice(const DeviceId &deviceId, const QHash<RuleId, RuleEngine::RemovePolicy> &removePolicyList)
{
// TODO: make sure we don't remove a device and keep stale rules around...
QHash<RuleId, RuleEngine::RemovePolicy> toBeChanged;
QList<RuleId> unhandledRules;
foreach (const RuleId &ruleId, m_ruleEngine->findRules(deviceId)) {
bool found = false;
foreach (const RuleId &policyRuleId, removePolicyList.keys()) {
if (ruleId == policyRuleId) {
found = true;
toBeChanged.insert(ruleId, removePolicyList.value(ruleId));
break;
}
}
if (!found) {
unhandledRules.append(ruleId);
}
}
if (!unhandledRules.isEmpty()) {
return qMakePair<DeviceManager::DeviceError, QString>(DeviceManager::DeviceErrorMissingParameter, "There are unhandled rules which depend on this device.");
}
// Update the rules...
foreach (const RuleId &ruleId, toBeChanged.keys()) {
if (toBeChanged.value(ruleId) == RuleEngine::RemovePolicyCascade) {
m_ruleEngine->removeRule(ruleId);
} else if (toBeChanged.value(ruleId) == RuleEngine::RemovePolicyUpdate){
m_ruleEngine->removeDeviceFromRule(ruleId, deviceId);
}
}
return m_deviceManager->removeConfiguredDevice(deviceId);
}
@ -144,6 +172,16 @@ QList<Rule> GuhCore::rules() const
return m_ruleEngine->rules();
}
QList<RuleId> GuhCore::ruleIds() const
{
return m_ruleEngine->ruleIds();
}
Rule GuhCore::findRule(const RuleId &ruleId)
{
return m_ruleEngine->findRule(ruleId);
}
RuleEngine::RuleError GuhCore::addRule(const RuleId &id, const QList<EventDescriptor> &eventDescriptorList, const QList<Action> &actionList)
{
return m_ruleEngine->addRule(id, eventDescriptorList, actionList);
@ -154,6 +192,11 @@ RuleEngine::RuleError GuhCore::removeRule(const RuleId &id)
return m_ruleEngine->removeRule(id);
}
QList<RuleId> GuhCore::findRules(const DeviceId &deviceId)
{
return m_ruleEngine->findRules(deviceId);
}
/*! Returns a pointer to the \l{DeviceManager} instance owned by GuhCore.*/
DeviceManager *GuhCore::deviceManager() const
{

View File

@ -55,7 +55,7 @@ public:
QList<Device*> configuredDevices() const;
Device *findConfiguredDevice(const DeviceId &deviceId) const;
QList<Device*> findConfiguredDevices(const DeviceClassId &deviceClassId) const;
QPair<DeviceManager::DeviceError, QString> removeConfiguredDevice(const DeviceId &deviceId);
QPair<DeviceManager::DeviceError, QString> removeConfiguredDevice(const DeviceId &deviceId, const QHash<RuleId, RuleEngine::RemovePolicy> &removePolicyList);
QPair<DeviceManager::DeviceError, QString> pairDevice(const DeviceClassId &deviceClassId, const DeviceDescriptorId &deviceDescriptorId);
QPair<DeviceManager::DeviceError, QString> pairDevice(const DeviceClassId &deviceClassId, const QList<Param> &params);
@ -64,8 +64,11 @@ public:
QPair<DeviceManager::DeviceError, QString> executeAction(const Action &action);
QList<Rule> rules() const;
QList<RuleId> ruleIds() const;
Rule findRule(const RuleId &ruleId);
RuleEngine::RuleError addRule(const RuleId &id, const QList<EventDescriptor> &eventDescriptorList, const QList<Action> &actionList);
RuleEngine::RuleError removeRule(const RuleId &id);
QList<RuleId> findRules(const DeviceId &deviceId);
signals:
void eventTriggered(const Event &event);

View File

@ -147,6 +147,12 @@ DeviceHandler::DeviceHandler(QObject *parent) :
params.clear(); returns.clear();
setDescription("RemoveConfiguredDevice", "Remove a device from the system.");
params.insert("deviceId", "uuid");
QVariantList removePolicyList;
QVariantMap policy;
policy.insert("ruleId", "uuid");
policy.insert("policy", JsonTypes::removePolicyTypesRef());
removePolicyList.append(policy);
params.insert("o:removePolicyList", removePolicyList);
setParams("RemoveConfiguredDevice", params);
returns.insert("success", "bool");
returns.insert("errorMessage", "string");
@ -480,8 +486,16 @@ JsonReply* DeviceHandler::GetConfiguredDevices(const QVariantMap &params) const
JsonReply* DeviceHandler::RemoveConfiguredDevice(const QVariantMap &params)
{
DeviceId deviceId = DeviceId(params.value("deviceId").toString());
QHash<RuleId, RuleEngine::RemovePolicy> removePolicyList;
foreach (const QVariant &variant, params.value("removePolicyList").toList()) {
RuleId ruleId = RuleId(variant.toMap().value("ruleId").toString());
RuleEngine::RemovePolicy policy = variant.toMap().value("policy").toString() == "RemovePolicyCascade" ? RuleEngine::RemovePolicyCascade : RuleEngine::RemovePolicyUpdate;
removePolicyList.insert(ruleId, policy);
}
QVariantMap returns;
QPair<DeviceManager::DeviceError, QString> status = GuhCore::instance()->removeConfiguredDevice(DeviceId(params.value("deviceId").toString()));
QPair<DeviceManager::DeviceError, QString> status = GuhCore::instance()->removeConfiguredDevice(deviceId, removePolicyList);
switch(status.first) {
case DeviceManager::DeviceErrorNoError:
returns.insert("success", true);
@ -491,6 +505,10 @@ JsonReply* DeviceHandler::RemoveConfiguredDevice(const QVariantMap &params)
returns.insert("success", false);
returns.insert("errorMessage", QString("No such device: %1").arg(status.second));
break;
case DeviceManager::DeviceErrorMissingParameter:
returns.insert("success", false);
returns.insert("errorMessage", QString("Missing Parameter: %1").arg(status.second));
break;
default:
returns.insert("success", false);
returns.insert("errorMessage", "Unknown error.");

View File

@ -42,7 +42,7 @@
#include <QJsonDocument>
#include <QStringList>
#define JSON_PROTOCOL_VERSION 2
#define JSON_PROTOCOL_VERSION 3
JsonRPCServer::JsonRPCServer(QObject *parent):
JsonHandler(parent),

View File

@ -32,6 +32,7 @@ QVariantList JsonTypes::s_stateOperatorTypes;
QVariantList JsonTypes::s_valueOperatorTypes;
QVariantList JsonTypes::s_createMethodTypes;
QVariantList JsonTypes::s_setupMethodTypes;
QVariantList JsonTypes::s_removePolicyTypes;
QVariantMap JsonTypes::s_paramType;
QVariantMap JsonTypes::s_param;
@ -60,6 +61,7 @@ void JsonTypes::init()
s_valueOperatorTypes << "OperatorTypeEquals" << "OperatorTypeNotEquals" << "OperatorTypeLess" << "OperatorTypeGreater" << "OperatorTypeLessThan" << "OperatorTypeGreaterThan";
s_createMethodTypes << "CreateMethodUser" << "CreateMethodAuto" << "CreateMethodDiscovery";
s_setupMethodTypes << "SetupMethodJustAdd" << "SetupMethodDisplayPin" << "SetupMethodEnterPin" << "SetupMethodPushButton";
s_removePolicyTypes << "RemovePolicyCascade" << "RemovePolicyUpdate";
// ParamType
s_paramType.insert("name", "string");
@ -180,6 +182,7 @@ QVariantMap JsonTypes::allTypes()
allTypes.insert("SetupMethodType", setupMethodTypes());
allTypes.insert("ValueOperatorType", valueOperatorTypes());
allTypes.insert("StateOperatorType", stateOperatorTypes());
allTypes.insert("RemovePolicyType", removePolicyTypes());
allTypes.insert("StateType", stateTypeDescription());
allTypes.insert("StateDescriptor", stateDescriptorDescription());
allTypes.insert("StateEvaluator", stateEvaluatorDescription());

View File

@ -69,6 +69,7 @@ public:
DECLARE_TYPE(valueOperatorTypes, "ValueOperatorType")
DECLARE_TYPE(createMethodTypes, "CreateMethodType")
DECLARE_TYPE(setupMethodTypes, "SetupMethodType")
DECLARE_TYPE(removePolicyTypes, "RemovePolicyType")
DECLARE_OBJECT(paramType, "ParamType")
DECLARE_OBJECT(param, "Param")
DECLARE_OBJECT(paramDescriptor, "ParamDescriptor")

View File

@ -32,11 +32,16 @@ RulesHandler::RulesHandler(QObject *parent) :
params.clear(); returns.clear();
setDescription("GetRules", "Get all configured rules");
setParams("GetRules", params);
QVariantList rules;
rules.append(JsonTypes::ruleRef());
returns.insert("rules", rules);
returns.insert("ruleIds", QVariantList() << "uuid");
setReturns("GetRules", returns);
params.clear(); returns.clear();
setDescription("GetRuleDetails", "Get details for the rule identified by ruleId");
params.insert("ruleId", "uuid");
setParams("GetRuleDetails", params);
returns.insert("rule", JsonTypes::ruleRef());
setReturns("GetRuleDetails", returns);
params.clear(); returns.clear();
setDescription("AddRule", "Add a rule.");
params.insert("o:eventDescriptor", JsonTypes::eventDescriptorRef());
@ -58,6 +63,13 @@ RulesHandler::RulesHandler(QObject *parent) :
returns.insert("success", "bool");
returns.insert("errorMessage", "string");
setReturns("RemoveRule", returns);
params.clear(); returns.clear();
setDescription("FindRules", "Find a list of rules containing any of the given parameters.");
params.insert("deviceId", "uuid");
setParams("FindRules", params);
returns.insert("ruleIds", QVariantList() << "uuid");
setReturns("FindRules", returns);
}
QString RulesHandler::name() const
@ -70,16 +82,26 @@ JsonReply* RulesHandler::GetRules(const QVariantMap &params)
Q_UNUSED(params)
QVariantList rulesList;
foreach (const Rule &rule, GuhCore::instance()->rules()) {
QVariantMap ruleMap = JsonTypes::packRule(rule);
rulesList.append(ruleMap);
foreach (const RuleId &ruleId, GuhCore::instance()->ruleIds()) {
rulesList.append(ruleId);
}
QVariantMap returns;
returns.insert("rules", rulesList);
returns.insert("ruleIds", rulesList);
return createReply(returns);
}
JsonReply *RulesHandler::GetRuleDetails(const QVariantMap &params)
{
RuleId ruleId = RuleId(params.value("ruleId").toString());
Rule rule = GuhCore::instance()->findRule(ruleId);
QVariantMap ruleData;
if (!rule.id().isNull()) {
ruleData.insert("rule", JsonTypes::packRule(rule));
}
return createReply(ruleData);
}
JsonReply* RulesHandler::AddRule(const QVariantMap &params)
{
if (params.contains("eventDescriptor") && params.contains("eventDescriptorList")) {
@ -157,3 +179,18 @@ JsonReply* RulesHandler::RemoveRule(const QVariantMap &params)
}
return createReply(returns);
}
JsonReply *RulesHandler::FindRules(const QVariantMap &params)
{
DeviceId deviceId = DeviceId(params.value("deviceId").toString());
QList<RuleId> rules = GuhCore::instance()->findRules(deviceId);
QVariantList rulesList;
foreach (const RuleId &ruleId, rules) {
rulesList.append(ruleId);
}
QVariantMap returns;
returns.insert("ruleIds", rulesList);
return createReply(returns);
}

View File

@ -30,9 +30,11 @@ public:
QString name() const override;
Q_INVOKABLE JsonReply* GetRules(const QVariantMap &params);
Q_INVOKABLE JsonReply* GetRuleDetails(const QVariantMap &params);
Q_INVOKABLE JsonReply* AddRule(const QVariantMap &params);
Q_INVOKABLE JsonReply* RemoveRule(const QVariantMap &params);
Q_INVOKABLE JsonReply* FindRules(const QVariantMap &params);
};

View File

@ -133,7 +133,7 @@ RuleEngine::RuleEngine(QObject *parent) :
settings.endGroup();
Rule rule = Rule(RuleId(idString), eventDescriptorList, stateEvaluator, actions);
m_rules.append(rule);
appendRule(rule);
}
}
@ -149,12 +149,12 @@ QList<Action> RuleEngine::evaluateEvent(const Event &event)
qDebug() << "got event:" << event << device->name();
QList<Action> actions;
for (int i = 0; i < m_rules.count(); ++i) {
qDebug() << "evaluating rule" << i << m_rules.at(i).eventDescriptors();
if (containsEvent(m_rules.at(i), event)) {
if (m_rules.at(i).stateEvaluator().evaluate()) {
foreach (const RuleId &id, m_ruleIds) {
Rule rule = m_rules.value(id);
if (containsEvent(rule, event)) {
if (rule.stateEvaluator().evaluate()) {
qDebug() << "states matching!";
actions.append(m_rules.at(i).actions());
actions.append(rule.actions());
}
}
}
@ -220,7 +220,7 @@ RuleEngine::RuleError RuleEngine::addRule(const RuleId &ruleId, const QList<Even
}
Rule rule = Rule(ruleId, eventDescriptorList, stateEvaluator, actions);
m_rules.append(rule);
appendRule(rule);
emit ruleAdded(rule.id());
QSettings settings(m_settingsFile);
@ -263,10 +263,18 @@ RuleEngine::RuleError RuleEngine::addRule(const RuleId &ruleId, const QList<Even
return RuleErrorNoError;
}
/*! Returns a list of all \l{Rule}{Rules} loaded in this Engine.*/
/*! Returns a list of all \l{Rule}{Rules} loaded in this Engine.
Be aware that this does not necessarily reflect the order of the rules in the engine.
Use ruleIds() if you need the correct order.
*/
QList<Rule> RuleEngine::rules() const
{
return m_rules;
return m_rules.values();
}
QList<RuleId> RuleEngine::ruleIds() const
{
return m_ruleIds;
}
/*! Removes the \l{Rule} with the given \a ruleId from the Engine.
@ -274,22 +282,22 @@ QList<Rule> RuleEngine::rules() const
was successful or not. */
RuleEngine::RuleError RuleEngine::removeRule(const RuleId &ruleId)
{
for (int i = 0; i < m_rules.count(); ++i) {
Rule rule = m_rules.at(i);
if (rule.id() == ruleId) {
int index = m_ruleIds.indexOf(ruleId);
m_rules.takeAt(i);
QSettings settings(m_settingsFile);
settings.beginGroup(rule.id().toString());
settings.remove("");
settings.endGroup();
emit ruleRemoved(rule.id());
return RuleErrorNoError;
}
if (index < 0) {
return RuleErrorRuleNotFound;
}
return RuleErrorRuleNotFound;
m_ruleIds.takeAt(index);
m_rules.remove(ruleId);
QSettings settings(m_settingsFile);
settings.beginGroup(ruleId.toString());
settings.remove("");
settings.endGroup();
emit ruleRemoved(ruleId);
return RuleErrorNoError;
}
Rule RuleEngine::findRule(const RuleId &ruleId)
@ -302,6 +310,68 @@ Rule RuleEngine::findRule(const RuleId &ruleId)
return Rule();
}
QList<RuleId> RuleEngine::findRules(const DeviceId &deviceId)
{
// Find all offending rules
QList<RuleId> offendingRules;
foreach (const Rule &rule, m_rules) {
bool offending = false;
foreach (const EventDescriptor &eventDescriptor, rule.eventDescriptors()) {
if (eventDescriptor.deviceId() == deviceId) {
offending = true;
break;
}
}
if (!offending && rule.stateEvaluator().containsDevice(deviceId)) {
offending = true;
}
if (!offending) {
foreach (const Action &action, rule.actions()) {
if (action.deviceId() == deviceId) {
offending = true;
break;
}
}
}
if (offending) {
offendingRules.append(rule.id());
}
}
return offendingRules;
}
void RuleEngine::removeDeviceFromRule(const RuleId &id, const DeviceId &deviceId)
{
if (!m_rules.contains(id)) {
return;
}
Rule rule = m_rules.value(id);
QList<EventDescriptor> eventDescriptors = rule.eventDescriptors();
QList<int> removeIndexes;
for (int i = 0; i < eventDescriptors.count(); i++) {
if (eventDescriptors.at(i).deviceId() == deviceId) {
removeIndexes.append(i);
}
}
while (removeIndexes.count() > 0) {
eventDescriptors.takeAt(removeIndexes.takeLast());
}
StateEvaluator stateEvalatuator = rule.stateEvaluator();
stateEvalatuator.removeDevice(deviceId);
QList<Action> actions = rule.actions();
for (int i = 0; i < actions.count(); i++) {
if (actions.at(i).deviceId() == deviceId) {
removeIndexes.append(i);
}
}
while (removeIndexes.count() > 0) {
actions.takeAt(removeIndexes.takeLast());
}
Rule newRule(id, eventDescriptors, stateEvalatuator, actions);
m_rules[id] = newRule;
}
bool RuleEngine::containsEvent(const Rule &rule, const Event &event)
{
foreach (const EventDescriptor &eventDescriptor, rule.eventDescriptors()) {
@ -311,3 +381,9 @@ bool RuleEngine::containsEvent(const Rule &rule, const Event &event)
}
return false;
}
void RuleEngine::appendRule(const Rule &rule)
{
m_rules.insert(rule.id(), rule);
m_ruleIds.append(rule.id());
}

View File

@ -40,6 +40,11 @@ public:
RuleErrorActionTypeNotFound
};
enum RemovePolicy {
RemovePolicyCascade,
RemovePolicyUpdate
};
explicit RuleEngine(QObject *parent = 0);
QList<Action> evaluateEvent(const Event &event);
@ -47,10 +52,14 @@ public:
RuleError addRule(const RuleId &ruleId, const QList<EventDescriptor> &eventDescriptorList, const QList<Action> &actions);
RuleError addRule(const RuleId &ruleId, const QList<EventDescriptor> &eventDescriptorList, const StateEvaluator &stateEvaluator, const QList<Action> &actions);
QList<Rule> rules() const;
QList<RuleId> ruleIds() const;
RuleError removeRule(const RuleId &ruleId);
Rule findRule(const RuleId &ruleId);
QList<RuleId> findRules(const DeviceId &deviceId);
void removeDeviceFromRule(const RuleId &id, const DeviceId &deviceId);
signals:
void ruleAdded(const RuleId &ruleId);
@ -59,10 +68,12 @@ signals:
private:
bool containsEvent(const Rule &rule, const Event &event);
void appendRule(const Rule &rule);
private:
QString m_settingsFile;
QList<Rule> m_rules;
QList<RuleId> m_ruleIds; // Keeping a list of RuleIds to keep sorting order...
QHash<RuleId, Rule> m_rules; // ...but use a Hash for faster finding
};
#endif // RULEENGINE_H

View File

@ -99,6 +99,29 @@ bool StateEvaluator::evaluate() const
return true;
}
bool StateEvaluator::containsDevice(const DeviceId &deviceId) const
{
if (m_stateDescriptor.deviceId() == deviceId) {
return true;
}
foreach (const StateEvaluator &childEvaluator, m_childEvaluators) {
if (childEvaluator.containsDevice(deviceId)) {
return true;
}
}
return false;
}
void StateEvaluator::removeDevice(const DeviceId &deviceId)
{
if (m_stateDescriptor.deviceId() == deviceId) {
m_stateDescriptor = StateDescriptor();
}
for (int i = 0; i < m_childEvaluators.count(); i++) {
m_childEvaluators[i].removeDevice(deviceId);
}
}
void StateEvaluator::dumpToSettings(QSettings &settings, const QString &groupName) const
{
settings.beginGroup(groupName);

View File

@ -45,6 +45,9 @@ public:
void setOperatorType(StateOperator operatorType);
bool evaluate() const;
bool containsDevice(const DeviceId &deviceId) const;
void removeDevice(const DeviceId &deviceId);
void dumpToSettings(QSettings &settings, const QString &groupName) const;
static StateEvaluator loadFromSettings(QSettings &settings, const QString &groupPrefix);

View File

@ -1,4 +1,4 @@
2
3
{
"methods": {
"Actions.ExecuteAction": {
@ -194,7 +194,13 @@
"Devices.RemoveConfiguredDevice": {
"description": "Remove a device from the system.",
"params": {
"deviceId": "uuid"
"deviceId": "uuid",
"o:removePolicyList": [
{
"policy": "$ref:RemovePolicyType",
"ruleId": "uuid"
}
]
},
"returns": {
"errorMessage": "string",
@ -261,13 +267,33 @@
"success": "bool"
}
},
"Rules.FindRules": {
"description": "Find a list of rules containing any of the given parameters.",
"params": {
"deviceId": "uuid"
},
"returns": {
"ruleIds": [
"uuid"
]
}
},
"Rules.GetRuleDetails": {
"description": "Get details for the rule identified by ruleId",
"params": {
"ruleId": "uuid"
},
"returns": {
"rule": "$ref:Rule"
}
},
"Rules.GetRules": {
"description": "Get all configured rules",
"params": {
},
"returns": {
"rules": [
"$ref:Rule"
"ruleIds": [
"uuid"
]
}
},
@ -405,6 +431,10 @@
"$ref:Param"
]
},
"RemovePolicyType": [
"RemovePolicyCascade",
"RemovePolicyUpdate"
],
"Rule": {
"actions": [
"$ref:Action"

View File

@ -142,7 +142,7 @@ void TestRules::addRemoveRules()
RuleId newRuleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toString());
response = injectAndWait("Rules.GetRules");
QVariantList rules = response.toMap().value("params").toMap().value("rules").toList();
QVariantList rules = response.toMap().value("params").toMap().value("ruleIds").toList();
if (!success) {
QVERIFY2(rules.count() == 0, "There should be no rules.");
@ -150,10 +150,16 @@ void TestRules::addRemoveRules()
}
QVERIFY2(rules.count() == 1, "There should be exactly one rule");
QCOMPARE(RuleId(rules.first().toMap().value("id").toString()), newRuleId);
QCOMPARE(RuleId(rules.first().toString()), newRuleId);
params.clear();
params.insert("ruleId", newRuleId);
response = injectAndWait("Rules.GetRuleDetails", params);
// verifySuccess(response);
QVariantList eventDescriptors = rules.first().toMap().value("eventDescriptors").toList();
QVariantMap rule = response.toMap().value("params").toMap().value("rule").toMap();
QVariantList eventDescriptors = rule.value("eventDescriptors").toList();
if (!eventDescriptor.isEmpty()) {
QVERIFY2(eventDescriptors.count() == 1, "There shoud be exactly one eventDescriptor");
QVERIFY2(eventDescriptors.first().toMap() == eventDescriptor, "Event descriptor doesn't match");
@ -172,7 +178,7 @@ void TestRules::addRemoveRules()
}
}
QVariantList replyActions = rules.first().toMap().value("actions").toList();
QVariantList replyActions = rule.value("actions").toList();
QVERIFY2(actions == replyActions, "Actions don't match");
@ -251,12 +257,18 @@ void TestRules::loadStoreConfig()
response = injectAndWait("Rules.GetRules");
QVariantList rules = response.toMap().value("params").toMap().value("rules").toList();
QVariantList rules = response.toMap().value("params").toMap().value("ruleIds").toList();
QVERIFY2(rules.count() == 1, "There should be exactly one rule");
QCOMPARE(RuleId(rules.first().toMap().value("id").toString()), newRuleId);
QCOMPARE(RuleId(rules.first().toString()), newRuleId);
QVariantList eventDescriptors = rules.first().toMap().value("eventDescriptors").toList();
params.clear();
params.insert("ruleId", rules.first().toString());
response = injectAndWait("Rules.GetRuleDetails", params);
QVariantMap rule = response.toMap().value("params").toMap().value("rule").toMap();
QVariantList eventDescriptors = rule.value("eventDescriptors").toList();
QVERIFY2(eventDescriptors.count() == 2, "There shoud be exactly 2 eventDescriptors");
foreach (const QVariant &expectedEventDescriptorVariant, eventDescriptorList) {
bool found = false;
@ -270,7 +282,7 @@ void TestRules::loadStoreConfig()
QVERIFY2(found, "missing eventdescriptor");
}
QVariantList replyActions = rules.first().toMap().value("actions").toList();
QVariantList replyActions = rule.value("actions").toList();
foreach (const QVariant &actionVariant, actions) {
bool found = false;
foreach (const QVariant &replyActionVariant, replyActions) {