This repository has been archived on 2026-05-31. You can view files and clone it, but cannot push or open issues or pull requests.
powersync-core/tests/auto/webserver/testwebserver.cpp
Michael Zanetti 192bdac209 Fix webserver tests
canonicalFilePath() behavior seems to have changed at some point
and not existing files outside the public dir will return a 404
rather than a 403. Ideally the logic would be fixed to first
check for the file being outside the public directory, directly
returning a 403, then checking if the file exists, return a 404
if not, and lastly check for permissions on the file and return
a 403 again of denied. However, that would result in a bigger
change.

Also, the tests were failing all along if syslog exists but is
not readable (code is ok, just bad test) but none of our
autotesters seemed to have such a setup till now.
2022-04-23 00:23:21 +02:00

647 lines
30 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 <QXmlReader>
using namespace nymeaserver;
class TestWebserver: public NymeaTestBase
{
Q_OBJECT
private slots:
void initTestCase();
void coverageCalls();
void httpVersion();
void multiPackageMessage();
void checkAllowedMethodCall_data();
void checkAllowedMethodCall();
void badRequests_data();
void badRequests();
void getFiles_data();
void getFiles();
void getServerDescription();
void getIcons_data();
void getIcons();
void getDebugServer_data();
void getDebugServer();
public slots:
void onSslErrors(const QList<QSslError> &errors) {
qCWarning(dcTests()) << "SSL errors:" << errors;
QSslSocket *socket = static_cast<QSslSocket*>(sender());
socket->ignoreSslErrors();
}
};
void TestWebserver::initTestCase()
{
NymeaTestBase::initTestCase("*.debug=false\nWebServer.debug=true\ntests.debug=true\nServerManager.debug=true");
qDebug() << "TestWebserver starting";
foreach (const WebServerConfiguration &config, NymeaCore::instance()->configuration()->webServerConfigurations()) {
if (config.port == 3333 && (QHostAddress(config.address) == QHostAddress("127.0.0.1") || QHostAddress(config.address) == QHostAddress("0.0.0.0"))) {
qDebug() << "Already have a webserver listening on 127.0.0.1:3333";
return;
}
}
qDebug() << "Creating new webserver instance on 127.0.0.1:3333";
WebServerConfiguration config;
config.address = "127.0.0.1";
config.port = 3333;
config.sslEnabled = true;
config.restServerEnabled = true;
NymeaCore::instance()->configuration()->setWebServerConfiguration(config);
}
void TestWebserver::coverageCalls()
{
HttpReply *reply = new HttpReply(this);
qDebug() << reply << reply->payload();
qDebug() << reply->rawHeaderList();
qDebug() << reply->rawHeader() << reply->isEmpty();
reply->clear();
}
void TestWebserver::httpVersion()
{
QSslSocket *socket = new QSslSocket(this);
typedef void (QSslSocket:: *sslErrorsSignal)(const QList<QSslError> &);
connect(socket, static_cast<sslErrorsSignal>(&QSslSocket::sslErrors), this, &TestWebserver::onSslErrors);
socket->connectToHostEncrypted("127.0.0.1", 3333);
QSignalSpy encryptedSpy(socket, SIGNAL(encrypted()));
bool encrypted = encryptedSpy.wait();
QVERIFY2(encrypted, "could not created encrypted webserver connection.");
QSignalSpy clientSpy(socket, SIGNAL(readyRead()));
QByteArray requestData;
requestData.append("GET /hello/nymea HTTP/1\r\n");
requestData.append("User-Agent: nymea webserver test\r\n\r\n");
quint64 count = socket->write(requestData);
QVERIFY2(count > 0, "could not write to webserver.");
clientSpy.wait(500);
qWarning() << "spy count" << clientSpy.count();
QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
QByteArray data = socket->readAll();
QVERIFY2(!data.isEmpty(), "got no response");
QStringList lines = QString(data).split("\r\n");
QStringList firstLineTokens = lines.first().split(QRegExp("[ \r\n][ \r\n]*"));
QVERIFY2(firstLineTokens.isEmpty() || firstLineTokens.count() > 2, "could not get tokens of first line");
bool ok = false;
int statusCode = firstLineTokens.at(1).toInt(&ok);
qDebug() << "have" << firstLineTokens;
QVERIFY2(ok, "Could not convert statuscode from response to int");
QCOMPARE(statusCode, 505);
socket->close();
socket->deleteLater();
}
void TestWebserver::multiPackageMessage()
{
QSslSocket *socket = new QSslSocket(this);
typedef void (QSslSocket:: *sslErrorsSignal)(const QList<QSslError> &);
connect(socket, static_cast<sslErrorsSignal>(&QSslSocket::sslErrors), this, &TestWebserver::onSslErrors);
socket->connectToHostEncrypted("127.0.0.1", 3333);
QSignalSpy encryptedSpy(socket, SIGNAL(encrypted()));
bool encrypted = encryptedSpy.wait();
QVERIFY2(encrypted, "could not created encrypte webserver connection.");
QSignalSpy clientSpy(socket, SIGNAL(readyRead()));
QByteArray requestData;
requestData.append("PUT / HTTP/1.1\r\n");
requestData.append("User-Agent: webserver test\r\n");
requestData.append("Content-Length: 42\r\n");
requestData.append("\r\n");
requestData.append("This message");
quint64 count = socket->write(requestData);
QVERIFY2(count > 0, "could not write to webserver.");
count = socket->write(QByteArray(" was sent"));
QVERIFY2(count > 0, "could not write to webserver.");
count = socket->write(QByteArray(" in four TCP"));
QVERIFY2(count > 0, "could not write to webserver.");
count = socket->write(QByteArray("packages. "));
QVERIFY2(count > 0, "could not write to webserver.");
clientSpy.wait(500);
QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
QByteArray data = socket->readAll();
QVERIFY2(!data.isEmpty(), "got no response");
QStringList lines = QString(data).split("\r\n");
QStringList firstLineTokens = lines.first().split(QRegExp("[ \r\n][ \r\n]*"));
QVERIFY2(firstLineTokens.isEmpty() || firstLineTokens.count() > 2, "could not get tokens of first line");
bool ok = false;
int statusCode = firstLineTokens.at(1).toInt(&ok);
qDebug() << "have" << firstLineTokens;
QVERIFY2(ok, "Could not convert statuscode from response to int");
QCOMPARE(statusCode, 501);
socket->close();
socket->deleteLater();
}
void TestWebserver::checkAllowedMethodCall_data()
{
QTest::addColumn<QString>("method");
QTest::addColumn<int>("expectedStatusCode");
QTest::newRow("GET") << "GET" << 200;
QTest::newRow("PUT") << "PUT" << 200;
QTest::newRow("POST") << "POST" << 200;
QTest::newRow("DELETE") << "DELETE" << 200;
QTest::newRow("OPTIONS") << "OPTIONS" << 200;
QTest::newRow("HEAD") << "HEAD" << 405;
QTest::newRow("CONNECT") << "CONNECT" << 405;
QTest::newRow("TRACE") << "TRACE" << 405;
}
void TestWebserver::checkAllowedMethodCall()
{
QFETCH(QString, method);
QFETCH(int, expectedStatusCode);
QNetworkAccessManager nam;
connect(&nam, &QNetworkAccessManager::sslErrors, [](QNetworkReply* reply, const QList<QSslError> &errors) {
qCWarning(dcTests) << "SSL errors:" << errors;
reply->ignoreSslErrors();
});
QSignalSpy clientSpy(&nam, SIGNAL(finished(QNetworkReply*)));
QNetworkRequest request;
request.setUrl(QUrl("https://localhost:3333"));
QNetworkReply *reply = 0;
clientSpy.clear();
if (method == "GET") {
reply = nam.get(request);
} else if(method == "PUT") {
reply = nam.put(request, QByteArray("Hello nymea!"));
} else if(method == "POST") {
reply = nam.post(request, QByteArray("Hello nymea!"));
} else if(method == "DELETE") {
reply = nam.deleteResource(request);
} else if(method == "HEAD") {
reply = nam.head(request);
} else if(method == "CONNECT") {
reply = nam.sendCustomRequest(request, "CONNECT");
} else if(method == "OPTIONS") {
QNetworkRequest req(QUrl("https://localhost:3333/api/v1/devices"));
reply = nam.sendCustomRequest(req, "OPTIONS");
} else if(method == "TRACE") {
reply = nam.sendCustomRequest(request, "TRACE");
} else {
// just to make sure there will be a reply to delete
reply = nam.get(request);
}
clientSpy.wait();
QVERIFY2(clientSpy.count() > 0, "expected response");
if (expectedStatusCode == 405){
QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), expectedStatusCode);
QVERIFY2(reply->hasRawHeader("Allow"), "405 should contain the allowed methods header");
}
reply->deleteLater();
}
void TestWebserver::badRequests_data()
{
QTest::addColumn<QByteArray>("request");
QTest::addColumn<int>("expectedStatusCode");
QByteArray wrongContentLength;
wrongContentLength.append("PUT / HTTP/1.1\r\n");
wrongContentLength.append("User-Agent: webserver test\r\n");
wrongContentLength.append("Content-Length: 1\r\n");
wrongContentLength.append("\r\n");
wrongContentLength.append("longer content than told in the header");
QByteArray wrongHeaderFormatting;
wrongHeaderFormatting.append("PUT / HTTP/1.1\r\n");
wrongHeaderFormatting.append("User-Agent webserver test\r\n");
wrongHeaderFormatting.append("Content-Length: 1\r\n");
wrongHeaderFormatting.append("\r\n");
QByteArray userAgentMissing;
userAgentMissing.append("GET /index.html HTTP/1.1\r\n");
userAgentMissing.append("\r\n");
QTest::newRow("wrong content length") << wrongContentLength << 400;
QTest::newRow("invalid header formatting") << wrongHeaderFormatting << 400;
QTest::newRow("user agent missing") << userAgentMissing << 404;
}
void TestWebserver::badRequests()
{
QFETCH(QByteArray, request);
QFETCH(int, expectedStatusCode);
QSslSocket *socket = new QSslSocket(this);
typedef void (QSslSocket:: *sslErrorsSignal)(const QList<QSslError> &);
connect(socket, static_cast<sslErrorsSignal>(&QSslSocket::sslErrors), this, &TestWebserver::onSslErrors);
socket->connectToHostEncrypted("127.0.0.1", 3333);
QSignalSpy encryptedSpy(socket, SIGNAL(encrypted()));
bool encrypted = encryptedSpy.wait();
QVERIFY2(encrypted, "could not created encrypte webserver connection.");
QSignalSpy clientSpy(socket, SIGNAL(readyRead()));
socket->write(request);
bool filesWritten = socket->waitForBytesWritten(500);
QVERIFY2(filesWritten, "could not write to webserver.");
clientSpy.wait(500);
QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
QByteArray data = socket->readAll();
QVERIFY2(!data.isEmpty(), "got no response");
QStringList lines = QString(data).split("\r\n");
QStringList firstLineTokens = lines.first().split(QRegExp("[ \r\n][ \r\n]*"));
QVERIFY2(firstLineTokens.isEmpty() || firstLineTokens.count() > 2, "could not get tokens of first line");
bool ok = false;
int statusCode = firstLineTokens.at(1).toInt(&ok);
QVERIFY2(ok, "Could not convert statuscode from response to int");
QCOMPARE(statusCode, expectedStatusCode);
socket->close();
socket->deleteLater();
}
void TestWebserver::getFiles_data()
{
QTest::addColumn<QString>("query");
QTest::addColumn<int>("expectedStatusCode");
QTest::newRow("get /etc/passwd") << "/etc/passwd" << 404;
QTest::newRow("get /blub/blub/blabla") << "/etc/passwd" << 404;
QTest::newRow("get /../../etc/passwd") << "/../../etc/passwd" << 404;
QTest::newRow("get /../../") << "/../../" << 404;
QTest::newRow("get /../") << "/../" << 404;
QTest::newRow("get /etc/nymea/nymead.conf") << "/etc/nymea/nymead.conf" << 404;
QTest::newRow("get /etc/sudoers") << "/etc/sudoers" << 404;
QTest::newRow("get /root/.ssh/id_rsa.pub") << "/root/.ssh/id_rsa.pub" << 404;
}
void TestWebserver::getFiles()
{
QFETCH(QString, query);
QFETCH(int, expectedStatusCode);
QNetworkAccessManager nam;
connect(&nam, &QNetworkAccessManager::sslErrors, this, [](QNetworkReply* reply, const QList<QSslError> &) {
reply->ignoreSslErrors();
});
QSignalSpy clientSpy(&nam, SIGNAL(finished(QNetworkReply*)));
QNetworkRequest request;
request.setUrl(QUrl("https://localhost:3333" + query));
QNetworkReply *reply = nam.get(request);
clientSpy.wait();
QVERIFY2(clientSpy.count() > 0, "expected 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, expectedStatusCode);
reply->deleteLater();
}
void TestWebserver::getServerDescription()
{
QNetworkAccessManager nam;
connect(&nam, &QNetworkAccessManager::sslErrors, [this, &nam](QNetworkReply* reply, const QList<QSslError> &) {
reply->ignoreSslErrors();
});
QSignalSpy clientSpy(&nam, SIGNAL(finished(QNetworkReply*)));
QNetworkRequest request;
request.setUrl(QUrl("https://localhost:3333/server.xml"));
QNetworkReply *reply = nam.get(request);
clientSpy.wait();
QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
QXmlSimpleReader xmlReader; QXmlInputSource xmlSource;
xmlSource.setData(reply->readAll());
QVERIFY(xmlReader.parse(xmlSource));
reply->deleteLater();
}
void TestWebserver::getIcons_data()
{
QTest::addColumn<QString>("query");
QTest::addColumn<int>("iconSize");
QTest::newRow("get /icons/nymea-logo-8x8.png") << "/icons/nymea-logo-8x8.png" << 228;
QTest::newRow("get /icons/nymea-logo-16x16.png") << "/icons/nymea-logo-16x16.png" << 392;
QTest::newRow("get /icons/nymea-logo-22x22.png") << "/icons/nymea-logo-22x22.png" << 512;
QTest::newRow("get /icons/nymea-logo-32x32.png") << "/icons/nymea-logo-32x32.png" << 747;
QTest::newRow("get /icons/nymea-logo-48x48.png") << "/icons/nymea-logo-48x48.png" << 1282;
QTest::newRow("get /icons/nymea-logo-64x64.png") << "/icons/nymea-logo-64x64.png" << 1825;
QTest::newRow("get /icons/nymea-logo-120x120.png") << "/icons/nymea-logo-120x120.png" << 4090;
QTest::newRow("get /icons/nymea-logo-128x128.png") << "/icons/nymea-logo-128x128.png" << 4453;
QTest::newRow("get /icons/nymea-logo-256x256.png") << "/icons/nymea-logo-256x256.png" << 10763;
QTest::newRow("get /icons/nymea-logo-512x512.png") << "/icons/nymea-logo-512x512.png" << 24287;
}
void TestWebserver::getIcons()
{
QFETCH(QString, query);
QFETCH(int, iconSize);
QNetworkAccessManager nam;
connect(&nam, &QNetworkAccessManager::sslErrors, [this, &nam](QNetworkReply* reply, const QList<QSslError> &) {
reply->ignoreSslErrors();
});
QSignalSpy clientSpy(&nam, SIGNAL(finished(QNetworkReply*)));
QNetworkRequest request;
request.setUrl(QUrl("https://localhost:3333" + query));
QNetworkReply *reply = nam.get(request);
clientSpy.wait();
QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
QByteArray iconData = reply->readAll();
QVERIFY(!iconData.isEmpty());
QCOMPARE(iconData.size(), iconSize);
reply->deleteLater();
}
void TestWebserver::getDebugServer_data()
{
QTest::addColumn<QString>("method");
QTest::addColumn<QString>("query");
QTest::addColumn<bool>("serverEnabled");
QTest::addColumn<int>("expectedStatusCode");
// Resource files
QTest::newRow("GET /debug/styles.css | server enabled | 200") << "get" << "/debug/styles.css" << true << 200;
QTest::newRow("GET /debug/logo.svg | server enabled | 200") << "get" << "/debug/logo.svg" << true << 200;
// Check redirection
QTest::newRow("GET /debug/thisresourcedoesnotexist | server enabled | 308-200") << "get" << "/debug/thisresourcedoesnotexist" << true << 308;
// debug enabled
QTest::newRow("GET /debug | server enabled | 200") << "get" << "/debug" << true << 200;
QTest::newRow("OPTIONS /debug | server enabled | 200") << "options" << "/debug" << true << 200;
QTest::newRow("PUT /debug | server enabled | 405") << "put" << "/debug" << true << 405;
QTest::newRow("POST /debug | server enabled | 405") << "post" << "/debug" << true << 405;
QTest::newRow("DELETE /debug | server enabled | 405") << "delete" << "/debug" << true << 405;
// debug disabled
QTest::newRow("GET /debug | server disabled | 404") << "get" << "/debug" << false << 404;
QTest::newRow("OPTIONS /debug | server disabled | 404") << "options" << "/debug" << false << 404;
QTest::newRow("PUT /debug | server disabled | 404") << "put" << "/debug" << false << 404;
QTest::newRow("POST /debug | server disabled | 404") << "post" << "/debug" << false << 404;
QTest::newRow("DELETE /debug | server disabled | 404") << "delete" << "/debug" << false << 404;
// styles.css enabled
QTest::newRow("GET /debug/styles.css | server enabled | 200") << "get" << "/debug/styles.css" << true << 200;
QTest::newRow("OPTIONS /debug/styles.css | server enabled | 200") << "options" << "/debug/styles.css" << true << 200;
QTest::newRow("PUT /debug/styles.css | server enabled | 405") << "put" << "/debug/styles.css" << true << 405;
QTest::newRow("POST /debug/styles.css | server enabled | 405") << "post" << "/debug/styles.css" << true << 405;
QTest::newRow("DELETE /debug/styles.css | server enabled | 405") << "delete" << "/debug/styles.css" << true << 405;
// styles.css disabled
QTest::newRow("GET /debug/styles.css | server disabled | 404") << "get" << "/debug/styles.css" << false << 404;
QTest::newRow("OPTIONS /debug/styles.css | server disabled | 404") << "options" << "/debug/styles.css" << false << 404;
QTest::newRow("PUT /debug/styles.css | server disabled | 404") << "put" << "/debug/styles.css" << false << 404;
QTest::newRow("POST /debug/styles.css | server disabled | 404") << "post" << "/debug/styles.css" << false << 404;
QTest::newRow("DELETE /debug/styles.css | server disabled | 404") << "delete" << "/debug/styles.css" << false << 404;
// logdb enabled
QTest::newRow("GET /debug/logdb.sql | server enabled | 200") << "get" << "/debug/logdb.sql" << true << 200;
QTest::newRow("OPTIONS /debug/logdb.sql | server enabled | 200") << "options" << "/debug/logdb.sql" << true << 200;
QTest::newRow("PUT /debug/logdb.sql | server enabled | 405") << "put" << "/debug/logdb.sql" << true << 405;
QTest::newRow("POST /debug/logdb.sql | server enabled | 405") << "post" << "/debug/logdb.sql" << true << 405;
QTest::newRow("DELETE /debug/logdb.sql | server enabled | 405") << "delete" << "/debug/logdb.sql" << true << 405;
// logdb disabled
QTest::newRow("GET /debug/logdb.sql | server disabled | 404") << "get" << "/debug/logdb.sql" << false << 404;
QTest::newRow("OPTIONS /debug/logdb.sql | server disabled | 404") << "options" << "/debug/logdb.sql" << false << 404;
QTest::newRow("PUT /debug/logdb.sql | server disabled | 404") << "put" << "/debug/logdb.sql" << false << 404;
QTest::newRow("POST /debug/logdb.sql | server disabled | 404") << "post" << "/debug/logdb.sql" << false << 404;
QTest::newRow("DELETE /debug/logdb.sql | server disabled | 404") << "delete" << "/debug/logdb.sql" << false << 404;
// Check if syslog is accessable
QFileInfo syslogFileInfo("/var/log/syslog");
if (!syslogFileInfo.exists()) {
// syslog file doesn't exist
QTest::newRow("GET /debug/syslog | server enabled | 200") << "get" << "/debug/syslog" << true << 404;
QTest::newRow("OPTIONS /debug/syslog | server enabled | 200") << "options" << "/debug/syslog" << true << 404;
QTest::newRow("PUT /debug/syslog | server enabled | 405") << "put" << "/debug/syslog" << true << 405;
QTest::newRow("POST /debug/syslog | server enabled | 405") << "post" << "/debug/syslog" << true << 405;
QTest::newRow("DELETE /debug/syslog | server enabled | 405") << "delete" << "/debug/syslog" << true << 405;
} else if (!syslogFileInfo.isReadable()) {
// syslog enabled, but not readable
QTest::newRow("GET /debug/syslog | server enabled | 200") << "get" << "/debug/syslog" << true << 403;
QTest::newRow("OPTIONS /debug/syslog | server enabled | 200") << "options" << "/debug/syslog" << true << 403;
QTest::newRow("PUT /debug/syslog | server enabled | 405") << "put" << "/debug/syslog" << true << 405;
QTest::newRow("POST /debug/syslog | server enabled | 405") << "post" << "/debug/syslog" << true << 405;
QTest::newRow("DELETE /debug/syslog | server enabled | 405") << "delete" << "/debug/syslog" << true << 405;
} else {
// syslog enabled
QTest::newRow("GET /debug/syslog | server enabled | 200") << "get" << "/debug/syslog" << true << 200;
QTest::newRow("OPTIONS /debug/syslog | server enabled | 200") << "options" << "/debug/syslog" << true << 200;
QTest::newRow("PUT /debug/syslog | server enabled | 405") << "put" << "/debug/syslog" << true << 405;
QTest::newRow("POST /debug/syslog | server enabled | 405") << "post" << "/debug/syslog" << true << 405;
QTest::newRow("DELETE /debug/syslog | server enabled | 405") << "delete" << "/debug/syslog" << true << 405;
}
// syslog disabled
QTest::newRow("GET /debug/syslog | server enabled | 404") << "get" << "/debug/syslog" << false << 404;
QTest::newRow("OPTIONS /debug/syslog | server enabled | 404") << "options" << "/debug/syslog" << false << 404;
QTest::newRow("PUT /debug/syslog | server enabled | 404") << "put" << "/debug/syslog" << false << 404;
QTest::newRow("POST /debug/syslog | server enabled | 404") << "post" << "/debug/syslog" << false << 404;
QTest::newRow("DELETE /debug/syslog | server enabled | 404") << "delete" << "/debug/syslog" << false << 404;
// settings/nymead enabled
QTest::newRow("GET /debug/settings/nymead | server enabled | 200") << "get" << "/debug/settings/nymead" << true << 200;
QTest::newRow("OPTIONS /debug/settings/nymead | server enabled | 200") << "options" << "/debug/settings/nymead" << true << 200;
QTest::newRow("PUT /debug/settings/nymead | server enabled | 405") << "put" << "/debug/settings/nymead" << true << 405;
QTest::newRow("POST /debug/settings/nymead | server enabled | 405") << "post" << "/debug/settings/nymead" << true << 405;
QTest::newRow("DELETE /debug/settings/nymead | server enabled | 405") << "delete" << "/debug/settings/nymead" << true << 405;
// settings/nymead disabled
QTest::newRow("GET /debug/settings/nymead | server disabled | 404") << "get" << "/debug/settings/nymead" << false << 404;
QTest::newRow("OPTIONS /debug/settings/nymead | server disabled | 404") << "options" << "/debug/settings/nymead" << false << 404;
QTest::newRow("PUT /debug/settings/nymead | server disabled | 404") << "put" << "/debug/settings/nymead" << false << 404;
QTest::newRow("POST /debug/settings/nymead | server disabled | 404") << "post" << "/debug/settings/nymead" << false << 404;
QTest::newRow("DELETE /debug/settings/nymead | server disabled | 404") << "delete" << "/debug/settings/nymead" << false << 404;
// settings/devices enabled
QTest::newRow("GET /debug/settings/devices | server enabled | 200") << "get" << "/debug/settings/things" << true << 200;
QTest::newRow("OPTIONS /debug/settings/devices | server enabled | 200") << "options" << "/debug/settings/things" << true << 200;
QTest::newRow("PUT /debug/settings/devices | server enabled | 405") << "put" << "/debug/settings/things" << true << 405;
QTest::newRow("POST /debug/settings/devices | server enabled | 405") << "post" << "/debug/settings/things" << true << 405;
QTest::newRow("DELETE /debug/settings/devices | server enabled | 405") << "delete" << "/debug/settings/things" << true << 405;
// settings/devices disabled
QTest::newRow("GET /debug/settings/devices | server disabled | 404") << "get" << "/debug/settings/things" << false << 404;
QTest::newRow("OPTIONS /debug/settings/devices | server disabled | 404") << "options" << "/debug/settings/things" << false << 404;
QTest::newRow("PUT /debug/settings/devices | server disabled | 404") << "put" << "/debug/settings/things" << false << 404;
QTest::newRow("POST /debug/settings/devices | server disabled | 404") << "post" << "/debug/settings/things" << false << 404;
QTest::newRow("DELETE /debug/settings/devices | server disabled | 404") << "delete" << "/debug/settings/things" << false << 404;
// settings/rules enabled
QTest::newRow("GET /debug/settings/rules | server enabled | 200") << "get" << "/debug/settings/rules" << true << 200;
QTest::newRow("OPTIONS /debug/settings/rules | server enabled | 200") << "options" << "/debug/settings/rules" << true << 200;
QTest::newRow("PUT /debug/settings/rules | server enabled | 405") << "put" << "/debug/settings/rules" << true << 405;
QTest::newRow("POST /debug/settings/rules | server enabled | 405") << "post" << "/debug/settings/rules" << true << 405;
QTest::newRow("DELETE /debug/settings/rules | server enabled | 405") << "delete" << "/debug/settings/rules" << true << 405;
// settings/rules disabled
QTest::newRow("GET /debug/settings/rules | server disabled | 404") << "get" << "/debug/settings/rules" << false << 404;
QTest::newRow("OPTIONS /debug/settings/rules | server disabled | 404") << "options" << "/debug/settings/rules" << false << 404;
QTest::newRow("PUT /debug/settings/rules | server disabled | 404") << "put" << "/debug/settings/rules" << false << 404;
QTest::newRow("POST /debug/settings/rules | server disabled | 404") << "post" << "/debug/settings/rules" << false << 404;
QTest::newRow("DELETE /debug/settings/rules | server disabled | 404") << "delete" << "/debug/settings/rules" << false << 404;
// settings/devicestates enabled
QTest::newRow("GET /debug/settings/devicestates | server enabled | 200") << "get" << "/debug/settings/thingstates" << true << 200;
QTest::newRow("OPTIONS /debug/settings/devicestates | server enabled | 200") << "options" << "/debug/settings/thingstates" << true << 200;
QTest::newRow("PUT /debug/settings/devicestates | server enabled | 405") << "put" << "/debug/settings/thingstates" << true << 405;
QTest::newRow("POST /debug/settings/devicestates | server enabled | 405") << "post" << "/debug/settings/thingstates" << true << 405;
QTest::newRow("DELETE /debug/settings/devicestates | server enabled | 405") << "delete" << "/debug/settings/thingstates" << true << 405;
// settings/devicestates disabled
QTest::newRow("GET /debug/settings/devicestates | server disabled | 404") << "get" << "/debug/settings/thingstates" << false << 404;
QTest::newRow("OPTIONS /debug/settings/devicestates | server disabled | 404") << "options" << "/debug/settings/thingstates" << false << 404;
QTest::newRow("PUT /debug/settings/devicestates | server disabled | 404") << "put" << "/debug/settings/thingstates" << false << 404;
QTest::newRow("POST /debug/settings/devicestates | server disabled | 404") << "post" << "/debug/settings/thingstates" << false << 404;
QTest::newRow("DELETE /debug/settings/devicestates | server disabled | 404") << "delete" << "/debug/settings/thingstates" << false << 404;
// settings/plugins enabled
QTest::newRow("GET /debug/settings/plugins | server enabled | 200") << "get" << "/debug/settings/plugins" << true << 200;
QTest::newRow("OPTIONS /debug/settings/plugins | server enabled | 200") << "options" << "/debug/settings/plugins" << true << 200;
QTest::newRow("PUT /debug/settings/plugins | server enabled | 405") << "put" << "/debug/settings/plugins" << true << 405;
QTest::newRow("POST /debug/settings/plugins | server enabled | 405") << "post" << "/debug/settings/plugins" << true << 405;
QTest::newRow("DELETE /debug/settings/plugins | server enabled | 405") << "delete" << "/debug/settings/plugins" << true << 405;
// settings/devicestates disabled
QTest::newRow("GET /debug/settings/plugins | server disabled | 404") << "get" << "/debug/settings/plugins" << false << 404;
QTest::newRow("OPTIONS /debug/settings/plugins | server disabled | 404") << "options" << "/debug/settings/plugins" << false << 404;
QTest::newRow("PUT /debug/settings/plugins | server disabled | 404") << "put" << "/debug/settings/plugins" << false << 404;
QTest::newRow("POST /debug/settings/plugins | server disabled | 404") << "post" << "/debug/settings/plugins" << false << 404;
QTest::newRow("DELETE /debug/settings/plugins | server disabled | 404") << "delete" << "/debug/settings/plugins" << false << 404;
}
void TestWebserver::getDebugServer()
{
QFETCH(QString, method);
QFETCH(QString, query);
QFETCH(bool, serverEnabled);
QFETCH(int, expectedStatusCode);
// Enable/disable debug server
QVariantMap params; QVariant response;
params.insert("enabled", serverEnabled);
response = injectAndWait("Configuration.SetDebugServerEnabled", params);
verifyError(response, "configurationError", "ConfigurationErrorNoError");
QNetworkAccessManager nam;
bool ok = false;
int statusCode = 0;
QSignalSpy clientSpy(&nam, SIGNAL(finished(QNetworkReply*)));
connect(&nam, &QNetworkAccessManager::sslErrors, [this, &nam](QNetworkReply* reply, const QList<QSslError> &) {
reply->ignoreSslErrors();
});
QNetworkReply *reply = nullptr;
QNetworkRequest request;
request.setUrl(QUrl("https://localhost:3333" + query));
clientSpy.clear();
if (method == "get") {
reply = nam.get(request);
} else if (method == "options") {
reply = nam.sendCustomRequest(request, "OPTIONS");
} else if (method == "post") {
reply = nam.post(request, "");
} else if (method == "delete") {
reply = nam.deleteResource(request);
} else if (method == "put") {
reply = nam.put(request, "");
}
clientSpy.wait();
QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
ok = false;
statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(&ok);
QVERIFY2(ok, "Could not convert statuscode from response to int");
QCOMPARE(statusCode, expectedStatusCode);
}
#include "testwebserver.moc"
QTEST_MAIN(TestWebserver)