Fix an issue where Rules might not be initialized properly at startup
This commit is contained in:
parent
6f1e22546a
commit
15938cafb3
@ -767,6 +767,8 @@ void NymeaCore::onDeviceDisappeared(const DeviceId &deviceId)
|
|||||||
|
|
||||||
void NymeaCore::deviceManagerLoaded()
|
void NymeaCore::deviceManagerLoaded()
|
||||||
{
|
{
|
||||||
|
m_ruleEngine->initRuleStates();
|
||||||
|
|
||||||
// Do some houskeeping...
|
// Do some houskeeping...
|
||||||
qCDebug(dcApplication()) << "Starting housekeeping...";
|
qCDebug(dcApplication()) << "Starting housekeeping...";
|
||||||
QDateTime startTime = QDateTime::currentDateTime();
|
QDateTime startTime = QDateTime::currentDateTime();
|
||||||
|
|||||||
@ -396,7 +396,6 @@ RuleEngine::RuleEngine(QObject *parent) :
|
|||||||
rule.setExitActions(exitActions);
|
rule.setExitActions(exitActions);
|
||||||
rule.setEnabled(enabled);
|
rule.setEnabled(enabled);
|
||||||
rule.setExecutable(executable);
|
rule.setExecutable(executable);
|
||||||
rule.setStatesActive(rule.stateEvaluator().evaluate());
|
|
||||||
appendRule(rule);
|
appendRule(rule);
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
}
|
}
|
||||||
@ -467,7 +466,7 @@ QList<Rule> RuleEngine::evaluateEvent(const Event &event)
|
|||||||
qCDebug(dcRuleEngine).nospace().noquote() << "Rule " << rule.name() << " (" + rule.id().toString() << ") contains event" << event.eventId() << "and all states match.";
|
qCDebug(dcRuleEngine).nospace().noquote() << "Rule " << rule.name() << " (" + rule.id().toString() << ") contains event" << event.eventId() << "and all states match.";
|
||||||
rules.append(rule);
|
rules.append(rule);
|
||||||
} else {
|
} else {
|
||||||
qCDebug(dcRuleEngine).nospace().noquote() << "Rule " << rule.name() << " (" + rule.id().toString() << ") contains event" << event.eventId() << "but state are not matching.";
|
qCDebug(dcRuleEngine).nospace().noquote() << "Rule " << rule.name() << " (" + rule.id().toString() << ") contains event" << event.eventId() << "and states are not matching.";
|
||||||
rules.append(rule);
|
rules.append(rule);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1515,4 +1514,11 @@ void RuleEngine::saveRule(const Rule &rule)
|
|||||||
qCDebug(dcRuleEngineDebug()) << "Saved rule to config:" << rule;
|
qCDebug(dcRuleEngineDebug()) << "Saved rule to config:" << rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RuleEngine::initRuleStates()
|
||||||
|
{
|
||||||
|
foreach (const RuleId &ruleId, m_rules.keys()) {
|
||||||
|
m_rules[ruleId].setStatesActive(m_rules[ruleId].stateEvaluator().evaluate());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -68,8 +68,9 @@ public:
|
|||||||
RemovePolicyUpdate
|
RemovePolicyUpdate
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit RuleEngine(QObject *parent = 0);
|
explicit RuleEngine(QObject *parent = nullptr);
|
||||||
~RuleEngine();
|
~RuleEngine();
|
||||||
|
void initRuleStates();
|
||||||
|
|
||||||
QList<Rule> evaluateEvent(const Event &event);
|
QList<Rule> evaluateEvent(const Event &event);
|
||||||
QList<Rule> evaluateTime(const QDateTime &dateTime);
|
QList<Rule> evaluateTime(const QDateTime &dateTime);
|
||||||
|
|||||||
@ -802,7 +802,7 @@ Device *DeviceManager::findConfiguredDevice(const DeviceId &id) const
|
|||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Returns all configured \{Device}{Devices} in the system. */
|
/*! Returns all configured \{Device}{Devices} in the system. */
|
||||||
|
|||||||
@ -233,7 +233,13 @@ DeviceManager::DeviceError DevicePluginMock::executeAction(Device *device, const
|
|||||||
if (action.actionTypeId() == mockMockFailingActionTypeId)
|
if (action.actionTypeId() == mockMockFailingActionTypeId)
|
||||||
return DeviceManager::DeviceErrorSetupFailed;
|
return DeviceManager::DeviceErrorSetupFailed;
|
||||||
|
|
||||||
|
if (action.actionTypeId() == mockPowerActionTypeId) {
|
||||||
|
qCDebug(dcMockDevice()) << "Setting power to" << action.param(mockPowerActionPowerParamTypeId).value().toBool();
|
||||||
|
device->setStateValue(mockPowerStateTypeId, action.param(mockPowerActionPowerParamTypeId).value().toBool());
|
||||||
|
return DeviceManager::DeviceErrorNoError;
|
||||||
|
}
|
||||||
m_daemons.value(device)->actionExecuted(action.actionTypeId());
|
m_daemons.value(device)->actionExecuted(action.actionTypeId());
|
||||||
|
|
||||||
return DeviceManager::DeviceErrorNoError;
|
return DeviceManager::DeviceErrorNoError;
|
||||||
} else if (device->deviceClassId() == mockDeviceAutoDeviceClassId) {
|
} else if (device->deviceClassId() == mockDeviceAutoDeviceClassId) {
|
||||||
if (action.actionTypeId() == mockDeviceAutoMockActionAsyncActionTypeId || action.actionTypeId() == mockDeviceAutoMockActionAsyncBrokenActionTypeId) {
|
if (action.actionTypeId() == mockDeviceAutoMockActionAsyncActionTypeId || action.actionTypeId() == mockDeviceAutoMockActionAsyncBrokenActionTypeId) {
|
||||||
|
|||||||
@ -44,6 +44,7 @@ StateTypeId mockIntStateId = StateTypeId("80baec19-54de-4948-ac46-31eabfaceb83")
|
|||||||
StateTypeId mockBoolStateId = StateTypeId("9dd6a97c-dfd1-43dc-acbd-367932742310");
|
StateTypeId mockBoolStateId = StateTypeId("9dd6a97c-dfd1-43dc-acbd-367932742310");
|
||||||
StateTypeId mockDoubleStateId = StateTypeId("7cac53ee-7048-4dc9-b000-7b585390f34c");
|
StateTypeId mockDoubleStateId = StateTypeId("7cac53ee-7048-4dc9-b000-7b585390f34c");
|
||||||
StateTypeId mockBatteryCriticalStateId = StateTypeId("580bc611-1a55-41f3-996f-8d3ccf543db3");
|
StateTypeId mockBatteryCriticalStateId = StateTypeId("580bc611-1a55-41f3-996f-8d3ccf543db3");
|
||||||
|
StateTypeId mockPowerStateTypeId = StateTypeId("064aed0d-da4c-49d4-b236-60f97e98ff84");
|
||||||
ActionTypeId mockActionIdPower = ActionTypeId("064aed0d-da4c-49d4-b236-60f97e98ff84");
|
ActionTypeId mockActionIdPower = ActionTypeId("064aed0d-da4c-49d4-b236-60f97e98ff84");
|
||||||
ActionTypeId mockActionIdWithParams = ActionTypeId("dea0f4e1-65e3-4981-8eaa-2701c53a9185");
|
ActionTypeId mockActionIdWithParams = ActionTypeId("dea0f4e1-65e3-4981-8eaa-2701c53a9185");
|
||||||
ActionTypeId mockActionIdNoParams = ActionTypeId("defd3ed6-1a0d-400b-8879-a0202cf39935");
|
ActionTypeId mockActionIdNoParams = ActionTypeId("defd3ed6-1a0d-400b-8879-a0202cf39935");
|
||||||
|
|||||||
@ -51,6 +51,7 @@ extern StateTypeId mockIntStateId;
|
|||||||
extern StateTypeId mockDoubleStateId;
|
extern StateTypeId mockDoubleStateId;
|
||||||
extern StateTypeId mockBatteryCriticalStateId;
|
extern StateTypeId mockBatteryCriticalStateId;
|
||||||
extern StateTypeId mockBoolStateId;
|
extern StateTypeId mockBoolStateId;
|
||||||
|
extern StateTypeId mockPowerStateTypeId;
|
||||||
|
|
||||||
// ParamTypes from mock devices
|
// ParamTypes from mock devices
|
||||||
extern ParamTypeId configParamIntParamTypeId;
|
extern ParamTypeId configParamIntParamTypeId;
|
||||||
|
|||||||
@ -46,8 +46,12 @@ private:
|
|||||||
|
|
||||||
QVariant validIntStateBasedRule(const QString &name, const bool &executable, const bool &enabled);
|
QVariant validIntStateBasedRule(const QString &name, const bool &executable, const bool &enabled);
|
||||||
|
|
||||||
|
void generateEvent(const EventTypeId &eventTypeId);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
|
void initTestCase();
|
||||||
|
|
||||||
void cleanup();
|
void cleanup();
|
||||||
void emptyRule();
|
void emptyRule();
|
||||||
void getInvalidRule();
|
void getInvalidRule();
|
||||||
@ -101,6 +105,8 @@ private slots:
|
|||||||
void testRuleActionPAramsFromEventParameter_data();
|
void testRuleActionPAramsFromEventParameter_data();
|
||||||
void testRuleActionPAramsFromEventParameter();
|
void testRuleActionPAramsFromEventParameter();
|
||||||
|
|
||||||
|
void testInitStatesActive();
|
||||||
|
|
||||||
void testInterfaceBasedEventRule();
|
void testInterfaceBasedEventRule();
|
||||||
|
|
||||||
void testInterfaceBasedStateRule();
|
void testInterfaceBasedStateRule();
|
||||||
@ -349,6 +355,27 @@ QVariant TestRules::validIntStateBasedRule(const QString &name, const bool &exec
|
|||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestRules::generateEvent(const EventTypeId &eventTypeId)
|
||||||
|
{
|
||||||
|
// Trigger an event
|
||||||
|
QNetworkAccessManager nam;
|
||||||
|
QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*)));
|
||||||
|
|
||||||
|
// trigger event in mock device
|
||||||
|
QNetworkRequest request(QUrl(QString("http://localhost:%1/generateevent?eventtypeid=%2").arg(m_mockDevice1Port).arg(eventTypeId.toString())));
|
||||||
|
QNetworkReply *reply = nam.get(request);
|
||||||
|
spy.wait();
|
||||||
|
QCOMPARE(spy.count(), 1);
|
||||||
|
reply->deleteLater();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestRules::initTestCase()
|
||||||
|
{
|
||||||
|
NymeaTestBase::initTestCase();
|
||||||
|
QLoggingCategory::setFilterRules("*.debug=false\nRuleEngine.debug=true\nRuleEngineDebug.debug=true\nMockDevice.*=true");
|
||||||
|
}
|
||||||
|
|
||||||
void TestRules::addRemoveRules_data()
|
void TestRules::addRemoveRules_data()
|
||||||
{
|
{
|
||||||
// RuleAction
|
// RuleAction
|
||||||
@ -2525,6 +2552,101 @@ void TestRules::testRuleActionPAramsFromEventParameter()
|
|||||||
verifyRuleError(response, error);
|
verifyRuleError(response, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestRules::testInitStatesActive()
|
||||||
|
{
|
||||||
|
|
||||||
|
// Create a rule to toggle the power state on event 1
|
||||||
|
QVariantMap params;
|
||||||
|
params.insert("name", "testrule");
|
||||||
|
|
||||||
|
QVariantMap eventDescriptor;
|
||||||
|
eventDescriptor.insert("deviceId", m_mockDeviceId);
|
||||||
|
eventDescriptor.insert("eventTypeId", mockEvent1Id);
|
||||||
|
QVariantList eventDescriptors;
|
||||||
|
eventDescriptors.append(eventDescriptor);
|
||||||
|
params.insert("eventDescriptors", eventDescriptors);
|
||||||
|
|
||||||
|
QVariantMap stateEvaluator;
|
||||||
|
QVariantMap stateDescriptor;
|
||||||
|
stateDescriptor.insert("stateTypeId", mockPowerStateTypeId);
|
||||||
|
stateDescriptor.insert("operator", "ValueOperatorEquals");
|
||||||
|
stateDescriptor.insert("value", false);
|
||||||
|
stateDescriptor.insert("deviceId", m_mockDeviceId);
|
||||||
|
stateEvaluator.insert("stateDescriptor", stateDescriptor);
|
||||||
|
params.insert("stateEvaluator", stateEvaluator);
|
||||||
|
|
||||||
|
QVariantList actions;
|
||||||
|
QVariantMap action;
|
||||||
|
action.insert("actionTypeId", mockActionIdPower);
|
||||||
|
action.insert("deviceId", m_mockDeviceId);
|
||||||
|
QVariantList actionParams;
|
||||||
|
QVariantMap actionParam;
|
||||||
|
actionParam.insert("paramTypeId", mockActionIdPower);
|
||||||
|
actionParam.insert("value", true);
|
||||||
|
actionParams.append(actionParam);
|
||||||
|
action.insert("ruleActionParams", actionParams);
|
||||||
|
actions.append(action);
|
||||||
|
params.insert("actions", actions);
|
||||||
|
|
||||||
|
QVariantList exitActions;
|
||||||
|
QVariantMap exitAction;
|
||||||
|
exitAction.insert("actionTypeId", mockActionIdPower);
|
||||||
|
exitAction.insert("deviceId", m_mockDeviceId);
|
||||||
|
QVariantList exitActionParams;
|
||||||
|
QVariantMap exitActionParam;
|
||||||
|
exitActionParam.insert("paramTypeId", mockActionIdPower);
|
||||||
|
exitActionParam.insert("value", false);
|
||||||
|
exitActionParams.append(exitActionParam);
|
||||||
|
exitAction.insert("ruleActionParams", exitActionParams);
|
||||||
|
exitActions.append(exitAction);
|
||||||
|
params.insert("exitActions", exitActions);
|
||||||
|
|
||||||
|
QVariant response = injectAndWait("Rules.AddRule", params);
|
||||||
|
RuleId ruleId = RuleId::fromUuid(response.toMap().value("params").toMap().value("ruleId").toUuid());
|
||||||
|
QVERIFY2(!ruleId.isNull(), "Error adding rule");
|
||||||
|
|
||||||
|
// Get the current state value, make sure it's false
|
||||||
|
params.clear();
|
||||||
|
params.insert("deviceId", m_mockDeviceId);
|
||||||
|
params.insert("stateTypeId", mockPowerStateTypeId);
|
||||||
|
|
||||||
|
response = injectAndWait("Devices.GetStateValue", params);
|
||||||
|
QVERIFY2(response.toMap().value("params").toMap().value("value").toBool() == false, "State initially true while it should be false");
|
||||||
|
|
||||||
|
|
||||||
|
// Trigger the event
|
||||||
|
generateEvent(mockEvent1Id);
|
||||||
|
|
||||||
|
|
||||||
|
// Make sure the value changed after the event has triggered
|
||||||
|
response = injectAndWait("Devices.GetStateValue", params);
|
||||||
|
QVERIFY2(response.toMap().value("params").toMap().value("value").toBool() == true, "State is false while it should have changed to true");
|
||||||
|
|
||||||
|
|
||||||
|
// Trigger the event again...
|
||||||
|
generateEvent(mockEvent1Id);
|
||||||
|
|
||||||
|
|
||||||
|
// ... and make sure the value changed back to false
|
||||||
|
response = injectAndWait("Devices.GetStateValue", params);
|
||||||
|
QVERIFY2(response.toMap().value("params").toMap().value("value").toBool() == false, "State is true while it should have changed to false");
|
||||||
|
|
||||||
|
restartServer();
|
||||||
|
|
||||||
|
// Make sure the value changed is still false
|
||||||
|
response = injectAndWait("Devices.GetStateValue", params);
|
||||||
|
QVERIFY2(response.toMap().value("params").toMap().value("value").toBool() == false, "State is true while it should have changed to false");
|
||||||
|
|
||||||
|
// Trigger the event
|
||||||
|
generateEvent(mockEvent1Id);
|
||||||
|
|
||||||
|
|
||||||
|
// Make sure the value changed after the event has triggered
|
||||||
|
response = injectAndWait("Devices.GetStateValue", params);
|
||||||
|
QVERIFY2(response.toMap().value("params").toMap().value("value").toBool() == true, "State is false while it should have changed to true");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void TestRules::testInterfaceBasedEventRule()
|
void TestRules::testInterfaceBasedEventRule()
|
||||||
{
|
{
|
||||||
QNetworkAccessManager nam;
|
QNetworkAccessManager nam;
|
||||||
|
|||||||
Reference in New Issue
Block a user