From 69ca5c4713f33b886eeba6270d866891836fc292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 8 Jun 2015 17:21:35 +0200 Subject: [PATCH] bump api version add tests for rule active changed notification --- guh.pri | 2 +- tests/auto/api.json | 25 ++- tests/auto/jsonrpc/testjsonrpc.cpp | 290 +++++++++++++++++++++++++++++ tests/auto/rules/testrules.cpp | 24 ++- 4 files changed, 326 insertions(+), 15 deletions(-) diff --git a/guh.pri b/guh.pri index a91952b7..3edc6234 100644 --- a/guh.pri +++ b/guh.pri @@ -2,7 +2,7 @@ GUH_VERSION_STRING=$$system('dpkg-parsechangelog | sed -n -e "s/^Version: //p"') # define JSON protocol version -JSON_PROTOCOL_VERSION=22 +JSON_PROTOCOL_VERSION=23 DEFINES += GUH_VERSION_STRING=\\\"$${GUH_VERSION_STRING}\\\" JSON_PROTOCOL_VERSION=\\\"$${JSON_PROTOCOL_VERSION}\\\" diff --git a/tests/auto/api.json b/tests/auto/api.json index 9b84147e..f870ad2b 100644 --- a/tests/auto/api.json +++ b/tests/auto/api.json @@ -1,4 +1,4 @@ -22 +23 { "methods": { "Actions.ExecuteAction": { @@ -287,12 +287,13 @@ } }, "Rules.AddRule": { - "description": "Add a rule. You can describe rules by one or many EventDesciptors and a StateEvaluator. Note that onlyone of either eventDescriptor or eventDescriptorList may be passed at a time. A rule can be created but left disabled,meaning it won't actually be executed until set to enabled. If not given, enabled defaults to true.", + "description": "Add a rule. You can describe rules by one or many EventDesciptors and a StateEvaluator. Note that only one of either eventDescriptor or eventDescriptorList may be passed at a time. A rule can be created but left disabled, meaning it won't actually be executed until set to enabled. If not given, enabled defaults to true.", "params": { "actions": [ "$ref:RuleAction" ], "name": "String", + "o:active": "Bool", "o:enabled": "Bool", "o:eventDescriptor": "$ref:EventDescriptor", "o:eventDescriptorList": [ @@ -348,12 +349,12 @@ } }, "Rules.GetRules": { - "description": "Get all configured rules", + "description": "Get the descriptions of all configured rules. If you need more information about a specific rule use the method Rules.GetRuleDetails.", "params": { }, "returns": { - "ruleIds": [ - "Uuid" + "ruleDescriptions": [ + "$ref:RuleDescription" ] } }, @@ -416,6 +417,13 @@ "logEntry": "$ref:LogEntry" } }, + "Rules.RuleActiveChanged": { + "description": "Emitted whenever the active state of a Rule changed.", + "params": { + "active": "Bool", + "ruleId": "Uuid" + } + }, "Rules.RuleAdded": { "description": "Emitted whenever a Rule was added.", "params": { @@ -620,6 +628,7 @@ "actions": [ "$ref:RuleAction" ], + "active": "Bool", "enabled": "Bool", "eventDescriptors": [ "$ref:EventDescriptor" @@ -644,6 +653,12 @@ "o:eventTypeId": "Uuid", "o:value": "$ref:BasicType" }, + "RuleDescription": { + "active": "Bool", + "enabled": "Bool", + "id": "Uuid", + "name": "String" + }, "RuleError": [ "RuleErrorNoError", "RuleErrorInvalidRuleId", diff --git a/tests/auto/jsonrpc/testjsonrpc.cpp b/tests/auto/jsonrpc/testjsonrpc.cpp index 10886413..92d70afe 100644 --- a/tests/auto/jsonrpc/testjsonrpc.cpp +++ b/tests/auto/jsonrpc/testjsonrpc.cpp @@ -52,6 +52,8 @@ private slots: void deviceAddedRemovedNotifications(); void ruleAddedRemovedNotifications(); + void ruleActiveChangedNotifications(); + void deviceParamsChangedNotifications(); private: @@ -261,6 +263,294 @@ void TestJSONRPC::stateChangeEmitsNotifications() } + + +void TestJSONRPC::deviceAddedRemovedNotifications() +{ + // enable notificartions + QVariantMap params; + params.insert("enabled", true); + QVariant response = injectAndWait("JSONRPC.SetNotificationStatus", params); + QCOMPARE(response.toMap().value("params").toMap().value("enabled").toBool(), true); + + // Setup connection to mock client + QSignalSpy clientSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray))); + + // add device and wait for notification + QVariantList deviceParams; + QVariantMap httpportParam; + httpportParam.insert("name", "httpport"); + httpportParam.insert("value", 8765); + deviceParams.append(httpportParam); + + params.clear(); response.clear(); + params.insert("deviceClassId", mockDeviceClassId); + params.insert("deviceParams", deviceParams); + response = injectAndWait("Devices.AddConfiguredDevice", params); + + // Lets wait for the notification + clientSpy.wait(500); + qDebug() << "got" << clientSpy.count() << "notifications"; + QCOMPARE(clientSpy.count(), 2); // wait for device added notification and response + + QJsonDocument jsonDocResponse = QJsonDocument::fromJson(clientSpy.at(1).at(1).toByteArray()); + QJsonDocument jsonDocNotification = QJsonDocument::fromJson(clientSpy.at(0).at(1).toByteArray()); + + verifyDeviceError(jsonDocResponse.toVariant()); + DeviceId deviceId = DeviceId(jsonDocResponse.toVariant().toMap().value("params").toMap().value("deviceId").toString()); + QVERIFY(!deviceId.isNull()); + + // check the DeviceAdded notification + QCOMPARE(jsonDocNotification.toVariant().toMap().value("notification").toString(), QString("Devices.DeviceAdded")); + QVariantMap notificationDeviceMap = jsonDocNotification.toVariant().toMap().value("params").toMap().value("device").toMap(); + + QCOMPARE(notificationDeviceMap.value("deviceClassId").toString(), mockDeviceClassId.toString()); + QCOMPARE(notificationDeviceMap.value("id").toString(), deviceId.toString()); + foreach (const QVariant ¶m, notificationDeviceMap.value("params").toList()) { + if (param.toMap().value("name").toString() == "httpport") { + QCOMPARE(param.toMap().value("value").toInt(), httpportParam.value("value").toInt()); + } + } + + // Setup connection to mock client + QSignalSpy clientSpy2(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray))); + + // now remove the device and check the device removed notification + params.clear(); response.clear(); + params.insert("deviceId", deviceId); + response = injectAndWait("Devices.RemoveConfiguredDevice", params); + + clientSpy2.wait(500); + qDebug() << "got" << clientSpy2.count() << "notifications"; + QCOMPARE(clientSpy2.count(), 2); // wait for device removed notification and response + + jsonDocResponse = QJsonDocument::fromJson(clientSpy2.at(1).at(1).toByteArray()); + jsonDocNotification = QJsonDocument::fromJson(clientSpy2.at(0).at(1).toByteArray()); + + verifyDeviceError(jsonDocResponse.toVariant()); + + // check the DeviceRemoved notification + QCOMPARE(jsonDocNotification.toVariant().toMap().value("notification").toString(), QString("Devices.DeviceRemoved")); + QCOMPARE(jsonDocNotification.toVariant().toMap().value("params").toMap().value("deviceId").toString(), deviceId.toString()); +} + +void TestJSONRPC::ruleAddedRemovedNotifications() +{ + // enable notificartions + QVariantMap params; + params.insert("enabled", true); + QVariant response = injectAndWait("JSONRPC.SetNotificationStatus", params); + QCOMPARE(response.toMap().value("params").toMap().value("enabled").toBool(), true); + + // Add rule and wait for notification + // StateDescriptor + QVariantMap stateDescriptor; + stateDescriptor.insert("stateTypeId", mockIntStateId); + stateDescriptor.insert("deviceId", m_mockDeviceId); + stateDescriptor.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorLess)); + stateDescriptor.insert("value", "20"); + + QVariantMap stateEvaluator; + stateEvaluator.insert("stateDescriptor", stateDescriptor); + + + // RuleAction + QVariantMap actionNoParams; + actionNoParams.insert("actionTypeId", mockActionIdNoParams); + actionNoParams.insert("deviceId", m_mockDeviceId); + actionNoParams.insert("ruleActionParams", QVariantList()); + + // EventDescriptor + QVariantMap eventDescriptor; + eventDescriptor.insert("eventTypeId", mockEvent1Id); + eventDescriptor.insert("deviceId", m_mockDeviceId); + eventDescriptor.insert("paramDescriptors", QVariantList()); + + params.clear(); response.clear(); + params.insert("name", "Test Rule notifications"); + params.insert("actions", QVariantList() << actionNoParams); + params.insert("eventDescriptor", eventDescriptor); + params.insert("stateEvaluator", stateEvaluator); + + // Setup connection to mock client + QSignalSpy clientSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray))); + + response = injectAndWait("Rules.AddRule", params); + + clientSpy.wait(500); + qDebug() << "got" << clientSpy.count() << "notifications"; + QCOMPARE(clientSpy.count(), 2); + + QJsonDocument jsonDocResponse = QJsonDocument::fromJson(clientSpy.at(1).at(1).toByteArray()); + QJsonDocument jsonDocNotification = QJsonDocument::fromJson(clientSpy.at(0).at(1).toByteArray()); + + verifyRuleError(jsonDocResponse.toVariant()); + RuleId ruleId = RuleId(jsonDocResponse.toVariant().toMap().value("params").toMap().value("ruleId").toString()); + QVERIFY(!ruleId.isNull()); + + // check the DeviceAdded notification + QCOMPARE(jsonDocNotification.toVariant().toMap().value("notification").toString(), QString("Rules.RuleAdded")); + QVariantMap notificationRuleMap = jsonDocNotification.toVariant().toMap().value("params").toMap().value("rule").toMap(); + + QCOMPARE(notificationRuleMap.value("enabled").toBool(), true); + QCOMPARE(notificationRuleMap.value("name").toString(), params.value("name").toString()); + QCOMPARE(notificationRuleMap.value("id").toString(), ruleId.toString()); + QCOMPARE(notificationRuleMap.value("actions").toList(), QVariantList() << actionNoParams); + QCOMPARE(notificationRuleMap.value("stateEvaluator").toMap().value("stateDescriptor").toMap(), stateDescriptor); + QCOMPARE(notificationRuleMap.value("eventDescriptors").toList(), QVariantList() << eventDescriptor); + QCOMPARE(notificationRuleMap.value("exitActions").toList(), QVariantList()); + + // Setup connection to mock client + QSignalSpy clientSpy2(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray))); + + // now remove the rule and check the RuleRemoved notification + params.clear(); response.clear(); + params.insert("ruleId", ruleId); + response = injectAndWait("Rules.RemoveRule", params); + + clientSpy2.wait(500); + qDebug() << "got" << clientSpy2.count() << "notifications"; + QCOMPARE(clientSpy2.count(), 2); // wait for RuleRemoved notification and response + + jsonDocResponse = QJsonDocument::fromJson(clientSpy2.at(1).at(1).toByteArray()); + jsonDocNotification = QJsonDocument::fromJson(clientSpy2.at(0).at(1).toByteArray()); + + verifyRuleError(jsonDocResponse.toVariant()); + + // check the DeviceRemoved notification + QCOMPARE(jsonDocNotification.toVariant().toMap().value("notification").toString(), QString("Rules.RuleRemoved")); + QCOMPARE(jsonDocNotification.toVariant().toMap().value("params").toMap().value("ruleId").toString(), ruleId.toString()); +} + +void TestJSONRPC::ruleActiveChangedNotifications() +{ + // enable notificartions + QVariantMap params; + params.insert("enabled", true); + QVariant response = injectAndWait("JSONRPC.SetNotificationStatus", params); + QCOMPARE(response.toMap().value("params").toMap().value("enabled").toBool(), true); + + // Add rule and wait for notification + // StateDescriptor + QVariantMap stateDescriptor; + stateDescriptor.insert("stateTypeId", mockIntStateId); + stateDescriptor.insert("deviceId", m_mockDeviceId); + stateDescriptor.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals)); + stateDescriptor.insert("value", "20"); + + QVariantMap stateEvaluator; + stateEvaluator.insert("stateDescriptor", stateDescriptor); + + // RuleAction + QVariantMap actionNoParams; + actionNoParams.insert("actionTypeId", mockActionIdNoParams); + actionNoParams.insert("deviceId", m_mockDeviceId); + actionNoParams.insert("ruleActionParams", QVariantList()); + + params.clear(); response.clear(); + params.insert("name", "Test Rule notifications"); + params.insert("actions", QVariantList() << actionNoParams); + params.insert("stateEvaluator", stateEvaluator); + + // Setup connection to mock client + QSignalSpy clientSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray))); + + response = injectAndWait("Rules.AddRule", params); + + clientSpy.wait(500); + qDebug() << "got" << clientSpy.count() << "notifications"; + QCOMPARE(clientSpy.count(), 2); + + QJsonDocument jsonDocResponse = QJsonDocument::fromJson(clientSpy.at(1).at(1).toByteArray()); + QJsonDocument jsonDocNotification = QJsonDocument::fromJson(clientSpy.at(0).at(1).toByteArray()); + + verifyRuleError(jsonDocResponse.toVariant()); + RuleId ruleId = RuleId(jsonDocResponse.toVariant().toMap().value("params").toMap().value("ruleId").toString()); + QVERIFY(!ruleId.isNull()); + + // check the DeviceAdded notification + QCOMPARE(jsonDocNotification.toVariant().toMap().value("notification").toString(), QString("Rules.RuleAdded")); + QVariantMap notificationRuleMap = jsonDocNotification.toVariant().toMap().value("params").toMap().value("rule").toMap(); + + QCOMPARE(notificationRuleMap.value("enabled").toBool(), true); + QCOMPARE(notificationRuleMap.value("name").toString(), params.value("name").toString()); + QCOMPARE(notificationRuleMap.value("id").toString(), ruleId.toString()); + QCOMPARE(notificationRuleMap.value("actions").toList(), QVariantList() << actionNoParams); + QCOMPARE(notificationRuleMap.value("stateEvaluator").toMap().value("stateDescriptor").toMap(), stateDescriptor); + QCOMPARE(notificationRuleMap.value("exitActions").toList(), QVariantList()); + + // set the rule active + QNetworkAccessManager nam; + QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*))); + QSignalSpy clientSpy2(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray))); + + // state state to 20 + qDebug() << "setting mock int state to 20"; + QNetworkRequest request(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockIntStateId.toString()).arg(20))); + QNetworkReply *reply = nam.get(request); + spy.wait(); + QCOMPARE(spy.count(), 1); + reply->deleteLater(); + + clientSpy2.wait(500); + qDebug() << "got" << clientSpy2.count() << "notifications"; + QCOMPARE(clientSpy2.count(), 6); + + for (int i = 0; i < clientSpy2.count(); i++) { + QByteArray notification = clientSpy2.at(i).at(1).toByteArray(); + if (notification.contains("Rules.RuleActiveChanged")) { + QVariantMap notificationMap = QJsonDocument::fromJson(notification).toVariant().toMap(); + QCOMPARE(notificationMap.value("notification").toString(), QString("Rules.RuleActiveChanged")); + QCOMPARE(notificationMap.value("params").toMap().value("ruleId").toString(), ruleId.toString()); + QCOMPARE(notificationMap.value("params").toMap().value("active").toBool(), true); + } + } + clientSpy2.clear(); + spy.clear(); + + // set the rule inactive + qDebug() << "setting mock int state to 42"; + QNetworkRequest request2(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(m_mockDevice1Port).arg(mockIntStateId.toString()).arg(42))); + QNetworkReply *reply2 = nam.get(request2); + spy.wait(); + QCOMPARE(spy.count(), 1); + reply2->deleteLater(); + + clientSpy2.wait(500); + QCOMPARE(clientSpy2.count(), 5); + + for (int i = 0; i < clientSpy2.count(); i++) { + QByteArray notification = clientSpy2.at(i).at(1).toByteArray(); + if (notification.contains("Rules.RuleActiveChanged")) { + QVariantMap notificationMap = QJsonDocument::fromJson(notification).toVariant().toMap(); + QCOMPARE(notificationMap.value("notification").toString(), QString("Rules.RuleActiveChanged")); + QCOMPARE(notificationMap.value("params").toMap().value("ruleId").toString(), ruleId.toString()); + QCOMPARE(notificationMap.value("params").toMap().value("active").toBool(), false); + } + } + + // Setup connection to mock client + QSignalSpy clientSpy3(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray))); + + // now remove the rule and check the RuleRemoved notification + params.clear(); response.clear(); + params.insert("ruleId", ruleId); + response = injectAndWait("Rules.RemoveRule", params); + + clientSpy3.wait(500); + qDebug() << "got" << clientSpy3.count() << "notifications"; + QCOMPARE(clientSpy3.count(), 2); // wait for RuleRemoved notification and response + + jsonDocResponse = QJsonDocument::fromJson(clientSpy3.at(1).at(1).toByteArray()); + jsonDocNotification = QJsonDocument::fromJson(clientSpy3.at(0).at(1).toByteArray()); + + verifyRuleError(jsonDocResponse.toVariant()); + + // check the DeviceRemoved notification + QCOMPARE(jsonDocNotification.toVariant().toMap().value("notification").toString(), QString("Rules.RuleRemoved")); + QCOMPARE(jsonDocNotification.toVariant().toMap().value("params").toMap().value("ruleId").toString(), ruleId.toString()); +} + void TestJSONRPC::deviceParamsChangedNotifications() { // enable notificartions diff --git a/tests/auto/rules/testrules.cpp b/tests/auto/rules/testrules.cpp index bf0072ef..5e325d5e 100644 --- a/tests/auto/rules/testrules.cpp +++ b/tests/auto/rules/testrules.cpp @@ -81,9 +81,9 @@ void TestRules::cleanupMockHistory() { void TestRules::cleanupRules() { QVariant response = injectAndWait("Rules.GetRules"); - foreach (const QVariant &ruleId, response.toMap().value("params").toMap().value("ruleIds").toList()) { + foreach (const QVariant &ruleDescription, response.toMap().value("params").toMap().value("ruleDescriptions").toList()) { QVariantMap params; - params.insert("ruleId", ruleId.toString()); + params.insert("ruleId", ruleDescription.toMap().value("id").toString()); verifyRuleError(injectAndWait("Rules.RemoveRule", params)); } } @@ -319,7 +319,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("ruleIds").toList(); + QVariantList rules = response.toMap().value("params").toMap().value("ruleDescriptions").toList(); if (error != RuleEngine::RuleErrorNoError) { QVERIFY2(rules.count() == 0, "There should be no rules."); @@ -327,7 +327,7 @@ void TestRules::addRemoveRules() } QVERIFY2(rules.count() == 1, "There should be exactly one rule"); - QCOMPARE(RuleId(rules.first().toString()), newRuleId); + QCOMPARE(RuleId(rules.first().toMap().value("id").toString()), newRuleId); params.clear(); params.insert("ruleId", newRuleId); @@ -369,7 +369,7 @@ void TestRules::addRemoveRules() verifyRuleError(response); response = injectAndWait("Rules.GetRules"); - rules = response.toMap().value("params").toMap().value("rules").toList(); + rules = response.toMap().value("params").toMap().value("ruleDescriptions").toList(); QVERIFY2(rules.count() == 0, "There should be no rules."); } @@ -518,12 +518,18 @@ void TestRules::loadStoreConfig() response = injectAndWait("Rules.GetRules"); - QVariantList rules = response.toMap().value("params").toMap().value("ruleIds").toList(); + QVariantList rules = response.toMap().value("params").toMap().value("ruleDescriptions").toList(); QVERIFY2(rules.count() == 3, "There should be exactly three rule."); - QVERIFY2(rules.contains(newRuleId.toString()), "Rule 1 should be in ruleIds list."); - QVERIFY2(rules.contains(newRuleId2.toString()), "Rule 2 should be in ruleIds list."); - QVERIFY2(rules.contains(newRuleId3.toString()), "Rule 3 should be in ruleIds list."); + + QStringList idList; + foreach (const QVariant &ruleDescription, rules) { + idList.append(ruleDescription.toMap().value("id").toString()); + } + + QVERIFY2(idList.contains(newRuleId.toString()), "Rule 1 should be in ruleIds list."); + QVERIFY2(idList.contains(newRuleId2.toString()), "Rule 2 should be in ruleIds list."); + QVERIFY2(idList.contains(newRuleId3.toString()), "Rule 3 should be in ruleIds list."); // Rule 1 params.clear();