From fa1cd3605c03ab0a417a5f64e1fe8a15a24f70d0 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Mon, 4 Nov 2019 11:47:16 +0100 Subject: [PATCH] Add deprecation warnings --- libnymea-core/jsonrpc/devicehandler.cpp | 2 +- .../jsonrpc/jsonrpcserverimplementation.cpp | 55 +++++- .../jsonrpc/jsonrpcserverimplementation.h | 2 +- libnymea/jsonrpc/jsonhandler.cpp | 5 - tests/auto/api.json | 49 ++++- tests/auto/devices/testdevices.cpp | 185 ++++++++++++++++++ tests/auto/events/testevents.cpp | 32 +++ 7 files changed, 313 insertions(+), 17 deletions(-) diff --git a/libnymea-core/jsonrpc/devicehandler.cpp b/libnymea-core/jsonrpc/devicehandler.cpp index e4b074fd..367b0c88 100644 --- a/libnymea-core/jsonrpc/devicehandler.cpp +++ b/libnymea-core/jsonrpc/devicehandler.cpp @@ -385,7 +385,7 @@ DeviceHandler::DeviceHandler(QObject *parent) : params.clear(); returns.clear(); description = "Emitted whenever an Event is triggered."; params.insert("event", objectRef()); - registerNotification("EventTriggered", description, params, "Please use Devices.EventTriggered instead."); + registerNotification("EventTriggered", description, params); connect(NymeaCore::instance(), &NymeaCore::eventTriggered, this, [this](const Event &event){ QVariantMap params; params.insert("event", pack(event)); diff --git a/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp b/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp index 69ce0848..8aded8dc 100644 --- a/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp +++ b/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp @@ -467,13 +467,17 @@ bool JsonRPCServerImplementation::registerExperienceHandler(JsonHandler *handler /*! Send a JSON success response to the client with the given \a clientId, * \a commandId and \a params to the inerted \l{TransportInterface}. */ -void JsonRPCServerImplementation::sendResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QVariantMap ¶ms) +void JsonRPCServerImplementation::sendResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QVariantMap ¶ms, const QString &deprecationWarning) { QVariantMap response; response.insert("id", commandId); response.insert("status", "success"); response.insert("params", params); + if (!deprecationWarning.isEmpty()) { + response.insert("deprecationWarning", deprecationWarning); + } + QByteArray data = QJsonDocument::fromVariant(response).toJson(QJsonDocument::Compact); qCDebug(dcJsonRpcTraffic()) << "Sending data:" << data; interface->sendData(clientId, data); @@ -694,7 +698,15 @@ void JsonRPCServerImplementation::processJsonPacket(TransportInterface *interfac Q_ASSERT_X((targetNamespace == "JSONRPC" && method == "Introspect") || validator.validateReturns(reply->data(), targetNamespace + '.' + method, m_api).success(), validator.result().where().toUtf8(), validator.result().errorString().toUtf8() + "\nReturn value:\n" + QJsonDocument::fromVariant(reply->data()).toJson()); - sendResponse(interface, clientId, commandId, reply->data()); + + QString deprecationWarning; + if (m_api.value("methods").toMap().value(targetNamespace + '.' + method).toMap().contains("deprecated")) { + deprecationWarning = m_api.value("methods").toMap().value(targetNamespace + '.' + method).toMap().value("deprecated").toString(); + qCWarning(dcJsonRpc()) << "Client uses deprecated API. Please update client implementation!"; + qCWarning(dcJsonRpc()) << targetNamespace + '.' + method + ':' << deprecationWarning; + } + + sendResponse(interface, clientId, commandId, reply->data(), deprecationWarning); reply->deleteLater(); } } @@ -704,6 +716,16 @@ void JsonRPCServerImplementation::sendNotification(const QVariantMap ¶ms) JsonHandler *handler = qobject_cast(sender()); QMetaMethod method = handler->metaObject()->method(senderSignalIndex()); + QList clientsToBeNotified; + foreach (const QUuid &clientId, m_clientNotifications.keys()) { + if (m_clientNotifications.value(clientId).contains(handler->name())) { + clientsToBeNotified.append(clientId); + } + } + if (clientsToBeNotified.isEmpty()) { + return; + } + QVariantMap notification; notification.insert("id", m_notificationId++); notification.insert("notification", handler->name() + "." + method.name()); @@ -713,14 +735,20 @@ void JsonRPCServerImplementation::sendNotification(const QVariantMap ¶ms) Q_ASSERT_X(validator.validateNotificationParams(params, handler->name() + '.' + method.name(), m_api).success(), validator.result().where().toUtf8(), validator.result().errorString().toUtf8()); + + if (m_api.value("notifications").toMap().value(handler->name() + '.' + method.name()).toMap().contains("deprecated")) { + QString deprecationMessage = m_api.value("notifications").toMap().value(handler->name() + '.' + method.name()).toMap().value("deprecated").toString(); + qCWarning(dcJsonRpc()) << "Client uses deprecated API. Please update client implementation!"; + qCWarning(dcJsonRpc()) << handler->name() + '.' + method.name() + ':' << deprecationMessage; + notification.insert("deprecationWarning", deprecationMessage); + } + QByteArray data = QJsonDocument::fromVariant(notification).toJson(QJsonDocument::Compact); - qCDebug(dcJsonRpc()) << "Sending notification:" << handler->name() + "." + method.name(); qCDebug(dcJsonRpcTraffic()) << "Notification content:" << data; - foreach (const QUuid &clientId, m_clientNotifications.keys()) { - if (m_clientNotifications.value(clientId).contains(handler->name())) { - m_clientTransports.value(clientId)->sendData(clientId, data); - } + foreach (const QUuid &clientId, clientsToBeNotified) { + qCDebug(dcJsonRpc()) << "Sending notification:" << handler->name() + "." + method.name(); + m_clientTransports.value(clientId)->sendData(clientId, data); } } @@ -735,10 +763,19 @@ void JsonRPCServerImplementation::asyncReplyFinished() } if (!reply->timedOut()) { JsonValidator validator; - Q_ASSERT_X(validator.validateReturns(reply->data(), reply->handler()->name() + '.' + reply->method(), m_api).success() + QString method = reply->handler()->name() + '.' + reply->method(); + Q_ASSERT_X(validator.validateReturns(reply->data(), method, m_api).success() ,validator.result().where().toUtf8() ,validator.result().errorString().toUtf8() + "\nReturn value:\n" + QJsonDocument::fromVariant(reply->data()).toJson()); - sendResponse(interface, reply->clientId(), reply->commandId(), reply->data()); + + QString deprecationWarning; + if (m_api.value("methods").toMap().value(method).toMap().contains("deprecated")) { + deprecationWarning = m_api.value("methods").toMap().value(method).toMap().value("deprecated").toString(); + qCWarning(dcJsonRpc()) << "Client uses deprecated API. Please update client implementation!"; + qCWarning(dcJsonRpc()) << method + ':' << deprecationWarning; + } + + sendResponse(interface, reply->clientId(), reply->commandId(), reply->data(), deprecationWarning); } else { qCWarning(dcJsonRpc()) << "RPC call timed out:" << reply->handler()->name() << ":" << reply->method(); sendErrorResponse(interface, reply->clientId(), reply->commandId(), "Command timed out"); diff --git a/libnymea-core/jsonrpc/jsonrpcserverimplementation.h b/libnymea-core/jsonrpc/jsonrpcserverimplementation.h index 59bcea8e..097066e7 100644 --- a/libnymea-core/jsonrpc/jsonrpcserverimplementation.h +++ b/libnymea-core/jsonrpc/jsonrpcserverimplementation.h @@ -78,7 +78,7 @@ private: bool registerHandler(JsonHandler *handler); QHash handlers() const; - void sendResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QVariantMap ¶ms = QVariantMap()); + void sendResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QVariantMap ¶ms = QVariantMap(), const QString &deprecationWarning = QString()); void sendErrorResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QString &error); void sendUnauthorizedResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QString &error); QVariantMap createWelcomeMessage(TransportInterface *interface, const QUuid &clientId) const; diff --git a/libnymea/jsonrpc/jsonhandler.cpp b/libnymea/jsonrpc/jsonhandler.cpp index f2df0559..85c22b43 100644 --- a/libnymea/jsonrpc/jsonhandler.cpp +++ b/libnymea/jsonrpc/jsonhandler.cpp @@ -307,7 +307,6 @@ QVariant JsonHandler::pack(const QMetaObject &metaObject, const void *value) con // Manually converting QList... Only QVariantList is known to the meta system if (propertyTypeName.startsWith("QList")) { - qWarning() << "Packing list" << metaProperty.name() << propertyValue.toList(); QVariantList list; foreach (int entry, propertyValue.value>()) { list << entry; @@ -350,7 +349,6 @@ QVariant JsonHandler::unpack(const QMetaObject &metaObject, const QVariant &valu // If it's a list object, loop over count if (m_listMetaObjects.contains(typeName)) { - qWarning() << "** Unpacking" << typeName; if (value.type() != QVariant::List) { qCWarning(dcJsonRpc()) << "Cannot unpack" << typeName << ". Value is not in list format:" << value; return QVariant(); @@ -367,7 +365,6 @@ QVariant JsonHandler::unpack(const QMetaObject &metaObject, const QVariant &valu foreach (const QVariant &variant, list) { QVariant value = unpack(entryMetaObject, variant); - qWarning() << "Putting" << value << putMethod.name() << ptr << typeId; putMethod.invokeOnGadget(ptr, Q_ARG(QVariant, value)); } @@ -378,7 +375,6 @@ QVariant JsonHandler::unpack(const QMetaObject &metaObject, const QVariant &valu // if it's an object, loop over all properties if (m_metaObjects.contains(typeName)) { - qWarning() << "*** Unpacking" << typeName; QVariantMap map = value.toMap(); int typeId = QMetaType::type(metaObject.className()); Q_ASSERT_X(typeId != 0, this->metaObject()->className(), QString("Cannot handle unregistered meta type %1").arg(typeName).toUtf8()); @@ -403,7 +399,6 @@ QVariant JsonHandler::unpack(const QMetaObject &metaObject, const QVariant &valu // recurse into child lists if (m_listMetaObjects.contains(propertyTypeName)) { QMetaObject propertyMetaObject = m_listMetaObjects.value(propertyTypeName); - qWarning() << "Entering list object" << propertyTypeName << propertyMetaObject.className(); metaProperty.writeOnGadget(ptr, unpack(propertyMetaObject, variant)); continue; } diff --git a/tests/auto/api.json b/tests/auto/api.json index 57f5c4e5..95483d3c 100644 --- a/tests/auto/api.json +++ b/tests/auto/api.json @@ -304,6 +304,7 @@ }, "methods": { "Actions.ExecuteAction": { + "deprecated": "Please use Devices.ExecuteAction instead.", "description": "Execute a single action.", "params": { "actionTypeId": "Uuid", @@ -316,6 +317,7 @@ } }, "Actions.ExecuteBrowserItem": { + "deprecated": "Please use Devices.ExecuteBrowserItem instead.", "description": "Execute the item identified by itemId on the given device.", "params": { "deviceId": "Uuid", @@ -326,6 +328,7 @@ } }, "Actions.ExecuteBrowserItemAction": { + "deprecated": "Please use Devices.ExecuteBrowserItem instead.", "description": "Execute the action for the browser item identified by actionTypeId and the itemId on the given device.", "params": { "actionTypeId": "Uuid", @@ -338,7 +341,8 @@ } }, "Actions.GetActionType": { - "description": "Get the ActionType for the given ActionTypeId", + "deprecated": "Please use the Devices namespace instead.", + "description": "Get the ActionType for the given ActionTypeId.", "params": { "actionTypeId": "Uuid" }, @@ -599,6 +603,40 @@ "deviceError": "$ref:DeviceError" } }, + "Devices.ExecuteAction": { + "description": "Execute a single action.", + "params": { + "actionTypeId": "Uuid", + "deviceId": "Uuid", + "o:params": "$ref:ParamList" + }, + "returns": { + "deviceError": "$ref:DeviceError", + "o:displayMessage": "String" + } + }, + "Devices.ExecuteBrowserItem": { + "description": "Execute the item identified by itemId on the given device.", + "params": { + "deviceId": "Uuid", + "itemId": "String" + }, + "returns": { + "deviceError": "$ref:DeviceError" + } + }, + "Devices.ExecuteBrowserItemAction": { + "description": "Execute the action for the browser item identified by actionTypeId and the itemId on the given device.", + "params": { + "actionTypeId": "Uuid", + "deviceId": "Uuid", + "itemId": "String", + "o:params": "$ref:ParamList" + }, + "returns": { + "deviceError": "$ref:DeviceError" + } + }, "Devices.GetActionTypes": { "description": "Get action types for a specified deviceClassId.", "params": { @@ -784,6 +822,7 @@ } }, "Events.GetEventType": { + "deprecated": "Please use the Devices namespace instead.", "description": "Get the EventType for the given eventTypeId.", "params": { "eventTypeId": "Uuid" @@ -1185,6 +1224,7 @@ } }, "States.GetStateType": { + "deprecated": "Please use the Devices namespace instead.", "description": "Get the StateType for the given stateTypeId.", "params": { "stateTypeId": "Uuid" @@ -1441,6 +1481,12 @@ "value": "Variant" } }, + "Devices.EventTriggered": { + "description": "Emitted whenever an Event is triggered.", + "params": { + "event": "$ref:Event" + } + }, "Devices.PluginConfigurationChanged": { "description": "Emitted whenever a plugin's configuration is changed.", "params": { @@ -1457,6 +1503,7 @@ } }, "Events.EventTriggered": { + "deprecated": "Please use Devices.EventTriggered instead.", "description": "Emitted whenever an Event is triggered.", "params": { "event": "$ref:Event" diff --git a/tests/auto/devices/testdevices.cpp b/tests/auto/devices/testdevices.cpp index 02ee3ea8..6a4a771a 100644 --- a/tests/auto/devices/testdevices.cpp +++ b/tests/auto/devices/testdevices.cpp @@ -26,6 +26,8 @@ #include "devices/devicediscoveryinfo.h" #include "devices/devicesetupinfo.h" +#include "servers/mocktcpserver.h" + using namespace nymeaserver; class TestDevices : public NymeaTestBase @@ -117,6 +119,14 @@ private slots: void testExecuteBrowserItemAction_data(); void testExecuteBrowserItemAction(); + void executeAction_data(); + void executeAction(); + + void triggerEvent(); + void triggerStateChangeEvent(); + + void params(); + // Keep those at last as they will remove devices void removeDevice_data(); void removeDevice(); @@ -1777,6 +1787,181 @@ void TestDevices::testExecuteBrowserItemAction() } +void TestDevices::executeAction_data() +{ + QTest::addColumn("deviceId"); + QTest::addColumn("actionTypeId"); + QTest::addColumn("actionParams"); + QTest::addColumn("error"); + + QVariantList params; + QVariantMap param1; + param1.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId); + param1.insert("value", 5); + params.append(param1); + QVariantMap param2; + param2.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId); + param2.insert("value", true); + params.append(param2); + + QTest::newRow("valid action") << m_mockDeviceId << mockWithParamsActionTypeId << params << Device::DeviceErrorNoError; + QTest::newRow("invalid deviceId") << DeviceId::createDeviceId() << mockWithParamsActionTypeId << params << Device::DeviceErrorDeviceNotFound; + QTest::newRow("invalid actionTypeId") << m_mockDeviceId << ActionTypeId::createActionTypeId() << params << Device::DeviceErrorActionTypeNotFound; + QTest::newRow("missing params") << m_mockDeviceId << mockWithParamsActionTypeId << QVariantList() << Device::DeviceErrorMissingParameter; + QTest::newRow("async action") << m_mockDeviceId << mockAsyncActionTypeId << QVariantList() << Device::DeviceErrorNoError; + QTest::newRow("broken action") << m_mockDeviceId << mockFailingActionTypeId << QVariantList() << Device::DeviceErrorSetupFailed; + QTest::newRow("async broken action") << m_mockDeviceId << mockAsyncFailingActionTypeId << QVariantList() << Device::DeviceErrorSetupFailed; +} + +void TestDevices::executeAction() +{ + QFETCH(DeviceId, deviceId); + QFETCH(ActionTypeId, actionTypeId); + QFETCH(QVariantList, actionParams); + QFETCH(Device::DeviceError, error); + + QVariantMap params; + params.insert("actionTypeId", actionTypeId); + params.insert("deviceId", deviceId); + params.insert("params", actionParams); + QVariant response = injectAndWait("Devices.ExecuteAction", params); + qDebug() << "executeActionresponse" << response; + verifyError(response, "deviceError", enumValueName(error)); + + // Fetch action execution history from mock device + QNetworkAccessManager nam; + QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*))); + + QNetworkRequest request(QUrl(QString("http://localhost:%1/actionhistory").arg(m_mockDevice1Port))); + QNetworkReply *reply = nam.get(request); + spy.wait(); + QCOMPARE(spy.count(), 1); + reply->deleteLater(); + QByteArray data = reply->readAll(); + + if (error == Device::DeviceErrorNoError) { + QVERIFY2(actionTypeId == ActionTypeId(data), QString("ActionTypeId mismatch. Got %1, Expected: %2") + .arg(ActionTypeId(data).toString()).arg(actionTypeId.toString()).toLatin1().data()); + } else { + QVERIFY2(data.length() == 0, QString("Data is %1, should be empty.").arg(QString(data)).toLatin1().data()); + } + + // cleanup for the next run + spy.clear(); + request.setUrl(QUrl(QString("http://localhost:%1/clearactionhistory").arg(m_mockDevice1Port))); + reply = nam.get(request); + spy.wait(); + QCOMPARE(spy.count(), 1); + reply->deleteLater(); + + 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(); + data = reply->readAll(); + qDebug() << "cleared data:" << data; + +} + +void TestDevices::triggerEvent() +{ + enableNotifications({"Devices"}); + QList devices = NymeaCore::instance()->deviceManager()->findConfiguredDevices(mockDeviceClassId); + QVERIFY2(devices.count() > 0, "There needs to be at least one configured Mock Device for this test"); + Device *device = devices.first(); + + + QSignalSpy spy(NymeaCore::instance(), SIGNAL(eventTriggered(const Event&))); + QSignalSpy notificationSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray))); + + // Setup connection to mock client + QNetworkAccessManager nam; + + // trigger event in mock device + int port = device->paramValue(mockDeviceHttpportParamTypeId).toInt(); + QNetworkRequest request(QUrl(QString("http://localhost:%1/generateevent?eventtypeid=%2").arg(port).arg(mockEvent1EventTypeId.toString()))); + QNetworkReply *reply = nam.get(request); + connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); + + // Lets wait for the notification + spy.wait(); + QVERIFY(spy.count() > 0); + for (int i = 0; i < spy.count(); i++ ){ + Event event = spy.at(i).at(0).value(); + if (event.deviceId() == device->id()) { + // Make sure the event contains all the stuff we expect + QCOMPARE(event.eventTypeId(), mockEvent1EventTypeId); + } + } + + // Check for the notification on JSON API + QVariantList notifications; + notifications = checkNotifications(notificationSpy, "Devices.EventTriggered"); + QVERIFY2(notifications.count() == 1, "Should get Devices.EventTriggered notification"); + QVariantMap notificationContent = notifications.first().toMap().value("params").toMap(); + + QCOMPARE(notificationContent.value("event").toMap().value("deviceId").toUuid().toString(), device->id().toString()); + QCOMPARE(notificationContent.value("event").toMap().value("eventTypeId").toUuid().toString(), mockEvent1EventTypeId.toString()); +} + +void TestDevices::triggerStateChangeEvent() +{ + enableNotifications({"Devices"}); + + QList devices = NymeaCore::instance()->deviceManager()->findConfiguredDevices(mockDeviceClassId); + QVERIFY2(devices.count() > 0, "There needs to be at least one configured Mock Device for this test"); + Device *device = devices.first(); + + QSignalSpy spy(NymeaCore::instance(), SIGNAL(eventTriggered(const Event&))); + QSignalSpy notificationSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray))); + + // Setup connection to mock client + QNetworkAccessManager nam; + + // trigger state changed event in mock device + int port = device->paramValue(mockDeviceHttpportParamTypeId).toInt(); + QNetworkRequest request(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(port).arg(mockIntStateTypeId.toString()).arg(11))); + QNetworkReply *reply = nam.get(request); + connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); + + // Lets wait for the notification + spy.wait(); + QVERIFY(spy.count() > 0); + for (int i = 0; i < spy.count(); i++ ){ + Event event = spy.at(i).at(0).value(); + if (event.deviceId() == device->id()) { + // Make sure the event contains all the stuff we expect + QCOMPARE(event.eventTypeId().toString(), mockIntStateTypeId.toString()); + QCOMPARE(event.param(ParamTypeId(mockIntStateTypeId.toString())).value().toInt(), 11); + } + } + + // Check for the notification on JSON API + QVariantList notifications; + notifications = checkNotifications(notificationSpy, "Devices.EventTriggered"); + QVERIFY2(notifications.count() == 1, "Should get Devices.EventTriggered notification"); + QVariantMap notificationContent = notifications.first().toMap().value("params").toMap(); + + QCOMPARE(notificationContent.value("event").toMap().value("deviceId").toUuid().toString(), device->id().toString()); + QCOMPARE(notificationContent.value("event").toMap().value("eventTypeId").toUuid().toString(), mockIntEventTypeId.toString()); + +} + +void TestDevices::params() +{ + Event event; + ParamList params; + ParamTypeId id = ParamTypeId::createParamTypeId(); + Param p(id, "foo bar"); + params.append(p); + event.setParams(params); + + QVERIFY(event.param(id).value().toString() == "foo bar"); + QVERIFY(!event.param(ParamTypeId::createParamTypeId()).value().isValid()); +} + #include "testdevices.moc" QTEST_MAIN(TestDevices) diff --git a/tests/auto/events/testevents.cpp b/tests/auto/events/testevents.cpp index 63005268..6edf2b86 100644 --- a/tests/auto/events/testevents.cpp +++ b/tests/auto/events/testevents.cpp @@ -22,6 +22,8 @@ #include "nymeatestbase.h" #include "nymeacore.h" +#include "servers/mocktcpserver.h" + using namespace nymeaserver; class TestEvents: public NymeaTestBase @@ -40,11 +42,14 @@ private slots: void TestEvents::triggerEvent() { + enableNotifications({"Events"}); + QList devices = NymeaCore::instance()->deviceManager()->findConfiguredDevices(mockDeviceClassId); QVERIFY2(devices.count() > 0, "There needs to be at least one configured Mock Device for this test"); Device *device = devices.first(); QSignalSpy spy(NymeaCore::instance(), SIGNAL(eventTriggered(const Event&))); + QSignalSpy notificationSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray))); // Setup connection to mock client QNetworkAccessManager nam; @@ -65,15 +70,28 @@ void TestEvents::triggerEvent() QCOMPARE(event.eventTypeId(), mockEvent1EventTypeId); } } + + // Check for the notification on JSON API + QVariantList notifications; + notifications = checkNotifications(notificationSpy, "Events.EventTriggered"); + QVERIFY2(notifications.count() == 1, "Should get Events.EventTriggered notification"); + QVERIFY2(notifications.first().toMap().contains("deprecationWarning"), "Deprecation warning not included in notification"); + + QVariantMap notificationContent = notifications.first().toMap().value("params").toMap(); + QCOMPARE(notificationContent.value("event").toMap().value("deviceId").toUuid().toString(), device->id().toString()); + QCOMPARE(notificationContent.value("event").toMap().value("eventTypeId").toUuid().toString(), mockEvent1EventTypeId.toString()); } void TestEvents::triggerStateChangeEvent() { + enableNotifications({"Events"}); + QList devices = NymeaCore::instance()->deviceManager()->findConfiguredDevices(mockDeviceClassId); QVERIFY2(devices.count() > 0, "There needs to be at least one configured Mock Device for this test"); Device *device = devices.first(); QSignalSpy spy(NymeaCore::instance(), SIGNAL(eventTriggered(const Event&))); + QSignalSpy notificationSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray))); // Setup connection to mock client QNetworkAccessManager nam; @@ -95,6 +113,17 @@ void TestEvents::triggerStateChangeEvent() QCOMPARE(event.param(ParamTypeId(mockIntStateTypeId.toString())).value().toInt(), 11); } } + + // Check for the notification on JSON API + QVariantList notifications; + notifications = checkNotifications(notificationSpy, "Events.EventTriggered"); + QVERIFY2(notifications.count() == 1, "Should get Devices.EventTriggered notification"); + QVERIFY2(notifications.first().toMap().contains("deprecationWarning"), "Deprecation warning not included in notification!"); + + QVariantMap notificationContent = notifications.first().toMap().value("params").toMap(); + + QCOMPARE(notificationContent.value("event").toMap().value("deviceId").toUuid().toString(), device->id().toString()); + QCOMPARE(notificationContent.value("event").toMap().value("eventTypeId").toUuid().toString(), mockIntEventTypeId.toString()); } void TestEvents::params() @@ -130,6 +159,9 @@ void TestEvents::getEventType() verifyError(response, "deviceError", enumValueName(error)); + qCDebug(dcTests()) << "*content" << response; + QVERIFY2(response.toMap().contains("deprecationWarning"), "Deprecation warning not shown in reply"); + if (error == Device::DeviceErrorNoError) { QVERIFY2(EventTypeId(response.toMap().value("params").toMap().value("eventType").toMap().value("id").toString()) == eventTypeId, "Didn't get a reply for the same actionTypeId as requested."); }