mirror of https://github.com/nymea/nymea.git
790 lines
31 KiB
C++
790 lines
31 KiB
C++
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
*
|
|
* Copyright 2013 - 2020, nymea GmbH
|
|
* Contact: contact@nymea.io
|
|
*
|
|
* This file is part of nymea.
|
|
* This project including source code and documentation is protected by
|
|
* copyright law, and remains the property of nymea GmbH. All rights, including
|
|
* reproduction, publication, editing and translation, are reserved. The use of
|
|
* this project is subject to the terms of a license agreement to be concluded
|
|
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
|
|
* under https://nymea.io/license
|
|
*
|
|
* GNU General Public License Usage
|
|
* Alternatively, this project may be redistributed and/or modified under the
|
|
* terms of the GNU General Public License as published by the Free Software
|
|
* Foundation, GNU version 3. This project 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
|
|
* this project. If not, see <https://www.gnu.org/licenses/>.
|
|
*
|
|
* For any further details and any questions please contact us under
|
|
* contact@nymea.io or see our FAQ/Licensing Information on
|
|
* https://nymea.io/license/faq
|
|
*
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
#include "nymeatestbase.h"
|
|
#include "nymeacore.h"
|
|
#include "nymeasettings.h"
|
|
#include "logging/logvaluetool.h"
|
|
#include "servers/mocktcpserver.h"
|
|
|
|
#include "../plugins/mock/extern-plugininfo.h"
|
|
|
|
#include <qglobal.h>
|
|
|
|
using namespace nymeaserver;
|
|
|
|
class TestLogging : public NymeaTestBase
|
|
{
|
|
Q_OBJECT
|
|
|
|
private:
|
|
|
|
inline void verifyLoggingError(const QVariant &response, Logging::LoggingError error = Logging::LoggingErrorNoError) {
|
|
verifyError(response, "loggingError", enumValueName(error));
|
|
}
|
|
inline void verifyThingError(const QVariant &response, Thing::ThingError error = Thing::ThingErrorNoError) {
|
|
verifyError(response, "thingError", enumValueName(error));
|
|
}
|
|
// DEPRECTATED
|
|
inline void verifyDeviceError(const QVariant &response, Thing::ThingError error = Thing::ThingErrorNoError) {
|
|
verifyError(response, "deviceError", enumValueName(error).replace("Thing", "Device"));
|
|
}
|
|
|
|
private slots:
|
|
void initTestCase();
|
|
void init();
|
|
|
|
void initLogs();
|
|
|
|
void databaseSerializationTest_data();
|
|
void databaseSerializationTest();
|
|
|
|
void coverageCalls();
|
|
|
|
void systemLogs();
|
|
|
|
void invalidFilter_data();
|
|
void invalidFilter();
|
|
|
|
void eventLogs_data();
|
|
void eventLogs();
|
|
|
|
void actionLog();
|
|
|
|
void thingLogs();
|
|
|
|
void testDoubleValues();
|
|
|
|
void testHouseKeeping();
|
|
|
|
void testLimits();
|
|
|
|
// this has to be the last test
|
|
void removeThing();
|
|
};
|
|
|
|
void TestLogging::initTestCase()
|
|
{
|
|
NymeaTestBase::initTestCase();
|
|
QLoggingCategory::setFilterRules("*.debug=false\n"
|
|
"LogEngine.debug=true\n"
|
|
"Tests.debug=true\n"
|
|
"MockDevice.debug=true\n"
|
|
"DeviceManager.debug=true\n"
|
|
"Application.debug=true\n");
|
|
}
|
|
|
|
void TestLogging::init()
|
|
{
|
|
waitForDBSync();
|
|
}
|
|
|
|
void TestLogging::initLogs()
|
|
{
|
|
QVariant response = injectAndWait("Logging.GetLogEntries");
|
|
verifyLoggingError(response);
|
|
|
|
QVariantList logEntries = response.toMap().value("params").toMap().value("logEntries").toList();
|
|
QVERIFY2(logEntries.count() > 0,
|
|
QString("Expected at least one log entry.")
|
|
.toUtf8());
|
|
|
|
clearLoggingDatabase();
|
|
waitForDBSync();
|
|
|
|
response = injectAndWait("Logging.GetLogEntries");
|
|
verifyLoggingError(response);
|
|
logEntries = response.toMap().value("params").toMap().value("logEntries").toList();
|
|
QVERIFY(logEntries.count() == 0);
|
|
|
|
restartServer();
|
|
NymeaCore::instance()->logEngine()->setMaxLogEntries(1000, 10);
|
|
}
|
|
|
|
void TestLogging::databaseSerializationTest_data()
|
|
{
|
|
QUuid uuid = QUuid("3782732b-61b4-48e8-8d6d-b5205159d7cd");
|
|
|
|
QVariantMap variantMap;
|
|
variantMap.insert("string", "value");
|
|
variantMap.insert("int", 5);
|
|
variantMap.insert("double", 3.14);
|
|
variantMap.insert("uuid", uuid);
|
|
|
|
QVariantList variantList;
|
|
variantList.append(variantMap);
|
|
variantList.append("String");
|
|
variantList.append(3.14);
|
|
variantList.append(uuid);
|
|
|
|
QTest::addColumn<QVariant>("value");
|
|
|
|
QTest::newRow("QString") << QVariant(QString("Hello"));
|
|
QTest::newRow("Integer") << QVariant((int)2);
|
|
QTest::newRow("Double") << QVariant((double)2.34);
|
|
QTest::newRow("Float") << QVariant((float)2.34);
|
|
QTest::newRow("QColor") << QVariant(QColor(0,255,128));
|
|
QTest::newRow("QByteArray") << QVariant(QByteArray("\nthisisatestarray\n"));
|
|
QTest::newRow("QUuid") << QVariant(uuid);
|
|
QTest::newRow("QVariantMap") << QVariant(variantMap);
|
|
QTest::newRow("QVariantList") << QVariant(variantList);
|
|
}
|
|
|
|
void TestLogging::databaseSerializationTest()
|
|
{
|
|
QFETCH(QVariant, value);
|
|
|
|
QString serializedValue = LogValueTool::serializeValue(value);
|
|
QVariant deserializedValue = LogValueTool::deserializeValue(serializedValue);
|
|
|
|
qDebug() << "Stored:" << value;
|
|
qDebug() << "Loaded:" << deserializedValue;
|
|
QCOMPARE(deserializedValue, value);
|
|
}
|
|
|
|
void TestLogging::coverageCalls()
|
|
{
|
|
LogEntry entry(QDateTime::currentDateTime(), Logging::LoggingLevelInfo, Logging::LoggingSourceSystem);
|
|
qDebug() << entry;
|
|
|
|
LogFilter filter;
|
|
qDebug() << filter.queryString() << filter.timeFilters();
|
|
}
|
|
|
|
void TestLogging::systemLogs()
|
|
{
|
|
qWarning() << "Clearing logging DB";
|
|
clearLoggingDatabase();
|
|
|
|
waitForDBSync();
|
|
|
|
QVariantMap params;
|
|
params.insert("loggingSources", QVariantList() << enumValueName(Logging::LoggingSourceSystem));
|
|
params.insert("eventTypes", QVariantList() << enumValueName(Logging::LoggingEventTypeActiveChange));
|
|
|
|
// there should be 0 log entries
|
|
QVariant response = injectAndWait("Logging.GetLogEntries", params);
|
|
QVariantList logEntries = response.toMap().value("params").toMap().value("logEntries").toList();
|
|
QVERIFY2(logEntries.count() == 0,
|
|
QString("Expected 0 log entries but got:\n%1")
|
|
.arg(QString(QJsonDocument::fromVariant(logEntries).toJson()))
|
|
.toUtf8());
|
|
|
|
// check the active system log at boot
|
|
qWarning() << "Restarting server";
|
|
restartServer();
|
|
qWarning() << "Restart done";
|
|
waitForDBSync();
|
|
|
|
// there should be 2 log entries, one for shutdown, one for startup (from server restart)
|
|
response = injectAndWait("Logging.GetLogEntries", params);
|
|
verifyLoggingError(response);
|
|
logEntries = response.toMap().value("params").toMap().value("logEntries").toList();
|
|
QVERIFY2(logEntries.count() == 2,
|
|
QString("Expected 2 log entries but got:\n%1")
|
|
.arg(QString(QJsonDocument::fromVariant(logEntries).toJson()))
|
|
.toUtf8());
|
|
|
|
QVariantMap logEntryStartup = logEntries.first().toMap();
|
|
QVariantMap logEntryShutdown = logEntries.last().toMap();
|
|
// We cannot rely on the order those events
|
|
if (!logEntryStartup.value("active").toBool()) {
|
|
logEntryStartup = logEntries.last().toMap();
|
|
logEntryShutdown = logEntries.first().toMap();
|
|
}
|
|
|
|
QCOMPARE(logEntryShutdown.value("active").toBool(), false);
|
|
QCOMPARE(logEntryShutdown.value("eventType").toString(), enumValueName(Logging::LoggingEventTypeActiveChange));
|
|
QCOMPARE(logEntryShutdown.value("source").toString(), enumValueName(Logging::LoggingSourceSystem));
|
|
QCOMPARE(logEntryShutdown.value("loggingLevel").toString(), enumValueName(Logging::LoggingLevelInfo));
|
|
|
|
|
|
QCOMPARE(logEntryStartup.value("active").toBool(), true);
|
|
QCOMPARE(logEntryStartup.value("eventType").toString(), enumValueName(Logging::LoggingEventTypeActiveChange));
|
|
QCOMPARE(logEntryStartup.value("source").toString(), enumValueName(Logging::LoggingSourceSystem));
|
|
QCOMPARE(logEntryStartup.value("loggingLevel").toString(), enumValueName(Logging::LoggingLevelInfo));
|
|
}
|
|
|
|
void TestLogging::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() << enumValueName(Logging::LoggingEventTypeTrigger) << "blub");
|
|
|
|
QTest::addColumn<QVariantMap>("filter");
|
|
|
|
QTest::newRow("Invalid source") << invalidSourcesFilter;
|
|
QTest::newRow("Invalid filter value") << invalidFilterValue;
|
|
QTest::newRow("Invalid typeIds") << invalidTypeIds;
|
|
QTest::newRow("Invalid eventTypes") << invalidEventTypes;
|
|
}
|
|
|
|
void TestLogging::invalidFilter()
|
|
{
|
|
QFETCH(QVariantMap, filter);
|
|
QVariant response = injectAndWait("Logging.GetLogEntries", filter);
|
|
QVERIFY(!response.isNull());
|
|
|
|
// verify json error
|
|
QVERIFY(response.toMap().value("status").toString() == "error");
|
|
qDebug() << response.toMap().value("error").toString();
|
|
}
|
|
|
|
void TestLogging::eventLogs_data()
|
|
{
|
|
QTest::addColumn<StateTypeId>("stateTypeId");
|
|
QTest::addColumn<QVariant>("initValue");
|
|
QTest::addColumn<QVariant>("newValue");
|
|
QTest::addColumn<bool>("expectLogEntry");
|
|
|
|
QTest::newRow("logged event") << mockConnectedStateTypeId << QVariant(false) << QVariant(true) << true;
|
|
QTest::newRow("not logged event") << mockSignalStrengthStateTypeId << QVariant(10) << QVariant(20) << false;
|
|
}
|
|
|
|
void TestLogging::eventLogs()
|
|
{
|
|
QFETCH(StateTypeId, stateTypeId);
|
|
QFETCH(QVariant, initValue);
|
|
QFETCH(QVariant, newValue);
|
|
QFETCH(bool, expectLogEntry);
|
|
|
|
QList<Thing*> devices = NymeaCore::instance()->thingManager()->findConfiguredThings(mockThingClassId);
|
|
QVERIFY2(devices.count() > 0, "There needs to be at least one configured Mock Device for this test");
|
|
Thing *device = devices.first();
|
|
|
|
// Setup connection to mock client
|
|
QNetworkAccessManager nam;
|
|
|
|
int port = device->paramValue(mockThingHttpportParamTypeId).toInt();
|
|
|
|
// init state in mock device
|
|
QNetworkRequest request(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(port).arg(stateTypeId.toString()).arg(initValue.toString())));
|
|
QNetworkReply *reply = nam.get(request);
|
|
{
|
|
QSignalSpy finishedSpy(reply, &QNetworkReply::finished);
|
|
finishedSpy.wait();
|
|
}
|
|
|
|
// Now snoop in for the events
|
|
clearLoggingDatabase();
|
|
enableNotifications({"Integrations", "Logging"});
|
|
QSignalSpy clientSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray)));
|
|
|
|
// trigger state change in mock device
|
|
request = QNetworkRequest(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(port).arg(stateTypeId.toString()).arg(newValue.toString())));
|
|
reply = nam.get(request);
|
|
{
|
|
QSignalSpy finishedSpy(reply, &QNetworkReply::finished);
|
|
finishedSpy.wait();
|
|
}
|
|
|
|
// Lets wait for the notification
|
|
QTest::qWait(200);
|
|
clientSpy.wait(1000);
|
|
reply->deleteLater();
|
|
|
|
// Make sure the logg notification contains all the stuff we expect
|
|
QVariantList logEntryAddedVariants = checkNotifications(clientSpy, "Logging.LogEntryAdded");
|
|
qDebug() << "got" << logEntryAddedVariants.count() << "Logging.LogEntryAdded notifications";
|
|
|
|
bool found = false;
|
|
qDebug() << "got" << logEntryAddedVariants.count() << "Logging.LogEntryAdded";
|
|
foreach (const QVariant &logEntryAddedVariant, logEntryAddedVariants) {
|
|
QVariantMap logEntry = logEntryAddedVariant.toMap().value("params").toMap().value("logEntry").toMap();
|
|
if (logEntry.value("thingId").toUuid() == device->id()) {
|
|
found = true;
|
|
// Make sure the notification contains all the stuff we expect
|
|
QCOMPARE(logEntry.value("typeId").toUuid().toString(), stateTypeId.toString());
|
|
QCOMPARE(logEntry.value("eventType").toString(), enumValueName(Logging::LoggingEventTypeTrigger));
|
|
QCOMPARE(logEntry.value("source").toString(), enumValueName(Logging::LoggingSourceStates));
|
|
QCOMPARE(logEntry.value("loggingLevel").toString(), enumValueName(Logging::LoggingLevelInfo));
|
|
break;
|
|
}
|
|
}
|
|
|
|
QVERIFY2(found == expectLogEntry, "Could not find the corresponding Logging.LogEntryAdded notification");
|
|
|
|
if (expectLogEntry) {
|
|
// get this logentry with filter
|
|
QVariantMap params;
|
|
params.insert("thingIds", QVariantList() << device->id());
|
|
params.insert("loggingSources", QVariantList() << enumValueName(Logging::LoggingSourceStates));
|
|
params.insert("eventTypes", QVariantList() << enumValueName(Logging::LoggingEventTypeTrigger));
|
|
params.insert("typeIds", QVariantList() << stateTypeId);
|
|
|
|
QVariant response = injectAndWait("Logging.GetLogEntries", params);
|
|
verifyLoggingError(response);
|
|
|
|
QVariantList logEntries = response.toMap().value("params").toMap().value("logEntries").toList();
|
|
qCDebug(dcTests()) << qUtf8Printable(QJsonDocument::fromVariant(logEntries).toJson());
|
|
QCOMPARE(logEntries.count(), 1);
|
|
}
|
|
|
|
|
|
// disable notifications
|
|
QCOMPARE(disableNotifications(), true);
|
|
}
|
|
|
|
void TestLogging::actionLog()
|
|
{
|
|
clearLoggingDatabase();
|
|
|
|
QVariantList actionParams;
|
|
QVariantMap param1;
|
|
param1.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
|
|
param1.insert("value", 7);
|
|
actionParams.append(param1);
|
|
QVariantMap param2;
|
|
param2.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId);
|
|
param2.insert("value", true);
|
|
actionParams.append(param2);
|
|
|
|
QVariantMap params;
|
|
params.insert("actionTypeId", mockWithParamsActionTypeId);
|
|
params.insert("thingId", m_mockThingId);
|
|
params.insert("params", actionParams);
|
|
|
|
enableNotifications({"Logging"});
|
|
|
|
QSignalSpy clientSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray)));
|
|
|
|
// EXECUTE with params
|
|
QVariant response = injectAndWait("Integrations.ExecuteAction", params);
|
|
verifyThingError(response);
|
|
|
|
// wait for the outgoing data
|
|
// 3 packets: ExecuteAction reply, LogDatabaseUpdated signal and LogEntryAdded signal
|
|
while (clientSpy.count() < 3) {
|
|
bool success = clientSpy.wait();
|
|
if (!success) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
QVariantList logEntryAddedVariants = checkNotifications(clientSpy, "Logging.LogEntryAdded");
|
|
qWarning() << QJsonDocument::fromVariant(logEntryAddedVariants).toJson();
|
|
QVERIFY2(!logEntryAddedVariants.isEmpty(), "Did not get Logging.LogEntryAdded notification.");
|
|
|
|
bool found = false;
|
|
foreach (const QVariant &loggEntryAddedVariant, logEntryAddedVariants) {
|
|
QVariantMap logEntry = loggEntryAddedVariant.toMap().value("params").toMap().value("logEntry").toMap();
|
|
if (logEntry.value("thingId").toUuid() == m_mockThingId) {
|
|
found = true;
|
|
// Make sure the notification contains all the stuff we expect
|
|
QCOMPARE(logEntry.value("typeId").toUuid().toString(), mockWithParamsActionTypeId.toString());
|
|
QCOMPARE(logEntry.value("eventType").toString(), enumValueName(Logging::LoggingEventTypeTrigger));
|
|
QCOMPARE(logEntry.value("source").toString(), enumValueName(Logging::LoggingSourceActions));
|
|
QCOMPARE(logEntry.value("loggingLevel").toString(), enumValueName(Logging::LoggingLevelInfo));
|
|
break;
|
|
}
|
|
}
|
|
|
|
QVERIFY2(found, "Could not find the corresponding Logging.LogEntryAdded notification");
|
|
|
|
// EXECUTE without params
|
|
params.clear(); clientSpy.clear();
|
|
params.insert("actionTypeId", mockWithoutParamsActionTypeId);
|
|
params.insert("thingId", m_mockThingId);
|
|
response = injectAndWait("Integrations.ExecuteAction", params);
|
|
verifyThingError(response);
|
|
|
|
clientSpy.wait(200);
|
|
|
|
logEntryAddedVariants = checkNotifications(clientSpy, "Logging.LogEntryAdded");
|
|
QVERIFY(!logEntryAddedVariants.isEmpty());
|
|
|
|
// get this logentry with filter
|
|
params.clear();
|
|
params.insert("thingIds", QVariantList() << m_mockThingId);
|
|
params.insert("loggingSources", QVariantList() << enumValueName(Logging::LoggingSourceActions));
|
|
params.insert("eventTypes", QVariantList() << enumValueName(Logging::LoggingEventTypeTrigger));
|
|
|
|
// FIXME: currently is filtering for values not supported
|
|
//params.insert("values", QVariantList() << "7, true");
|
|
|
|
response = injectAndWait("Logging.GetLogEntries", params);
|
|
verifyLoggingError(response);
|
|
|
|
QVariantList logEntries = response.toMap().value("params").toMap().value("logEntries").toList();
|
|
QVERIFY2(!logEntries.isEmpty(), "No logs received");
|
|
|
|
// EXECUTE broken action
|
|
params.clear(); clientSpy.clear();
|
|
params.insert("actionTypeId", mockFailingActionTypeId);
|
|
params.insert("thingId", m_mockThingId);
|
|
response = injectAndWait("Integrations.ExecuteAction", params);
|
|
verifyThingError(response, Thing::ThingErrorSetupFailed);
|
|
|
|
clientSpy.wait(200);
|
|
|
|
logEntryAddedVariants = checkNotifications(clientSpy, "Logging.LogEntryAdded");
|
|
QVERIFY2(!logEntryAddedVariants.isEmpty(), "Did not get Logging.LogEntryAdded notification.");
|
|
|
|
found = false;
|
|
foreach (const QVariant &loggEntryAddedVariant, logEntryAddedVariants) {
|
|
QVariantMap logEntry = loggEntryAddedVariant.toMap().value("params").toMap().value("logEntry").toMap();
|
|
if (logEntry.value("thingId").toUuid() == m_mockThingId) {
|
|
found = true;
|
|
// Make sure the notification contains all the stuff we expect
|
|
QCOMPARE(logEntry.value("typeId").toUuid().toString(), mockFailingActionTypeId.toString());
|
|
QCOMPARE(logEntry.value("eventType").toString(), enumValueName(Logging::LoggingEventTypeTrigger));
|
|
QCOMPARE(logEntry.value("source").toString(), enumValueName(Logging::LoggingSourceActions));
|
|
QCOMPARE(logEntry.value("loggingLevel").toString(), enumValueName(Logging::LoggingLevelAlert));
|
|
QCOMPARE(logEntry.value("errorCode").toString(), enumValueName(Thing::ThingErrorSetupFailed));
|
|
break;
|
|
}
|
|
}
|
|
|
|
QVERIFY2(found, "Could not find the corresponding Logging.LogEntryAdded notification");
|
|
|
|
// get this logentry with filter
|
|
params.clear();
|
|
params.insert("thingIds", QVariantList() << m_mockThingId);
|
|
params.insert("loggingSources", QVariantList() << enumValueName(Logging::LoggingSourceActions));
|
|
params.insert("eventTypes", QVariantList() << enumValueName(Logging::LoggingEventTypeTrigger));
|
|
|
|
// FIXME: filter for values currently not working
|
|
//params.insert("values", QVariantList() << "7, true");
|
|
|
|
response = injectAndWait("Logging.GetLogEntries", params);
|
|
verifyLoggingError(response);
|
|
|
|
logEntries = response.toMap().value("params").toMap().value("logEntries").toList();
|
|
QVERIFY2(!logEntries.isEmpty(), "No logs received");
|
|
|
|
// check different filters
|
|
params.clear();
|
|
params.insert("thingIds", QVariantList() << m_mockThingId);
|
|
params.insert("loggingSources", QVariantList() << enumValueName(Logging::LoggingSourceActions));
|
|
params.insert("eventTypes", QVariantList() << enumValueName(Logging::LoggingEventTypeTrigger));
|
|
params.insert("typeIds", QVariantList() << mockWithoutParamsActionTypeId);
|
|
|
|
response = injectAndWait("Logging.GetLogEntries", params);
|
|
verifyLoggingError(response);
|
|
|
|
logEntries = response.toMap().value("params").toMap().value("logEntries").toList();
|
|
QVERIFY2(!logEntries.isEmpty(), "No logs received");
|
|
|
|
params.clear();
|
|
params.insert("thingIds", QVariantList() << m_mockThingId);
|
|
params.insert("loggingSources", QVariantList() << enumValueName(Logging::LoggingSourceActions));
|
|
params.insert("eventTypes", QVariantList() << enumValueName(Logging::LoggingEventTypeTrigger));
|
|
params.insert("typeIds", QVariantList() << mockWithoutParamsActionTypeId << mockWithParamsActionTypeId << mockFailingActionTypeId);
|
|
|
|
response = injectAndWait("Logging.GetLogEntries", params);
|
|
verifyLoggingError(response);
|
|
|
|
logEntries = response.toMap().value("params").toMap().value("logEntries").toList();
|
|
QVERIFY2(!logEntries.isEmpty(), "No logs received");
|
|
|
|
// disable notifications
|
|
QCOMPARE(disableNotifications(), true);
|
|
}
|
|
|
|
void TestLogging::thingLogs()
|
|
{
|
|
QVariantMap params;
|
|
params.insert("thingClassId", parentMockThingClassId);
|
|
params.insert("name", "Parent thing");
|
|
|
|
QVariant response = injectAndWait("Integrations.AddThing", params);
|
|
verifyThingError(response);
|
|
|
|
ThingId thingId = ThingId(response.toMap().value("params").toMap().value("thingId").toString());
|
|
QVERIFY(!thingId.isNull());
|
|
|
|
// get this logentry with filter
|
|
params.clear();
|
|
params.insert("thingIds", QVariantList() << m_mockThingId << thingId);
|
|
params.insert("loggingSources", QVariantList() << enumValueName(Logging::LoggingSourceActions)
|
|
<< enumValueName(Logging::LoggingSourceEvents)
|
|
<< enumValueName(Logging::LoggingSourceStates));
|
|
params.insert("loggingLevels", QVariantList() << enumValueName(Logging::LoggingLevelInfo)
|
|
<< enumValueName(Logging::LoggingLevelAlert));
|
|
params.insert("values", QVariantList() << "7, true" << "9, false");
|
|
|
|
QVariantMap timeFilter;
|
|
timeFilter.insert("startDate", QDateTime::currentDateTime().toTime_t() - 5);
|
|
timeFilter.insert("endDate", QDateTime::currentDateTime().toTime_t());
|
|
|
|
QVariantMap timeFilter2;
|
|
timeFilter2.insert("endDate", QDateTime::currentDateTime().toTime_t() - 20);
|
|
|
|
params.insert("timeFilters", QVariantList() << timeFilter << timeFilter2);
|
|
|
|
response = injectAndWait("Logging.GetLogEntries", params);
|
|
verifyLoggingError(response);
|
|
|
|
}
|
|
|
|
void TestLogging::testDoubleValues()
|
|
{
|
|
enableNotifications({"Logging"});
|
|
|
|
// Add display pin device which contains a double value
|
|
|
|
// Discover device
|
|
QVariantList discoveryParams;
|
|
QVariantMap resultCountParam;
|
|
resultCountParam.insert("paramTypeId", displayPinMockDiscoveryResultCountParamTypeId);
|
|
resultCountParam.insert("value", 1);
|
|
discoveryParams.append(resultCountParam);
|
|
|
|
QVariantMap params;
|
|
params.insert("thingClassId", displayPinMockThingClassId);
|
|
params.insert("discoveryParams", discoveryParams);
|
|
QVariant response = injectAndWait("Integrations.DiscoverThings", params);
|
|
|
|
verifyThingError(response, Thing::ThingErrorNoError);
|
|
|
|
// Pair device
|
|
ThingDescriptorId descriptorId = ThingDescriptorId(response.toMap().value("params").toMap().value("thingDescriptors").toList().first().toMap().value("id").toString());
|
|
params.clear();
|
|
params.insert("thingClassId", displayPinMockThingClassId);
|
|
params.insert("name", "Display pin mock device");
|
|
params.insert("thingDescriptorId", descriptorId.toString());
|
|
response = injectAndWait("Integrations.PairThing", params);
|
|
|
|
verifyThingError(response);
|
|
|
|
PairingTransactionId pairingTransactionId(response.toMap().value("params").toMap().value("pairingTransactionId").toString());
|
|
QString displayMessage = response.toMap().value("params").toMap().value("displayMessage").toString();
|
|
|
|
qCDebug(dcTests) << "displayMessage" << displayMessage;
|
|
|
|
params.clear();
|
|
params.insert("pairingTransactionId", pairingTransactionId.toString());
|
|
params.insert("secret", "243681");
|
|
response = injectAndWait("Integrations.ConfirmPairing", params);
|
|
|
|
verifyThingError(response);
|
|
|
|
ThingId thingId(response.toMap().value("params").toMap().value("thingId").toString());
|
|
|
|
QSignalSpy notificationSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray)));
|
|
|
|
// Set the double state value and sniff for LogEntryAdded notification
|
|
double value = 23.80;
|
|
QVariantMap actionParam;
|
|
actionParam.insert("paramTypeId", displayPinMockDoubleActionDoubleParamTypeId.toString());
|
|
actionParam.insert("value", value);
|
|
|
|
params.clear(); response.clear();
|
|
params.insert("thingId", thingId);
|
|
params.insert("actionTypeId", displayPinMockDoubleActionTypeId.toString());
|
|
params.insert("params", QVariantList() << actionParam);
|
|
|
|
response = injectAndWait("Integrations.ExecuteAction", params);
|
|
verifyThingError(response);
|
|
|
|
notificationSpy.wait();
|
|
QVariantList logNotificationsList = checkNotifications(notificationSpy, "Logging.LogEntryAdded");
|
|
QVERIFY2(!logNotificationsList.isEmpty(), "Did not get Logging.LogEntryAdded notification.");
|
|
|
|
foreach (const QVariant &logNotificationVariant, logNotificationsList) {
|
|
QVariantMap logNotification = logNotificationVariant.toMap().value("params").toMap().value("logEntry").toMap();
|
|
|
|
if (logNotification.value("typeId").toString() == displayPinMockDoubleActionDoubleParamTypeId.toString()) {
|
|
if (logNotification.value("typeId").toString() == displayPinMockDoubleActionDoubleParamTypeId.toString()) {
|
|
|
|
// If state source
|
|
if (logNotification.value("source").toString() == enumValueName(Logging::LoggingSourceStates)) {
|
|
QString logValue = logNotification.value("value").toString();
|
|
qDebug() << QString::number(value) << logValue;
|
|
QCOMPARE(logValue, QString::number(value));
|
|
}
|
|
|
|
// If action source notification
|
|
if (logNotification.value("source").toString() == enumValueName(Logging::LoggingSourceActions)) {
|
|
QString logValue = logNotification.value("value").toString();
|
|
qDebug() << QString::number(value) << logValue;
|
|
QCOMPARE(logValue, QString::number(value));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Remove device
|
|
params.clear();
|
|
params.insert("thingId", thingId.toString());
|
|
response = injectAndWait("Integrations.RemoveThing", params);
|
|
verifyThingError(response);
|
|
}
|
|
|
|
void TestLogging::testHouseKeeping()
|
|
{
|
|
QVariantMap params;
|
|
params.insert("thingClassId", mockThingClassId);
|
|
params.insert("name", "TestDeviceToBeRemoved");
|
|
QVariantList thingParams;
|
|
QVariantMap httpParam;
|
|
httpParam.insert("paramTypeId", mockThingHttpportParamTypeId);
|
|
httpParam.insert("value", 6667);
|
|
thingParams.append(httpParam);
|
|
params.insert("thingParams", thingParams);
|
|
QVariant response = injectAndWait("Integrations.AddThing", params);
|
|
ThingId thingId = ThingId(response.toMap().value("params").toMap().value("thingId").toUuid());
|
|
QVERIFY2(!thingId.isNull(), "Something went wrong creating the thing for testing.");
|
|
|
|
// Trigger something that creates a logging entry
|
|
QNetworkAccessManager nam;
|
|
QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*)));
|
|
QNetworkRequest request(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(6667).arg(mockConnectedStateTypeId.toString()).arg(false)));
|
|
QNetworkReply *reply = nam.get(request);
|
|
connect(reply, SIGNAL(finished()), reply, SLOT(deleteLater()));
|
|
spy.wait();
|
|
|
|
waitForDBSync();
|
|
|
|
params.clear();
|
|
params.insert("thingIds", QVariantList() << thingId);
|
|
response = injectAndWait("Logging.GetLogEntries", params);
|
|
QVERIFY2(response.toMap().value("params").toMap().value("logEntries").toList().count() > 0, "Couldn't find state change event in log...");
|
|
|
|
// Manually delete this device from config
|
|
NymeaSettings settings(NymeaSettings::SettingsRoleThings);
|
|
settings.beginGroup("ThingConfig");
|
|
settings.remove(thingId.toString());
|
|
settings.endGroup();
|
|
|
|
restartServer();
|
|
|
|
waitForDBSync();
|
|
|
|
params.clear();
|
|
params.insert("thingIds", QVariantList() << thingId);
|
|
response = injectAndWait("Logging.GetLogEntries", params);
|
|
qCDebug(dcTests()) << qUtf8Printable(QJsonDocument::fromVariant(response).toJson());
|
|
QVERIFY2(response.toMap().value("status").toString() == QString("success"), "GetLogEntries failed");
|
|
QVERIFY2(response.toMap().value("params").toMap().value("logEntries").toList().count() == 0, "Device state change event still in log. Should've been cleaned by housekeeping.");
|
|
}
|
|
|
|
void TestLogging::testLimits()
|
|
{
|
|
clearLoggingDatabase();
|
|
|
|
for (int i = 0; i < 50; i++) {
|
|
QVariantList actionParams;
|
|
QVariantMap param1;
|
|
param1.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId);
|
|
param1.insert("value", i);
|
|
actionParams.append(param1);
|
|
QVariantMap param2;
|
|
param2.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId);
|
|
param2.insert("value", true);
|
|
actionParams.append(param2);
|
|
|
|
QVariantMap params;
|
|
params.insert("actionTypeId", mockWithParamsActionTypeId);
|
|
params.insert("thingId", m_mockThingId);
|
|
params.insert("params", actionParams);
|
|
|
|
// EXECUTE with params
|
|
QVariant response = injectAndWait("Integrations.ExecuteAction", params);
|
|
verifyThingError(response);
|
|
}
|
|
|
|
waitForDBSync();
|
|
|
|
QVariantMap params;
|
|
QVariantMap response;
|
|
|
|
// No limits, should be all 50 entries
|
|
params.clear();
|
|
response = injectAndWait("Logging.GetLogEntries", params).toMap();
|
|
QCOMPARE(response.value("params").toMap().value("count").toInt(), 50);
|
|
QCOMPARE(response.value("params").toMap().value("logEntries").toList().count(), 50);
|
|
|
|
// Add a limit of 20
|
|
params.clear();
|
|
params.insert("limit", 20);
|
|
response = injectAndWait("Logging.GetLogEntries", params).toMap();
|
|
QCOMPARE(response.value("params").toMap().value("count").toInt(), 20);
|
|
QCOMPARE(response.value("params").toMap().value("logEntries").toList().count(), 20);
|
|
|
|
// Add a offset of 40, keeping a limit of 20. should return 10 entries
|
|
params.clear();
|
|
params.insert("limit", 20);
|
|
params.insert("offset", 40);
|
|
response = injectAndWait("Logging.GetLogEntries", params).toMap();
|
|
QCOMPARE(response.value("params").toMap().value("count").toInt(), 10);
|
|
QCOMPARE(response.value("params").toMap().value("logEntries").toList().count(), 10);
|
|
}
|
|
|
|
void TestLogging::removeThing()
|
|
{
|
|
// enable notifications
|
|
enableNotifications({"Logging"});
|
|
|
|
// get this logentry with filter
|
|
QVariantMap params;
|
|
params.insert("thingIds", QVariantList() << m_mockThingId);
|
|
QVariant response = injectAndWait("Logging.GetLogEntries", params);
|
|
verifyLoggingError(response);
|
|
QVariantList logEntries = response.toMap().value("params").toMap().value("logEntries").toList();
|
|
QVERIFY(logEntries.count() > 0);
|
|
|
|
QSignalSpy clientSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray)));
|
|
|
|
// Remove the device
|
|
params.clear();
|
|
params.insert("thingId", m_mockThingId);
|
|
response = injectAndWait("Integrations.RemoveThing", params);
|
|
verifyThingError(response);
|
|
|
|
clientSpy.wait(200);
|
|
QVariant notification = checkNotification(clientSpy, "Logging.LogDatabaseUpdated");
|
|
QVERIFY(!notification.isNull());
|
|
|
|
// verify that the logs from this device where removed from the db
|
|
params.clear();
|
|
params.insert("thingIds", QVariantList() << m_mockThingId);
|
|
response = injectAndWait("Logging.GetLogEntries", params);
|
|
verifyLoggingError(response);
|
|
logEntries = response.toMap().value("params").toMap().value("logEntries").toList();
|
|
QCOMPARE(logEntries.count(), 0);
|
|
|
|
// disable notifications
|
|
QCOMPARE(disableNotifications(), true);
|
|
}
|
|
|
|
#include "testlogging.moc"
|
|
QTEST_MAIN(TestLogging)
|
|
|