/**************************************************************************** * * * This file is part of guh. * * * * Guh is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, version 2 of the License. * * * * Guh is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with guh. If not, see . * * * ***************************************************************************/ #include "guhtestbase.h" #include "guhcore.h" #include "devicemanager.h" #include "mocktcpserver.h" #include #include #include #include #include #include #include class TestRules: public GuhTestBase { Q_OBJECT private: void cleanupMockHistory(); void cleanupRules(); private slots: void cleanup(); void addRemoveRules_data(); void addRemoveRules(); void removeInvalidRule(); void loadStoreConfig(); void evaluateEvent(); void testStateEvaluator_data(); void testStateEvaluator(); void testStateEvaluator2_data(); void testStateEvaluator2(); void enableDisableRule(); }; void TestRules::cleanupMockHistory() { QNetworkAccessManager nam; QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*))); QNetworkRequest request(QUrl(QString("http://localhost:%1/clearactionhistory").arg(m_mockDevice1Port).arg(mockEvent1Id.toString()))); QNetworkReply *reply = nam.get(request); spy.wait(); QCOMPARE(spy.count(), 1); reply->deleteLater(); } void TestRules::cleanupRules() { QVariant response = injectAndWait("Rules.GetRules"); foreach (const QVariant &ruleId, response.toMap().value("params").toMap().value("ruleIds").toList()) { QVariantMap params; params.insert("ruleId", ruleId.toString()); verifyRuleError(injectAndWait("Rules.RemoveRule", params)); } } void TestRules::cleanup() { cleanupMockHistory(); cleanupRules(); } void TestRules::addRemoveRules_data() { QVariantMap validActionNoParams; validActionNoParams.insert("actionTypeId", mockActionIdNoParams); validActionNoParams.insert("deviceId", m_mockDeviceId); validActionNoParams.insert("params", QVariantList()); QVariantMap invalidAction; invalidAction.insert("actionTypeId", ActionTypeId()); invalidAction.insert("deviceId", m_mockDeviceId); invalidAction.insert("params", QVariantList()); QVariantMap stateDescriptor; stateDescriptor.insert("stateTypeId", mockIntStateId); stateDescriptor.insert("deviceId", m_mockDeviceId); stateDescriptor.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorLess)); stateDescriptor.insert("value", "20"); QVariantMap validStateEvaluator; validStateEvaluator.insert("stateDescriptor", stateDescriptor); QVariantMap invalidStateEvaluator; stateDescriptor.remove("deviceId"); invalidStateEvaluator.insert("stateDescriptor", stateDescriptor); QVariantMap validEventDescriptor1; validEventDescriptor1.insert("eventTypeId", mockEvent1Id); validEventDescriptor1.insert("deviceId", m_mockDeviceId); validEventDescriptor1.insert("paramDescriptors", QVariantList()); QVariantMap validEventDescriptor2; validEventDescriptor2.insert("eventTypeId", mockEvent2Id); validEventDescriptor2.insert("deviceId", m_mockDeviceId); QVariantList params; QVariantMap param1; param1.insert("name", "mockParamInt"); param1.insert("value", 3); param1.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals)); params.append(param1); validEventDescriptor2.insert("paramDescriptors", params); QVariantList eventDescriptorList; eventDescriptorList.append(validEventDescriptor1); eventDescriptorList.append(validEventDescriptor2); QVariantMap invalidEventDescriptor; invalidEventDescriptor.insert("eventTypeId", mockEvent1Id); invalidEventDescriptor.insert("deviceId", DeviceId()); invalidEventDescriptor.insert("paramDescriptors", QVariantList()); QTest::addColumn("enabled"); QTest::addColumn("action1"); QTest::addColumn("eventDescriptor"); QTest::addColumn("eventDescriptorList"); QTest::addColumn("stateEvaluator"); QTest::addColumn("error"); QTest::newRow("valid rule. 1 EventDescriptor, StateEvaluator, 1 Action, enabled") << true << validActionNoParams << validEventDescriptor1 << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorNoError; QTest::newRow("valid rule. 1 EventDescriptor, StateEvaluator, 1 Action, diabled") << false << validActionNoParams << validEventDescriptor1 << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorNoError; QTest::newRow("valid rule. 2 EventDescriptors, 1 Action") << true << validActionNoParams << QVariantMap() << eventDescriptorList << validStateEvaluator << RuleEngine::RuleErrorNoError; QTest::newRow("invalid rule: eventDescriptor and eventDescriptorList used") << true << validActionNoParams << validEventDescriptor1 << eventDescriptorList << validStateEvaluator << RuleEngine::RuleErrorInvalidParameter; QTest::newRow("invalid action") << true << invalidAction << validEventDescriptor1 << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorActionTypeNotFound; QTest::newRow("invalid event descriptor") <deleteLater(); // Verify rule got executed spy.clear(); request.setUrl(QUrl(QString("http://localhost:%1/actionhistory").arg(m_mockDevice1Port))); reply = nam.get(request); spy.wait(); QCOMPARE(spy.count(), 1); reply->deleteLater(); QByteArray actionHistory = reply->readAll(); QVERIFY2(mockActionIdNoParams == ActionTypeId(actionHistory), "Action not triggered"); } void TestRules::testStateEvaluator_data() { QTest::addColumn("deviceId"); QTest::addColumn("stateTypeId"); QTest::addColumn("value"); QTest::addColumn("operatorType"); QTest::addColumn("shouldMatch"); QTest::newRow("invalid stateId") << m_mockDeviceId << StateTypeId::createStateTypeId() << QVariant(10) << Types::ValueOperatorEquals << false; QTest::newRow("invalid deviceId") << DeviceId::createDeviceId() << mockIntStateId << QVariant(10) << Types::ValueOperatorEquals << false; QTest::newRow("equals, not matching") << m_mockDeviceId << mockIntStateId << QVariant(7777) << Types::ValueOperatorEquals << false; QTest::newRow("equals, matching") << m_mockDeviceId << mockIntStateId << QVariant(10) << Types::ValueOperatorEquals << true; QTest::newRow("not equal, not matching") << m_mockDeviceId << mockIntStateId << QVariant(10) << Types::ValueOperatorNotEquals << false; QTest::newRow("not equal, matching") << m_mockDeviceId << mockIntStateId << QVariant(7777) << Types::ValueOperatorNotEquals << true; QTest::newRow("Greater, not matching") << m_mockDeviceId << mockIntStateId << QVariant(7777) << Types::ValueOperatorGreater << false; QTest::newRow("Greater, matching") << m_mockDeviceId << mockIntStateId << QVariant(2) << Types::ValueOperatorGreater << true; QTest::newRow("GreaterOrEqual, not matching") << m_mockDeviceId << mockIntStateId << QVariant(7777) << Types::ValueOperatorGreaterOrEqual << false; QTest::newRow("GreaterOrEqual, matching (greater)") << m_mockDeviceId << mockIntStateId << QVariant(2) << Types::ValueOperatorGreaterOrEqual << true; QTest::newRow("GreaterOrEqual, matching (equals)") << m_mockDeviceId << mockIntStateId << QVariant(10) << Types::ValueOperatorGreaterOrEqual << true; QTest::newRow("Less, not matching") << m_mockDeviceId << mockIntStateId << QVariant(2) << Types::ValueOperatorLess << false; QTest::newRow("Less, matching") << m_mockDeviceId << mockIntStateId << QVariant(7777) << Types::ValueOperatorLess << true; QTest::newRow("LessOrEqual, not matching") << m_mockDeviceId << mockIntStateId << QVariant(2) << Types::ValueOperatorLessOrEqual << false; QTest::newRow("LessOrEqual, matching (less)") << m_mockDeviceId << mockIntStateId << QVariant(777) << Types::ValueOperatorLessOrEqual << true; QTest::newRow("LessOrEqual, matching (equals)") << m_mockDeviceId << mockIntStateId << QVariant(10) << Types::ValueOperatorLessOrEqual << true; } void TestRules::testStateEvaluator() { QFETCH(DeviceId, deviceId); QFETCH(StateTypeId, stateTypeId); QFETCH(QVariant, value); QFETCH(Types::ValueOperator, operatorType); QFETCH(bool, shouldMatch); StateDescriptor descriptor(stateTypeId, deviceId, value, operatorType); StateEvaluator evaluator(descriptor); QVERIFY2(evaluator.evaluate() == shouldMatch, shouldMatch ? "State should match" : "State shouldn't match"); } void TestRules::testStateEvaluator2_data() { QTest::addColumn("intValue"); QTest::addColumn("intOperator"); QTest::addColumn("boolValue"); QTest::addColumn("boolOperator"); QTest::addColumn("stateOperator"); QTest::addColumn("shouldMatch"); QTest::newRow("Y: 10 && false") << 10 << Types::ValueOperatorEquals << false << Types::ValueOperatorEquals << Types::StateOperatorAnd << true; QTest::newRow("N: 10 && true") << 10 << Types::ValueOperatorEquals << true << Types::ValueOperatorEquals << Types::StateOperatorAnd << false; QTest::newRow("N: 11 && false") << 11 << Types::ValueOperatorEquals << false << Types::ValueOperatorEquals << Types::StateOperatorAnd << false; QTest::newRow("Y: 11 || false") << 11 << Types::ValueOperatorEquals << false << Types::ValueOperatorEquals << Types::StateOperatorOr << true; QTest::newRow("Y: 10 || false") << 10 << Types::ValueOperatorEquals << false << Types::ValueOperatorEquals << Types::StateOperatorOr << true; QTest::newRow("Y: 10 || true") << 10 << Types::ValueOperatorEquals << true << Types::ValueOperatorEquals << Types::StateOperatorOr << true; QTest::newRow("N: 11 || true") << 11 << Types::ValueOperatorEquals << true << Types::ValueOperatorEquals << Types::StateOperatorOr << false; } void TestRules::testStateEvaluator2() { QFETCH(int, intValue); QFETCH(Types::ValueOperator, intOperator); QFETCH(bool, boolValue); QFETCH(Types::ValueOperator, boolOperator); QFETCH(Types::StateOperator, stateOperator); QFETCH(bool, shouldMatch); StateDescriptor descriptor1(mockIntStateId, m_mockDeviceId, intValue, intOperator); StateEvaluator evaluator1(descriptor1); StateDescriptor descriptor2(mockBoolStateId, m_mockDeviceId, boolValue, boolOperator); StateEvaluator evaluator2(descriptor2); QList childEvaluators; childEvaluators.append(evaluator1); childEvaluators.append(evaluator2); StateEvaluator mainEvaluator(childEvaluators); mainEvaluator.setOperatorType(stateOperator); QVERIFY2(mainEvaluator.evaluate() == shouldMatch, shouldMatch ? "State should match" : "State shouldn't match"); } void TestRules::enableDisableRule() { // Add a rule QVariantMap addRuleParams; QVariantList events; QVariantMap event1; event1.insert("eventTypeId", mockEvent1Id); event1.insert("deviceId", m_mockDeviceId); events.append(event1); addRuleParams.insert("eventDescriptorList", events); QVariantList actions; QVariantMap action; action.insert("actionTypeId", mockActionIdNoParams); action.insert("deviceId", m_mockDeviceId); actions.append(action); addRuleParams.insert("actions", actions); QVariant response = injectAndWait("Rules.AddRule", addRuleParams); verifyRuleError(response); RuleId id = RuleId(response.toMap().value("params").toMap().value("ruleId").toString()); // Trigger an event QNetworkAccessManager nam; QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*))); // trigger event in mock device QNetworkRequest request(QUrl(QString("http://localhost:%1/generateevent?eventtypeid=%2").arg(m_mockDevice1Port).arg(mockEvent1Id.toString()))); QNetworkReply *reply = nam.get(request); spy.wait(); QCOMPARE(spy.count(), 1); reply->deleteLater(); // Verify rule got executed spy.clear(); request.setUrl(QUrl(QString("http://localhost:%1/actionhistory").arg(m_mockDevice1Port))); reply = nam.get(request); spy.wait(); QCOMPARE(spy.count(), 1); QByteArray actionHistory = reply->readAll(); qDebug() << "have action history" << actionHistory; QVERIFY2(mockActionIdNoParams == ActionTypeId(actionHistory), "Action not triggered"); reply->deleteLater(); cleanupMockHistory(); // Now disable the rule QVariantMap disableParams; disableParams.insert("ruleId", id.toString()); response = injectAndWait("Rules.DisableRule", disableParams); verifyRuleError(response); // trigger event in mock device spy.clear(); request = QNetworkRequest(QUrl(QString("http://localhost:%1/generateevent?eventtypeid=%2").arg(m_mockDevice1Port).arg(mockEvent1Id.toString()))); reply = nam.get(request); spy.wait(); QCOMPARE(spy.count(), 1); reply->deleteLater(); // Verify rule got *NOT* executed spy.clear(); request.setUrl(QUrl(QString("http://localhost:%1/actionhistory").arg(m_mockDevice1Port))); reply = nam.get(request); spy.wait(); QCOMPARE(spy.count(), 1); actionHistory = reply->readAll(); qDebug() << "have action history" << actionHistory; QVERIFY2(actionHistory.isEmpty(), "Action is triggered while rule is disabled"); reply->deleteLater(); cleanupMockHistory(); // Now enable the rule again response = injectAndWait("Rules.EnableRule", disableParams); verifyRuleError(response); // trigger event in mock device 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(); // Verify rule got executed spy.clear(); request.setUrl(QUrl(QString("http://localhost:%1/actionhistory").arg(m_mockDevice1Port))); reply = nam.get(request); spy.wait(); QCOMPARE(spy.count(), 1); actionHistory = reply->readAll(); qDebug() << "have action history" << actionHistory; QVERIFY2(mockActionIdNoParams == ActionTypeId(actionHistory), "Action not triggered"); reply->deleteLater(); } #include "testrules.moc" QTEST_MAIN(TestRules)