diff --git a/.gitignore b/.gitignore index fab7372..745c4dd 100644 --- a/.gitignore +++ b/.gitignore @@ -71,3 +71,4 @@ Thumbs.db *.dll *.exe +coverage-html diff --git a/README.md b/README.md index 8a7034b..861bd4d 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,18 @@ In order to run the test, you can call `make check` in the build directory or ru $ nymea-remoteproxy-tests + +## Test coverage report + +If you want to create a line coverage report from the tests simply run following command in the source directory: + + + $ apt install lcov + $ ./create-coverage-html.sh + +The resulting coverage report will be place in the `coverage-html` directory. + + # Usage In order to get information about the server you can start the command with the `--help` parameter. diff --git a/create-coverage-html.sh b/create-coverage-html.sh new file mode 100755 index 0000000..f1a22ac --- /dev/null +++ b/create-coverage-html.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# Export the library path for now +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(pwd)/libnymea-remoteproxy:$(pwd)/libnymea-remoteproxyclient + +# Build +qmake CONFIG+=coverage +make -j$(nproc) +make coverage-html + +# Clean up source directory +rm -v libnymea-remoteproxy/libnymea-remoteproxy.so* +rm -v libnymea-remoteproxyclient/libnymea-remoteproxyclient.so* +rm -v server/nymea-remoteproxy +rm -v tests/nymea-remoteproxy-tests +make clean diff --git a/libnymea-remoteproxy/jsonrpc/authenticationhandler.cpp b/libnymea-remoteproxy/jsonrpc/authenticationhandler.cpp index 3dfb573..4f6da88 100644 --- a/libnymea-remoteproxy/jsonrpc/authenticationhandler.cpp +++ b/libnymea-remoteproxy/jsonrpc/authenticationhandler.cpp @@ -45,7 +45,8 @@ JsonReply *AuthenticationHandler::Authenticate(const QVariantMap ¶ms, const void AuthenticationHandler::onAuthenticationFinished() { - AuthenticationReply *authReply = static_cast(sender()); - JsonReply *jsonReply = m_runningAuthentications.value(authReply); - + //AuthenticationReply *authReply = static_cast(sender()); + //JsonReply *jsonReply = m_runningAuthentications.take(authReply); + + //emit asyncReply() } diff --git a/libnymea-remoteproxy/jsonrpcserver.cpp b/libnymea-remoteproxy/jsonrpcserver.cpp index a25360e..583bd3c 100644 --- a/libnymea-remoteproxy/jsonrpcserver.cpp +++ b/libnymea-remoteproxy/jsonrpcserver.cpp @@ -155,3 +155,19 @@ void JsonRpcServer::setup() registerHandler(new AuthenticationHandler(this)); } +void JsonRpcServer::clientConnected(const QUuid &clientId) +{ + Q_UNUSED(clientId) +} + +void JsonRpcServer::clientDisconnected(const QUuid &clientId) +{ + Q_UNUSED(clientId) +} + +void JsonRpcServer::processData(const QUuid &clientId, const QByteArray &data) +{ + Q_UNUSED(clientId) + Q_UNUSED(data) +} + diff --git a/libnymea-remoteproxy/jsonrpcserver.h b/libnymea-remoteproxy/jsonrpcserver.h index ea487a4..86e2f70 100644 --- a/libnymea-remoteproxy/jsonrpcserver.h +++ b/libnymea-remoteproxy/jsonrpcserver.h @@ -46,8 +46,8 @@ private slots: void clientConnected(const QUuid &clientId); void clientDisconnected(const QUuid &clientId); void processData(const QUuid &clientId, const QByteArray &data); - void sendNotification(const QVariantMap ¶ms); - void asyncReplyFinished(); +// void sendNotification(const QVariantMap ¶ms); +// void asyncReplyFinished(); }; diff --git a/libnymea-remoteproxy/websocketserver.cpp b/libnymea-remoteproxy/websocketserver.cpp index 24db971..325f03f 100644 --- a/libnymea-remoteproxy/websocketserver.cpp +++ b/libnymea-remoteproxy/websocketserver.cpp @@ -127,13 +127,13 @@ void WebSocketServer::onPing(quint64 elapsedTime, const QByteArray &payload) bool WebSocketServer::startServer() { m_server = new QWebSocketServer(QCoreApplication::applicationName(), QWebSocketServer::SecureMode, this); - m_server->setSslConfiguration(m_sslConfiguration); + m_server->setSslConfiguration(sslConfiguration()); connect (m_server, &QWebSocketServer::newConnection, this, &WebSocketServer::onClientConnected); connect (m_server, &QWebSocketServer::acceptError, this, &WebSocketServer::onServerError); - qCDebug(dcWebSocketServer()) << "Starting server" << m_server->serverName() << m_serverUrl.toString(); - if (!m_server->listen(QHostAddress(m_serverUrl.host()), static_cast(m_serverUrl.port()))) { + qCDebug(dcWebSocketServer()) << "Starting server" << m_server->serverName() << serverUrl().toString(); + if (!m_server->listen(QHostAddress(m_serverUrl.host()), static_cast(serverUrl().port()))) { qCWarning(dcWebSocketServer()) << "Server" << m_server->serverName() << "could not listen on" << serverUrl().toString(); return false; } @@ -151,7 +151,7 @@ bool WebSocketServer::stopServer() // Delete the server object if (m_server) { - qCDebug(dcWebSocketServer()) << "Stop server" << m_server->serverName() << m_serverUrl.toString(); + qCDebug(dcWebSocketServer()) << "Stop server" << m_server->serverName() << serverUrl().toString(); m_server->close(); delete m_server; m_server = nullptr; diff --git a/nymea-remoteproxy.pri b/nymea-remoteproxy.pri index 47a39ca..fe0a1a4 100644 --- a/nymea-remoteproxy.pri +++ b/nymea-remoteproxy.pri @@ -13,3 +13,54 @@ QMAKE_LFLAGS *= -std=c++11 top_srcdir=$$PWD top_builddir=$$shadowed($$PWD) + +coverage { + message("Building with coverage report") + + # Note: this works only if you build in the source dir + OBJECTS_DIR = + MOC_DIR = + + LIBS += -lgcov + QMAKE_CXXFLAGS += --coverage + QMAKE_LDFLAGS += --coverage + + QMAKE_EXTRA_TARGETS += coverage cov + QMAKE_EXTRA_TARGETS += clean-gcno clean-gcda coverage-html \ + generate-coverage-html clean-coverage-html coverage-gcovr \ + generate-gcovr generate-coverage-gcovr clean-coverage-gcovr + + clean-gcno.commands = \ + "@echo Removing old coverage instrumentation"; \ + "find -name '*.gcno' -print | xargs -r rm" + + clean-gcda.commands = \ + "@echo Removing old coverage results"; \ + "find -name '*.gcda' -print | xargs -r rm" + + coverage-html.depends = clean-gcda check generate-coverage-html + + generate-coverage-html.commands = \ + "@echo Collecting coverage data"; \ + "lcov --directory $${top_srcdir} --capture --output-file coverage.info --no-checksum --compat-libtool"; \ + "lcov --extract coverage.info \"*/server/*.cpp\" --extract coverage.info \"*/libnymea-remoteproxy/*.cpp\" --extract coverage.info \"*/libnymea-remoteproxyclient/*.cpp\" -o coverage.info"; \ + "lcov --remove coverage.info \"moc_*.cpp\" --remove coverage.info \"*/test/*\" -o coverage.info"; \ + "LANG=C genhtml --prefix $${top_srcdir} --output-directory coverage-html --title \"nymea-remoteproxy coverage\" --legend --show-details coverage.info" + + clean-coverage-html.depends = clean-gcda + clean-coverage-html.commands = \ + "lcov --directory $${top_srcdir} -z"; \ + "rm -rf coverage.info coverage-html" + + coverage-gcovr.depends = clean-gcda check generate-coverage-gcovr + + generate-coverage-gcovr.commands = \ + "@echo Generating coverage GCOVR report"; \ + "gcovr -x -r $${top_srcdir} -o $${top_srcdir}/coverage.xml -e \".*/moc_.*\" -e \"tests/.*\" -e \".*\\.h\"" + + clean-coverage-gcovr.depends = clean-gcda + clean-coverage-gcovr.commands = \ + "rm -rf $${top_srcdir}/coverage.xml" + + QMAKE_CLEAN += *.gcda *.gcno coverage.info coverage.xml +} diff --git a/nymea-remoteproxy.pro b/nymea-remoteproxy.pro index 67c3a5a..f1c2f89 100644 --- a/nymea-remoteproxy.pro +++ b/nymea-remoteproxy.pro @@ -5,4 +5,3 @@ SUBDIRS += server libnymea-remoteproxy libnymea-remoteproxyclient tests server.depends = libnymea-remoteproxy tests.depends = libnymea-remoteproxy libnymea-remoteproxyclient - diff --git a/tests/nymea-remoteproxy-tests.cpp b/tests/nymea-remoteproxy-tests.cpp index eaa1295..dd295da 100644 --- a/tests/nymea-remoteproxy-tests.cpp +++ b/tests/nymea-remoteproxy-tests.cpp @@ -6,6 +6,8 @@ #include #include +#include +#include RemoteProxyTests::RemoteProxyTests(QObject *parent) : QObject(parent) @@ -51,18 +53,30 @@ void RemoteProxyTests::restartEngine() QVERIFY(Engine::exists()); } +void RemoteProxyTests::startEngine() +{ + if (!Engine::exists()) { + Engine::instance(); + QVERIFY(Engine::exists()); + } +} + void RemoteProxyTests::startServer() { - restartEngine(); + startEngine(); + QString serverName = "nymea-remoteproxy-testserver"; + Engine::instance()->setAuthenticationServerUrl(QUrl("https://localhost")); + Engine::instance()->setServerName(serverName); Engine::instance()->setAuthenticator(m_authenticator); Engine::instance()->setWebSocketServerPort(m_port); Engine::instance()->setWebSocketServerHostAddress(QHostAddress::LocalHost); Engine::instance()->setSslConfiguration(m_sslConfiguration); Engine::instance()->start(); + QVERIFY(Engine::instance()->serverName() == serverName); QVERIFY(Engine::instance()->running()); - + QVERIFY(Engine::instance()->webSocketServer()->running()); } void RemoteProxyTests::stopServer() @@ -88,32 +102,73 @@ void RemoteProxyTests::cleanupTestCase() cleanUpEngine(); } -void RemoteProxyTests::authenticate() -{ -// // Start the server -// startServer(); - -// // Connect to the server -// RemoteProxyConnector *connector = new RemoteProxyConnector(this); -// connector->setInsecureConnection(true); - -// QSignalSpy spy(connector, &RemoteProxyConnector::connected); -// connector->connectServer(QHostAddress::LocalHost, m_port); -// spy.wait(); - -// connector->disconnectServer(); -// connector->deleteLater(); -// Engine::instance()->stop(); -} - void RemoteProxyTests::startStopServer() { - restartEngine(); + startEngine(); startServer(); stopServer(); cleanUpEngine(); } +void RemoteProxyTests::webserverConnectionBlocked() +{ + // Create a dummy server which blocks the port + QWebSocketServer dummyServer("dummy-server", QWebSocketServer::NonSecureMode); + dummyServer.listen(QHostAddress::LocalHost, m_port); + + // Start proxy webserver + Engine::instance()->setWebSocketServerPort(m_port); + Engine::instance()->setAuthenticator(m_authenticator); + Engine::instance()->setWebSocketServerHostAddress(QHostAddress::LocalHost); + Engine::instance()->setSslConfiguration(m_sslConfiguration); + Engine::instance()->start(); + + // Make sure the server is not running + QVERIFY(Engine::instance()->running()); + QVERIFY(!Engine::instance()->webSocketServer()->running()); + + dummyServer.close(); + + // Try again + startServer(); + + // Clean up + stopServer(); + cleanUpEngine(); +} + +void RemoteProxyTests::webserverSocketVersion() +{ + // Start the server + startServer(); + + QUrl serverUrl; + serverUrl.setScheme("wss"); + serverUrl.setHost("localhost"); + serverUrl.setPort(m_port); + + // Create a websocket with invalid version + QWebSocket socket("tests", QWebSocketProtocol::Version8); + socket.open(serverUrl); + + // Clean up + stopServer(); + cleanUpEngine(); +} + +void RemoteProxyTests::webserverConnection() +{ + // Start the server + startServer(); + + + + + // Clean up + stopServer(); + cleanUpEngine(); +} + void RemoteProxyTests::sslConfigurations() { // Start the server @@ -147,4 +202,23 @@ void RemoteProxyTests::sslConfigurations() Engine::instance()->stop(); } +void RemoteProxyTests::authenticate() +{ +// // Start the server +// startServer(); + +// // Connect to the server +// RemoteProxyConnector *connector = new RemoteProxyConnector(this); +// connector->setInsecureConnection(true); + +// QSignalSpy spy(connector, &RemoteProxyConnector::connected); +// connector->connectServer(QHostAddress::LocalHost, m_port); +// spy.wait(); + +// connector->disconnectServer(); +// connector->deleteLater(); +// Engine::instance()->stop(); +} + + QTEST_MAIN(RemoteProxyTests) diff --git a/tests/nymea-remoteproxy-tests.h b/tests/nymea-remoteproxy-tests.h index c74d336..81e3531 100644 --- a/tests/nymea-remoteproxy-tests.h +++ b/tests/nymea-remoteproxy-tests.h @@ -25,6 +25,7 @@ private: void cleanUpEngine(); void restartEngine(); + void startEngine(); void startServer(); void stopServer(); @@ -35,8 +36,11 @@ protected slots: private slots: void startStopServer(); - void authenticate(); + void webserverConnectionBlocked(); + void webserverSocketVersion(); + void webserverConnection(); void sslConfigurations(); + void authenticate(); };