diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 449d6ef6..f7ac36cf 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -17,5 +17,5 @@ SUBDIRS = versioning \ websocketserver \ coap \ logging \ - + restlogging \ diff --git a/tests/auto/restdeviceclasses/testrestdeviceclasses.cpp b/tests/auto/restdeviceclasses/testrestdeviceclasses.cpp index 4b80a8d8..5734befa 100644 --- a/tests/auto/restdeviceclasses/testrestdeviceclasses.cpp +++ b/tests/auto/restdeviceclasses/testrestdeviceclasses.cpp @@ -44,6 +44,7 @@ class TestRestDeviceClasses: public GuhTestBase private slots: void getSupportedDevices(); + void invalidMethod(); void getActionTypes_data(); void getActionTypes(); @@ -80,6 +81,7 @@ void TestRestDeviceClasses::getSupportedDevices() QVERIFY2(!response.isNull(), "Could not get device"); } + // get with vendor filter QUrlQuery query; query.addQueryItem("vendorId", guhVendorId.toString()); url.setQuery(query); @@ -88,6 +90,33 @@ void TestRestDeviceClasses::getSupportedDevices() deviceClassesList = response.toList(); QVERIFY2(deviceClassesList.count() > 0, "Not enought deviceclasses."); + // get with invalid vendor filter + query.clear(); + query.addQueryItem("vendorId", "uuid"); + url.setQuery(query); + + response = getAndWait(QNetworkRequest(url), 400); + QCOMPARE(JsonTypes::deviceErrorToString(DeviceManager::DeviceErrorVendorNotFound), response.toMap().value("error").toString()); +} + +void TestRestDeviceClasses::invalidMethod() +{ + QNetworkAccessManager nam; + QSignalSpy clientSpy(&nam, SIGNAL(finished(QNetworkReply*))); + + QNetworkRequest request; + request.setUrl(QUrl("http://localhost:3333/api/v1/deviceclasses/")); + QNetworkReply *reply = nam.post(request, QByteArray()); + + clientSpy.wait(); + QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver"); + + bool ok = false; + int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(&ok); + QVERIFY2(ok, "Could not convert statuscode from response to int"); + QCOMPARE(statusCode, 400); + + reply->deleteLater(); } void TestRestDeviceClasses::getActionTypes_data() diff --git a/tests/auto/restdevices/testrestdevices.cpp b/tests/auto/restdevices/testrestdevices.cpp index 7f24f568..9235efa9 100644 --- a/tests/auto/restdevices/testrestdevices.cpp +++ b/tests/auto/restdevices/testrestdevices.cpp @@ -487,21 +487,23 @@ void TestRestDevices::getStateValue_data() QVERIFY2(devices.count() > 0, "There needs to be at least one configured Mock Device for this test"); Device *device = devices.first(); - QTest::addColumn("deviceId"); - QTest::addColumn("stateTypeId"); + QTest::addColumn("deviceId"); + QTest::addColumn("stateTypeId"); QTest::addColumn("expectedStatusCode"); QTest::addColumn("error"); - QTest::newRow("existing state") << device->id() << mockIntStateId << 200 << DeviceManager::DeviceErrorNoError; - QTest::newRow("all states") << device->id() << StateTypeId() << 200 << DeviceManager::DeviceErrorNoError; - QTest::newRow("invalid device") << DeviceId::createDeviceId() << mockIntStateId << 404 << DeviceManager::DeviceErrorDeviceNotFound; - QTest::newRow("invalid statetype") << device->id() << StateTypeId::createStateTypeId() << 404 << DeviceManager::DeviceErrorStateTypeNotFound; + QTest::newRow("existing state") << device->id().toString() << mockIntStateId.toString() << 200 << DeviceManager::DeviceErrorNoError; + QTest::newRow("all states") << device->id().toString() << QString() << 200 << DeviceManager::DeviceErrorNoError; + QTest::newRow("invalid device") << DeviceId::createDeviceId().toString() << mockIntStateId.toString() << 404 << DeviceManager::DeviceErrorDeviceNotFound; + QTest::newRow("invalid device id format") << "uuid" << StateTypeId::createStateTypeId().toString() << 400 << DeviceManager::DeviceErrorDeviceNotFound; + QTest::newRow("invalid statetype") << device->id().toString() << StateTypeId::createStateTypeId().toString() << 404 << DeviceManager::DeviceErrorStateTypeNotFound; + QTest::newRow("invalid statetype format") << device->id().toString() << "uuid" << 400 << DeviceManager::DeviceErrorStateTypeNotFound; } void TestRestDevices::getStateValue() { - QFETCH(DeviceId, deviceId); - QFETCH(StateTypeId, stateTypeId); + QFETCH(QString, deviceId); + QFETCH(QString, stateTypeId); QFETCH(int, expectedStatusCode); QFETCH(DeviceManager::DeviceError, error); @@ -509,10 +511,10 @@ void TestRestDevices::getStateValue() request.setHeader(QNetworkRequest::ContentTypeHeader, "text/json"); if (!stateTypeId.isNull()) { - request.setUrl(QUrl(QString("http://localhost:3333/api/v1/devices/%1/states/%2").arg(deviceId.toString()).arg(stateTypeId.toString()))); + request.setUrl(QUrl(QString("http://localhost:3333/api/v1/devices/%1/states/%2").arg(deviceId).arg(stateTypeId))); } else { // Get all states - request.setUrl(QUrl(QString("http://localhost:3333/api/v1/devices/%1/states").arg(deviceId.toString()))); + request.setUrl(QUrl(QString("http://localhost:3333/api/v1/devices/%1/states").arg(deviceId))); } QVariant response = getAndWait(request, expectedStatusCode); QVERIFY2(!response.isNull(), "Could not read get state value response"); diff --git a/tests/auto/restlogging/restlogging.pro b/tests/auto/restlogging/restlogging.pro new file mode 100644 index 00000000..f321deba --- /dev/null +++ b/tests/auto/restlogging/restlogging.pro @@ -0,0 +1,5 @@ +include(../../../guh.pri) +include(../autotests.pri) + +TARGET = testrestlogging +SOURCES += testrestlogging.cpp diff --git a/tests/auto/restlogging/testrestlogging.cpp b/tests/auto/restlogging/testrestlogging.cpp new file mode 100644 index 00000000..9b0d26de --- /dev/null +++ b/tests/auto/restlogging/testrestlogging.cpp @@ -0,0 +1,371 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stuerz * + * Copyright (C) 2014 Michael Zanetti * + * * + * 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 "guhsettings.h" +#include "plugin/deviceplugin.h" + +#include +#include +#include +#include +#include + +using namespace guhserver; + +class TestRestLogging : public GuhTestBase +{ + Q_OBJECT + +private: + +private slots: + void initLogs(); + void systemLogs(); + + void invalidFilter_data(); + void invalidFilter(); + + void eventLogs(); + void actionLog(); + + // this has to be the last test + void removeDevice(); +}; + +void TestRestLogging::initLogs() +{ + QNetworkRequest request(QUrl("http://localhost:3333/api/v1/logs")); + QVariant response = getAndWait(request); + + QVariantList logEntries = response.toList(); + qDebug() << "Got" << logEntries.count() << "logs"; + QVERIFY(logEntries.count() > 0); + + clearLoggingDatabase(); + + response = getAndWait(request); + logEntries = response.toList(); + qDebug() << "Got" << logEntries.count() << "logs"; + QVERIFY(logEntries.count() == 0); + + restartServer(); +} + +void TestRestLogging::systemLogs() +{ + // check the active system log at boot + QVariantMap params; + params.insert("loggingSources", QVariantList() << JsonTypes::loggingSourceToString(Logging::LoggingSourceSystem)); + params.insert("eventTypes", QVariantList() << JsonTypes::loggingEventTypeToString(Logging::LoggingEventTypeActiveChange)); + + QUrl url("http://localhost:3333/api/v1/logs"); + QUrlQuery query; + query.addQueryItem("filter", QJsonDocument::fromVariant(params).toJson(QJsonDocument::Compact)); + url.setQuery(query); + + // there should be 2 logs, one for shutdown, one for startup (from server restart) + QVariant response = getAndWait(QNetworkRequest(url)); + QVariantList logEntries = response.toList(); + QVERIFY(logEntries.count() == 2); + + QVariantMap logEntryShutdown = logEntries.first().toMap(); + + QCOMPARE(logEntryShutdown.value("active").toBool(), false); + QCOMPARE(logEntryShutdown.value("eventType").toString(), JsonTypes::loggingEventTypeToString(Logging::LoggingEventTypeActiveChange)); + QCOMPARE(logEntryShutdown.value("source").toString(), JsonTypes::loggingSourceToString(Logging::LoggingSourceSystem)); + QCOMPARE(logEntryShutdown.value("loggingLevel").toString(), JsonTypes::loggingLevelToString(Logging::LoggingLevelInfo)); + + QVariantMap logEntryStartup = logEntries.last().toMap(); + + QCOMPARE(logEntryStartup.value("active").toBool(), true); + QCOMPARE(logEntryStartup.value("eventType").toString(), JsonTypes::loggingEventTypeToString(Logging::LoggingEventTypeActiveChange)); + QCOMPARE(logEntryStartup.value("source").toString(), JsonTypes::loggingSourceToString(Logging::LoggingSourceSystem)); + QCOMPARE(logEntryStartup.value("loggingLevel").toString(), JsonTypes::loggingLevelToString(Logging::LoggingLevelInfo)); +} + +void TestRestLogging::invalidFilter_data() +{ + QVariantMap invalidSourcesFilter; + invalidSourcesFilter.insert("loggingSources", QVariantList() << "bla"); + + QVariantMap invalidFilterValue; + invalidFilterValue.insert("loggingSource", QVariantList() << "bla"); + + QVariantMap invalidTypeIds; + invalidTypeIds.insert("typeId", QVariantList() << "bla" << "blub"); + + QVariantMap invalidEventTypes; + invalidEventTypes.insert("eventTypes", QVariantList() << JsonTypes::loggingEventTypeToString(Logging::LoggingEventTypeTrigger) << "blub"); + + QTest::addColumn("filter"); + + QTest::newRow("Invalid source") << invalidSourcesFilter; + QTest::newRow("Invalid filter value") << invalidFilterValue; + QTest::newRow("Invalid typeIds") << invalidTypeIds; + QTest::newRow("Invalid eventTypes") << invalidEventTypes; +} + +void TestRestLogging::invalidFilter() +{ + QFETCH(QVariantMap, filter); + + QUrl url("http://localhost:3333/api/v1/logs"); + QUrlQuery query; + query.addQueryItem("filter", QJsonDocument::fromVariant(filter).toJson(QJsonDocument::Compact)); + url.setQuery(query); + + // there should be 2 logs, one for shutdown, one for startup (from server restart) + QVariant response = getAndWait(QNetworkRequest(url)); + QVERIFY(!response.isNull()); + + // TODO: validate filter for REST api +} + + +void TestRestLogging::eventLogs() +{ + QList devices = GuhCore::instance()->findConfiguredDevices(mockDeviceClassId); + QVERIFY2(devices.count() > 0, "There needs to be at least one configured Mock Device for this test"); + Device *device = devices.first(); + + // enable notifications + QCOMPARE(enableNotifications(), true); + + // Setup connection to mock client + QNetworkAccessManager nam; + QSignalSpy clientSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray))); + + // trigger event in mock device + int port = device->paramValue("httpport").toInt(); + QNetworkRequest request(QUrl(QString("http://localhost:%1/generateevent?eventtypeid=%2").arg(port).arg(mockEvent1Id.toString()))); + QNetworkReply *reply = nam.get(request); + + // Lets wait for the notification + clientSpy.wait(200); + QVariant notification = checkNotification(clientSpy, "Logging.LogEntryAdded"); + QVERIFY(!notification.isNull()); + reply->deleteLater(); + + QVariantMap logEntry = notification.toMap().value("params").toMap().value("logEntry").toMap(); + + // Make sure the notification contains all the stuff we expect + QCOMPARE(logEntry.value("typeId").toString(), mockEvent1Id.toString()); + QCOMPARE(logEntry.value("deviceId").toString(), device->id().toString()); + QCOMPARE(logEntry.value("eventType").toString(), JsonTypes::loggingEventTypeToString(Logging::LoggingEventTypeTrigger)); + QCOMPARE(logEntry.value("source").toString(), JsonTypes::loggingSourceToString(Logging::LoggingSourceEvents)); + QCOMPARE(logEntry.value("loggingLevel").toString(), JsonTypes::loggingLevelToString(Logging::LoggingLevelInfo)); + + // get this logentry with filter + QVariantMap params; + params.insert("deviceIds", QVariantList() << device->id()); + params.insert("loggingSources", QVariantList() << JsonTypes::loggingSourceToString(Logging::LoggingSourceEvents)); + params.insert("eventTypes", QVariantList() << JsonTypes::loggingEventTypeToString(Logging::LoggingEventTypeTrigger)); + params.insert("typeIds", QVariantList() << mockEvent1Id); + + QVariant response = injectAndWait("Logging.GetLogEntries", params); + verifyLoggingError(response); + + QVariantList logEntries = response.toMap().value("params").toMap().value("logEntries").toList(); + QVERIFY(logEntries.count() == 1); + + // disable notifications + QCOMPARE(disableNotifications(), true); +} + +void TestRestLogging::actionLog() +{ + QVariantList actionParams; + QVariantMap param1; + param1.insert("name", "mockActionParam1"); + param1.insert("value", 7); + actionParams.append(param1); + QVariantMap param2; + param2.insert("name", "mockActionParam2"); + param2.insert("value", true); + actionParams.append(param2); + + QVariantMap params; + params.insert("actionTypeId", mockActionIdWithParams); + params.insert("deviceId", m_mockDeviceId); + params.insert("params", actionParams); + + // enable notifications + QCOMPARE(enableNotifications(), true); + + QSignalSpy clientSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray))); + + // EXECUTE with params + QVariant response = injectAndWait("Actions.ExecuteAction", params); + verifyDeviceError(response); + + // Lets wait 3for the notification + clientSpy.wait(200); + QVariant notification = checkNotification(clientSpy, "Logging.LogEntryAdded"); + QVERIFY(!notification.isNull()); + + QVariantMap logEntry = notification.toMap().value("params").toMap().value("logEntry").toMap(); + + // Make sure the notification contains all the stuff we expect + QCOMPARE(logEntry.value("typeId").toString(), mockActionIdWithParams.toString()); + QCOMPARE(logEntry.value("deviceId").toString(), m_mockDeviceId.toString()); + QCOMPARE(logEntry.value("eventType").toString(), JsonTypes::loggingEventTypeToString(Logging::LoggingEventTypeTrigger)); + QCOMPARE(logEntry.value("source").toString(), JsonTypes::loggingSourceToString(Logging::LoggingSourceActions)); + QCOMPARE(logEntry.value("loggingLevel").toString(), JsonTypes::loggingLevelToString(Logging::LoggingLevelInfo)); + + // EXECUTE without params + params.clear(); clientSpy.clear(); + params.insert("actionTypeId", mockActionIdNoParams); + params.insert("deviceId", m_mockDeviceId); + response = injectAndWait("Actions.ExecuteAction", params); + verifyDeviceError(response); + + clientSpy.wait(200); + notification = checkNotification(clientSpy, "Logging.LogEntryAdded"); + QVERIFY(!notification.isNull()); + + // get this logentry with filter + params.clear(); + params.insert("deviceIds", QVariantList() << m_mockDeviceId); + params.insert("loggingSources", QVariantList() << JsonTypes::loggingSourceToString(Logging::LoggingSourceActions)); + params.insert("eventTypes", QVariantList() << JsonTypes::loggingEventTypeToString(Logging::LoggingEventTypeTrigger)); + params.insert("values", QVariantList() << "7, true"); + + QUrl url("http://localhost:3333/api/v1/logs"); + QUrlQuery query; + query.addQueryItem("filter", QJsonDocument::fromVariant(params).toJson(QJsonDocument::Compact)); + url.setQuery(query); + + response = getAndWait(QNetworkRequest(url)); + QVariantList logEntries = response.toList(); + QCOMPARE(logEntries.count(), 1); + + // EXECUTE broken action + params.clear(); clientSpy.clear(); + params.insert("actionTypeId", mockActionIdFailing); + params.insert("deviceId", m_mockDeviceId); + response = injectAndWait("Actions.ExecuteAction", params); + verifyDeviceError(response, DeviceManager::DeviceErrorSetupFailed); + + clientSpy.wait(200); + notification = checkNotification(clientSpy, "Logging.LogEntryAdded"); + QVERIFY(!notification.isNull()); + + logEntry = notification.toMap().value("params").toMap().value("logEntry").toMap(); + + // Make sure the notification contains all the stuff we expect + QCOMPARE(logEntry.value("typeId").toString(), mockActionIdFailing.toString()); + QCOMPARE(logEntry.value("deviceId").toString(), m_mockDeviceId.toString()); + QCOMPARE(logEntry.value("eventType").toString(), JsonTypes::loggingEventTypeToString(Logging::LoggingEventTypeTrigger)); + QCOMPARE(logEntry.value("source").toString(), JsonTypes::loggingSourceToString(Logging::LoggingSourceActions)); + QCOMPARE(logEntry.value("loggingLevel").toString(), JsonTypes::loggingLevelToString(Logging::LoggingLevelAlert)); + QCOMPARE(logEntry.value("errorCode").toString(), JsonTypes::deviceErrorToString(DeviceManager::DeviceErrorSetupFailed)); + + // get this logentry with filter + params.clear(); + params.insert("deviceIds", QVariantList() << m_mockDeviceId); + params.insert("loggingSources", QVariantList() << JsonTypes::loggingSourceToString(Logging::LoggingSourceActions)); + params.insert("eventTypes", QVariantList() << JsonTypes::loggingEventTypeToString(Logging::LoggingEventTypeTrigger)); + params.insert("values", QVariantList() << "7, true"); + + query.clear(); + query.addQueryItem("filter", QJsonDocument::fromVariant(params).toJson(QJsonDocument::Compact)); + url.setQuery(query); + + response = getAndWait(QNetworkRequest(url)); + logEntries = response.toList(); + QCOMPARE(logEntries.count(), 1); + + // check different filters + params.clear(); + params.insert("deviceIds", QVariantList() << m_mockDeviceId); + params.insert("loggingSources", QVariantList() << JsonTypes::loggingSourceToString(Logging::LoggingSourceActions)); + params.insert("eventTypes", QVariantList() << JsonTypes::loggingEventTypeToString(Logging::LoggingEventTypeTrigger)); + params.insert("typeIds", QVariantList() << mockActionIdNoParams); + + query.clear(); + query.addQueryItem("filter", QJsonDocument::fromVariant(params).toJson(QJsonDocument::Compact)); + url.setQuery(query); + + response = getAndWait(QNetworkRequest(url)); + logEntries = response.toList(); + QCOMPARE(logEntries.count(), 1); + + params.clear(); + params.insert("deviceIds", QVariantList() << m_mockDeviceId); + params.insert("loggingSources", QVariantList() << JsonTypes::loggingSourceToString(Logging::LoggingSourceActions)); + params.insert("eventTypes", QVariantList() << JsonTypes::loggingEventTypeToString(Logging::LoggingEventTypeTrigger)); + params.insert("typeIds", QVariantList() << mockActionIdNoParams << mockActionIdWithParams << mockActionIdFailing); + + query.clear(); + query.addQueryItem("filter", QJsonDocument::fromVariant(params).toJson(QJsonDocument::Compact)); + url.setQuery(query); + + response = getAndWait(QNetworkRequest(url)); + logEntries = response.toList(); + QCOMPARE(logEntries.count(), 3); + + // disable notifications + QCOMPARE(disableNotifications(), true); +} + +void TestRestLogging::removeDevice() +{ + // enable notifications + QCOMPARE(enableNotifications(), true); + + QSignalSpy clientSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray))); + + QNetworkRequest deleteRequest(QUrl(QString("http://localhost:3333/api/v1/devices/%1").arg(m_mockDeviceId.toString()))); + QVariant response = deleteAndWait(deleteRequest); + QVERIFY2(!response.isNull(), "Could not delete device"); + + clientSpy.wait(200); + QVariant notification = checkNotification(clientSpy, "Logging.LogDatabaseUpdated"); + QVERIFY(!notification.isNull()); + + // get this logentry with filter + QUrl url("http://localhost:3333/api/v1/logs"); + response = getAndWait(QNetworkRequest(url)); + QVariantList logEntries = response.toList(); + QVERIFY(logEntries.count() > 0); + + // verify that the logs from this device where removed from the db + QVariantMap params; + params.insert("deviceIds", QVariantList() << m_mockDeviceId); + QUrlQuery query; + query.addQueryItem("filter", QJsonDocument::fromVariant(params).toJson(QJsonDocument::Compact)); + url.setQuery(query); + + response = getAndWait(QNetworkRequest(url)); + logEntries = response.toList(); + + QCOMPARE(logEntries.count(), 0); + + // disable notifications + QCOMPARE(disableNotifications(), true); +} + +#include "testrestlogging.moc" +QTEST_MAIN(TestRestLogging) + diff --git a/tests/auto/restvendors/testrestvendors.cpp b/tests/auto/restvendors/testrestvendors.cpp index da646cab..00b808ec 100644 --- a/tests/auto/restvendors/testrestvendors.cpp +++ b/tests/auto/restvendors/testrestvendors.cpp @@ -70,12 +70,12 @@ void TestRestVendors::getVendors() void TestRestVendors::invalidMethod() { - QNetworkAccessManager *nam = new QNetworkAccessManager(this); - QSignalSpy clientSpy(nam, SIGNAL(finished(QNetworkReply*))); + QNetworkAccessManager nam; + QSignalSpy clientSpy(&nam, SIGNAL(finished(QNetworkReply*))); QNetworkRequest request; request.setUrl(QUrl("http://localhost:3333/api/v1/vendors")); - QNetworkReply *reply = nam->post(request, QByteArray()); + QNetworkReply *reply = nam.post(request, QByteArray()); clientSpy.wait(); QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver"); @@ -86,17 +86,16 @@ void TestRestVendors::invalidMethod() QCOMPARE(statusCode, 400); reply->deleteLater(); - nam->deleteLater(); } void TestRestVendors::invalidPath() { - QNetworkAccessManager *nam = new QNetworkAccessManager(this); - QSignalSpy clientSpy(nam, SIGNAL(finished(QNetworkReply*))); + QNetworkAccessManager nam; + QSignalSpy clientSpy(&nam, SIGNAL(finished(QNetworkReply*))); QNetworkRequest request; request.setUrl(QUrl("http://localhost:3333/api/v1/vendors/" + QUuid::createUuid().toString() + "/" + QUuid::createUuid().toString())); - QNetworkReply *reply = nam->get(request); + QNetworkReply *reply = nam.get(request); clientSpy.wait(); QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver"); @@ -107,7 +106,6 @@ void TestRestVendors::invalidPath() QCOMPARE(statusCode, 501); reply->deleteLater(); - nam->deleteLater(); } void TestRestVendors::invalidVendor_data()