diff --git a/create-coverage-html.sh b/create-coverage-html.sh
index cbbc6d1..a6908b8 100755
--- a/create-coverage-html.sh
+++ b/create-coverage-html.sh
@@ -6,7 +6,7 @@ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(pwd)/libnymea-remoteproxy:$(pwd)/libny
# Build
qmake CONFIG+=coverage CONFIG+=ccache
make -j$(nproc)
-#make check
+#make test
make coverage-html
# Clean build
diff --git a/libnymea-remoteproxy/authentication/authenticationreply.cpp b/libnymea-remoteproxy/authentication/authenticationreply.cpp
index c7fa483..79bf9f4 100644
--- a/libnymea-remoteproxy/authentication/authenticationreply.cpp
+++ b/libnymea-remoteproxy/authentication/authenticationreply.cpp
@@ -26,23 +26,30 @@
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "engine.h"
+#include "loggingcategories.h"
#include "authenticationreply.h"
#include "authentication/authenticator.h"
namespace remoteproxy {
AuthenticationReply::AuthenticationReply(ProxyClient *proxyClient, QObject *parent) :
- QObject(parent),
- m_proxyClient(proxyClient)
+ QObject(parent)
{
+ m_proxyClient = proxyClient;
+
m_timer = new QTimer(this);
m_timer->setSingleShot(true);
connect(m_timer, &QTimer::timeout, this, &AuthenticationReply::onTimeout);
-
+ qCDebug(dcAuthentication) << "Created authentication reply for" << proxyClient << "Timeout:" << Engine::instance()->configuration()->authenticationTimeout() << "[ms]";
m_timer->start(Engine::instance()->configuration()->authenticationTimeout());
}
-ProxyClient *AuthenticationReply::proxyClient() const
+AuthenticationReply::~AuthenticationReply()
+{
+ qCCritical(dcAuthentication()) << "Destroy authentication reply";
+}
+
+QPointer AuthenticationReply::proxyClient() const
{
return m_proxyClient;
}
diff --git a/libnymea-remoteproxy/authentication/authenticationreply.h b/libnymea-remoteproxy/authentication/authenticationreply.h
index e57bf69..cf4d82f 100644
--- a/libnymea-remoteproxy/authentication/authenticationreply.h
+++ b/libnymea-remoteproxy/authentication/authenticationreply.h
@@ -31,6 +31,7 @@
#include
#include
#include
+#include
#include
#include
@@ -44,7 +45,7 @@ class AuthenticationReply : public QObject
public:
friend class Authenticator;
- ProxyClient *proxyClient() const;
+ QPointer proxyClient() const;
bool isTimedOut() const;
bool isFinished() const;
@@ -53,7 +54,9 @@ public:
private:
explicit AuthenticationReply(ProxyClient *proxyClient, QObject *parent = nullptr);
- ProxyClient *m_proxyClient = nullptr;
+ ~AuthenticationReply();
+
+ QPointer m_proxyClient;
QTimer *m_timer = nullptr;
bool m_timedOut = false;
diff --git a/libnymea-remoteproxy/authentication/authenticator.cpp b/libnymea-remoteproxy/authentication/authenticator.cpp
index d6c1b7f..329d76e 100644
--- a/libnymea-remoteproxy/authentication/authenticator.cpp
+++ b/libnymea-remoteproxy/authentication/authenticator.cpp
@@ -37,6 +37,11 @@ Authenticator::Authenticator(QObject *parent) :
}
+Authenticator::~Authenticator()
+{
+
+}
+
void Authenticator::setReplyError(AuthenticationReply *reply, Authenticator::AuthenticationError error)
{
reply->setError(error);
@@ -52,9 +57,4 @@ AuthenticationReply *Authenticator::createAuthenticationReply(ProxyClient *proxy
return new AuthenticationReply(proxyClient, parent);
}
-Authenticator::~Authenticator()
-{
-
-}
-
}
diff --git a/libnymea-remoteproxy/jsonrpc/authenticationhandler.cpp b/libnymea-remoteproxy/jsonrpc/authenticationhandler.cpp
index 127058f..57ab1fb 100644
--- a/libnymea-remoteproxy/jsonrpc/authenticationhandler.cpp
+++ b/libnymea-remoteproxy/jsonrpc/authenticationhandler.cpp
@@ -89,7 +89,7 @@ void AuthenticationHandler::onAuthenticationFinished()
AuthenticationReply *authenticationReply = static_cast(sender());
authenticationReply->deleteLater();
- qCDebug(dcJsonRpc()) << "Authentication response ready for" << authenticationReply->proxyClient() << authenticationReply->error();
+ qCDebug(dcJsonRpc()) << "Authentication reply finished";
JsonReply *jsonReply = m_runningAuthentications.take(authenticationReply);
if (authenticationReply->error() != Authenticator::AuthenticationErrorNoError) {
@@ -100,10 +100,12 @@ void AuthenticationHandler::onAuthenticationFinished()
jsonReply->setSuccess(true);
}
- // Set client authenticated
- authenticationReply->proxyClient()->setAuthenticated(authenticationReply->error() == Authenticator::AuthenticationErrorNoError);
+ // Set client authenticated if still there
+ if (!authenticationReply->proxyClient().isNull()) {
+ authenticationReply->proxyClient()->setAuthenticated(authenticationReply->error() == Authenticator::AuthenticationErrorNoError);
+ jsonReply->setData(errorToReply(authenticationReply->error()));
+ }
- jsonReply->setData(errorToReply(authenticationReply->error()));
jsonReply->finished();
}
diff --git a/libnymea-remoteproxy/jsonrpcserver.cpp b/libnymea-remoteproxy/jsonrpcserver.cpp
index 8b64e0f..b74d3a8 100644
--- a/libnymea-remoteproxy/jsonrpcserver.cpp
+++ b/libnymea-remoteproxy/jsonrpcserver.cpp
@@ -188,7 +188,7 @@ void JsonRpcServer::asyncReplyFinished()
qCDebug(dcJsonRpc()) << "Async reply finished" << reply->handler()->name() << reply->method() << reply->clientId().toString();
if (!proxyClient) {
- qCWarning(dcJsonRpc()) << "Got an async reply but the client does not exist any more";
+ qCWarning(dcJsonRpc()) << "Got an async reply but the client does not exist any more.";
return;
}
@@ -210,6 +210,7 @@ void JsonRpcServer::asyncReplyFinished()
}
} else {
+ qCWarning(dcJsonRpc()) << "The reply timeouted.";
sendErrorResponse(proxyClient, reply->commandId(), "Command timed out");
// Disconnect this client since he requested something that created a timeout
proxyClient->killConnection("API call timeouted.");
@@ -233,8 +234,14 @@ void JsonRpcServer::unregisterClient(ProxyClient *proxyClient)
qCWarning(dcJsonRpc()) << "Client was not registered" << proxyClient;
return;
}
-
m_clients.removeAll(proxyClient);
+
+ if (m_asyncReplies.values().contains(proxyClient)) {
+ qCWarning(dcJsonRpc()) << "Client was still waiting for a reply. Clean up reply";
+ JsonReply *reply = m_asyncReplies.key(proxyClient);
+ m_asyncReplies.remove(reply);
+ // Note: the reply will be deleted in the finished slot
+ }
}
void JsonRpcServer::processData(ProxyClient *proxyClient, const QByteArray &data)
@@ -246,7 +253,6 @@ void JsonRpcServer::processData(ProxyClient *proxyClient, const QByteArray &data
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
-
if(error.error != QJsonParseError::NoError) {
qCWarning(dcJsonRpc) << "Failed to parse JSON data" << data << ":" << error.errorString();
sendErrorResponse(proxyClient, -1, QString("Failed to parse JSON data: %1").arg(error.errorString()));
diff --git a/libnymea-remoteproxy/proxyclient.cpp b/libnymea-remoteproxy/proxyclient.cpp
index 7a95e90..10784f3 100644
--- a/libnymea-remoteproxy/proxyclient.cpp
+++ b/libnymea-remoteproxy/proxyclient.cpp
@@ -40,9 +40,10 @@ ProxyClient::ProxyClient(TransportInterface *interface, const QUuid &clientId, c
{
m_creationTimeStamp = QDateTime::currentDateTime().toTime_t();
- connect(&m_timer, &QTimer::timeout, this, &ProxyClient::timeoutOccured);
- m_timer.setSingleShot(true);
- m_timer.start(Engine::instance()->configuration()->inactiveTimeout());
+ m_timer = new QTimer(this);
+ connect(m_timer, &QTimer::timeout, this, &ProxyClient::timeoutOccured);
+ m_timer->setSingleShot(true);
+ resetTimer();
}
QUuid ProxyClient::clientId() const
@@ -74,8 +75,8 @@ void ProxyClient::setAuthenticated(bool isAuthenticated)
{
m_authenticated = isAuthenticated;
if (m_authenticated) {
- m_timer.stop();
- m_timer.start(Engine::instance()->configuration()->aloneTimeout());
+ m_timerWaitState = TimerWaitStateAlone;
+ resetTimer();
emit authenticated();
}
}
@@ -89,7 +90,7 @@ void ProxyClient::setTunnelConnected(bool isTunnelConnected)
{
m_tunnelConnected = isTunnelConnected;
if (m_tunnelConnected) {
- m_timer.stop();
+ m_timer->stop();
emit tunnelConnected();
}
}
@@ -174,6 +175,25 @@ void ProxyClient::addTxDataCount(int dataCount)
m_txDataCount += static_cast(dataCount);
}
+ProxyClient::TimerWaitState ProxyClient::timerWaitState() const
+{
+ return m_timerWaitState;
+}
+
+void ProxyClient::resetTimer()
+{
+ switch (m_timerWaitState) {
+ case TimerWaitStateInactive:
+ m_timer->stop();
+ m_timer->start(Engine::instance()->configuration()->inactiveTimeout());
+ break;
+ case TimerWaitStateAlone:
+ m_timer->stop();
+ m_timer->start(Engine::instance()->configuration()->aloneTimeout());
+ break;
+ }
+}
+
void ProxyClient::sendData(const QByteArray &data)
{
if (!m_interface)
@@ -200,8 +220,8 @@ QDebug operator<<(QDebug debug, ProxyClient *proxyClient)
debug.nospace() << ", " << proxyClient->clientId().toString();
debug.nospace() << ", " << proxyClient->userName();
debug.nospace() << ", " << proxyClient->peerAddress().toString();
- debug.nospace() << ", " << proxyClient->creationTimeString() << ") ";
- return debug;
+ debug.nospace() << ", " << proxyClient->creationTimeString() << ")";
+ return debug.space();
}
}
diff --git a/libnymea-remoteproxy/proxyclient.h b/libnymea-remoteproxy/proxyclient.h
index 58b83ac..792714f 100644
--- a/libnymea-remoteproxy/proxyclient.h
+++ b/libnymea-remoteproxy/proxyclient.h
@@ -43,6 +43,12 @@ class ProxyClient : public QObject
Q_OBJECT
public:
+ enum TimerWaitState {
+ TimerWaitStateInactive,
+ TimerWaitStateAlone
+ };
+ Q_ENUM(TimerWaitState)
+
explicit ProxyClient(TransportInterface *interface, const QUuid &clientId, const QHostAddress &address, QObject *parent = nullptr);
QUuid clientId() const;
@@ -84,12 +90,15 @@ public:
void addTxDataCount(int dataCount);
// Actions for this client
+ TimerWaitState timerWaitState() const;
+ void resetTimer();
void sendData(const QByteArray &data);
void killConnection(const QString &reason);
private:
TransportInterface *m_interface = nullptr;
- QTimer m_timer;
+ QTimer *m_timer = nullptr;
+ TimerWaitState m_timerWaitState = TimerWaitStateInactive;
QUuid m_clientId;
QHostAddress m_peerAddress;
diff --git a/libnymea-remoteproxy/proxyserver.cpp b/libnymea-remoteproxy/proxyserver.cpp
index c7f20c1..6048114 100644
--- a/libnymea-remoteproxy/proxyserver.cpp
+++ b/libnymea-remoteproxy/proxyserver.cpp
@@ -274,6 +274,8 @@ void ProxyServer::onClientDataAvailable(const QUuid &clientId, const QByteArray
if (!proxyClient->isAuthenticated() && !proxyClient->isTunnelConnected()) {
qCDebug(dcProxyServerTraffic()) << "Client data available" << proxyClient << qUtf8Printable(data);
m_jsonRpcServer->processData(proxyClient, data);
+ // Reset the inactive timer
+ proxyClient->resetTimer();
return;
}
@@ -373,8 +375,15 @@ void ProxyServer::onProxyClientAuthenticated()
void ProxyServer::onProxyClientTimeoutOccured()
{
ProxyClient *proxyClient = static_cast(sender());
- qCDebug(dcProxyServer()) << "Timeout occured for" << proxyClient;
- proxyClient->killConnection("Proxy timeout occuret");
+ qCDebug(dcProxyServer()) << "Timeout occured for" << proxyClient;
+ switch (proxyClient->timerWaitState()) {
+ case ProxyClient::TimerWaitStateInactive:
+ proxyClient->killConnection("Proxy timeout occuret. The socket was inactive.");
+ break;
+ case ProxyClient::TimerWaitStateAlone:
+ proxyClient->killConnection("Proxy timeout occuret. The tunnel partner did not show up.");
+ break;
+ }
}
void ProxyServer::startServer()
diff --git a/libnymea-remoteproxy/tcpsocketserver.cpp b/libnymea-remoteproxy/tcpsocketserver.cpp
index 40725f3..7fd358d 100644
--- a/libnymea-remoteproxy/tcpsocketserver.cpp
+++ b/libnymea-remoteproxy/tcpsocketserver.cpp
@@ -46,7 +46,10 @@ void TcpSocketServer::sendData(const QUuid &clientId, const QByteArray &data)
return;
}
- client->write(data + '\n');
+ qCDebug(dcTcpSocketServerTraffic()) << "Send data to" << clientId.toString() << data + '\n';
+ if (client->write(data + '\n') < 0) {
+ qCWarning(dcTcpSocketServer()) << "Could not write data to client socket" << clientId.toString();
+ }
}
void TcpSocketServer::killClientConnection(const QUuid &clientId, const QString &killReason)
@@ -56,7 +59,7 @@ void TcpSocketServer::killClientConnection(const QUuid &clientId, const QString
return;
qCWarning(dcTcpSocketServer()) << "Killing client connection" << clientId.toString() << "Reason:" << killReason;
- client->abort();
+ client->close();
}
bool TcpSocketServer::running() const
@@ -69,7 +72,7 @@ bool TcpSocketServer::running() const
void TcpSocketServer::onDataAvailable(QSslSocket *client, const QByteArray &data)
{
- qCDebug(dcTcpSocketServerTraffic()) << "Emitting data available internal.";
+ //qCDebug(dcTcpSocketServerTraffic()) << "Emitting data available internal.";
QUuid clientId = m_clientList.key(qobject_cast(client));
emit dataAvailable(clientId, data);
}
@@ -85,7 +88,7 @@ void TcpSocketServer::onClientConnected(QSslSocket *client)
void TcpSocketServer::onClientDisconnected(QSslSocket *client)
{
QUuid clientId = m_clientList.key(client);
- qCDebug(dcWebSocketServer()) << "Client disconnected:" << client << client->peerAddress().toString() << clientId.toString();
+ qCDebug(dcTcpSocketServer()) << "Client disconnected:" << client << client->peerAddress().toString() << clientId.toString();
m_clientList.take(clientId);
// Note: the SslServer is deleting the socket object
emit clientDisconnected(clientId);
@@ -138,12 +141,13 @@ SslServer::SslServer(bool sslEnabled, const QSslConfiguration &config, QObject *
void SslServer::incomingConnection(qintptr socketDescriptor)
{
QSslSocket *sslSocket = new QSslSocket(this);
-
- qCDebug(dcTcpSocketServer()) << "New client connected:" << sslSocket << sslSocket->peerAddress().toString();
-
- connect(sslSocket, &QSslSocket::encrypted, [this, sslSocket](){ emit clientConnected(sslSocket); });
+ qCDebug(dcTcpSocketServer()) << "Incomming connection" << sslSocket;
connect(sslSocket, &QSslSocket::readyRead, this, &SslServer::onSocketReadyRead);
connect(sslSocket, &QSslSocket::disconnected, this, &SslServer::onClientDisconnected);
+ connect(sslSocket, &QSslSocket::encrypted, [this, sslSocket](){
+ qCDebug(dcTcpSocketServer()) << "SSL encryption established for" << sslSocket;
+ emit clientConnected(sslSocket);
+ });
if (!sslSocket->setSocketDescriptor(socketDescriptor)) {
qCWarning(dcTcpSocketServer()) << "Failed to set SSL socket descriptor.";
@@ -153,6 +157,7 @@ void SslServer::incomingConnection(qintptr socketDescriptor)
if (m_sslEnabled) {
sslSocket->setSslConfiguration(m_config);
+ qCDebug(dcTcpSocketServer()) << "Start SSL encryption for" << sslSocket;
sslSocket->startServerEncryption();
} else {
emit clientConnected(sslSocket);
diff --git a/libnymea-remoteproxy/websocketserver.cpp b/libnymea-remoteproxy/websocketserver.cpp
index 205fd17..d7ffa66 100644
--- a/libnymea-remoteproxy/websocketserver.cpp
+++ b/libnymea-remoteproxy/websocketserver.cpp
@@ -78,8 +78,6 @@ void WebSocketServer::killClientConnection(const QUuid &clientId, const QString
qCWarning(dcWebSocketServer()) << "Killing client connection" << clientId.toString() << "Reason:" << killReason;
client->close(QWebSocketProtocol::CloseCodeBadOperation, killReason);
- client->flush();
- client->abort();
}
void WebSocketServer::onClientConnected()
@@ -95,9 +93,7 @@ void WebSocketServer::onClientConnected()
if (client->version() != QWebSocketProtocol::Version13) {
qCWarning(dcWebSocketServer()) << "Client with invalid protocol version" << client->version() << ". Rejecting.";
client->close(QWebSocketProtocol::CloseCodeProtocolError, QString("invalid protocol version: %1 != Supported Version 13").arg(client->version()));
- client->flush();
- client->abort();
- delete client;
+ client->deleteLater();
return;
}
@@ -125,8 +121,6 @@ void WebSocketServer::onClientDisconnected()
// Manually close it in any case
client->close();
- client->flush();
- client->abort();
m_clientList.take(clientId)->deleteLater();
emit clientDisconnected(clientId);
@@ -145,8 +139,6 @@ void WebSocketServer::onBinaryMessageReceived(const QByteArray &data)
qCWarning(dcWebSocketServerTraffic()) << "<-- Binary message from" << client->peerAddress().toString() << ":" << data;
// Note: this is not expected, so close this client connection.
client->close(QWebSocketProtocol::CloseCodeBadOperation, "Binary message not expected.");
- client->flush();
- client->abort();
}
void WebSocketServer::onClientError(QAbstractSocket::SocketError error)
@@ -156,8 +148,6 @@ void WebSocketServer::onClientError(QAbstractSocket::SocketError error)
// Note: on any error which can occure, make sure the socket will be closed in any case
client->close();
- client->flush();
- client->abort();
}
void WebSocketServer::onAcceptError(QAbstractSocket::SocketError error)
diff --git a/libnymea-remoteproxyclient/libnymea-remoteproxyclient.pri b/libnymea-remoteproxyclient/libnymea-remoteproxyclient.pri
index 6ae9be7..d1d89c8 100644
--- a/libnymea-remoteproxyclient/libnymea-remoteproxyclient.pri
+++ b/libnymea-remoteproxyclient/libnymea-remoteproxyclient.pri
@@ -1,7 +1,7 @@
INCLUDEPATH += $${PWD}
HEADERS += \
- $$PWD/tcpsocketconnection.h \
+ $${PWD}/tcpsocketconnection.h \
$${PWD}/proxyjsonrpcclient.h \
$${PWD}/jsonreply.h \
$${PWD}/remoteproxyconnection.h \
@@ -9,7 +9,7 @@ HEADERS += \
$${PWD}/websocketconnection.h
SOURCES += \
- $$PWD/tcpsocketconnection.cpp \
+ $${PWD}/tcpsocketconnection.cpp \
$${PWD}/proxyjsonrpcclient.cpp \
$${PWD}/jsonreply.cpp \
$${PWD}/remoteproxyconnection.cpp \
diff --git a/libnymea-remoteproxyclient/remoteproxyconnection.cpp b/libnymea-remoteproxyclient/remoteproxyconnection.cpp
index 73e0a10..dde5028 100644
--- a/libnymea-remoteproxyclient/remoteproxyconnection.cpp
+++ b/libnymea-remoteproxyclient/remoteproxyconnection.cpp
@@ -319,23 +319,18 @@ void RemoteProxyConnection::onTunnelEstablished(const QString &clientName, const
bool RemoteProxyConnection::connectServer(const QUrl &url)
{
- if (url.scheme() != "wss") {
- // FIXME: support also tcp
- qCWarning(dcRemoteProxyClientConnection()) << "Unsupported connection type" << url.scheme() << "Default to wss";
- m_serverUrl.setScheme("wss");
- }
-
m_serverUrl = url;
- m_connectionType = ConnectionTypeWebSocket;
m_error = QAbstractSocket::UnknownSocketError;
cleanUp();
switch (m_connectionType) {
case ConnectionTypeWebSocket:
+ qCDebug(dcRemoteProxyClientConnection()) << "Creating a web socket connection to" << url.toString();
m_connection = qobject_cast(new WebSocketConnection(this));
break;
case ConnectionTypeTcpSocket:
+ qCDebug(dcRemoteProxyClientConnection()) << "Creating a TCP socket connection to" << url.toString();
m_connection = qobject_cast(new TcpSocketConnection(this));
break;
}
diff --git a/libnymea-remoteproxyclient/tcpsocketconnection.cpp b/libnymea-remoteproxyclient/tcpsocketconnection.cpp
index 13bbf13..4ad69a3 100644
--- a/libnymea-remoteproxyclient/tcpsocketconnection.cpp
+++ b/libnymea-remoteproxyclient/tcpsocketconnection.cpp
@@ -31,6 +31,7 @@ TcpSocketConnection::TcpSocketConnection(QObject *parent) :
connect(m_tcpSocket, &QSslSocket::disconnected, this, &TcpSocketConnection::onDisconnected);
connect(m_tcpSocket, &QSslSocket::encrypted, this, &TcpSocketConnection::onEncrypted);
+ connect(m_tcpSocket, &QSslSocket::readyRead, this, &TcpSocketConnection::onReadyRead);
connect(m_tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError)));
connect(m_tcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onStateChanged(QAbstractSocket::SocketState)));
connect(m_tcpSocket, SIGNAL(sslErrors(QList)), this, SIGNAL(sslErrors(QList)));
@@ -65,6 +66,7 @@ void TcpSocketConnection::onDisconnected()
void TcpSocketConnection::onEncrypted()
{
qCDebug(dcRemoteProxyClientTcpSocket()) << "Connection encrypted";
+ setConnected(true);
}
void TcpSocketConnection::onError(QAbstractSocket::SocketError error)
@@ -80,7 +82,9 @@ void TcpSocketConnection::onStateChanged(QAbstractSocket::SocketState state)
switch (state) {
case QAbstractSocket::ConnectedState:
qCDebug(dcRemoteProxyClientTcpSocket()) << "Connected with" << serverUrl().toString();
- setConnected(true);
+ if (!m_ssl) {
+ setConnected(true);
+ }
break;
default:
setConnected(false);
@@ -97,12 +101,13 @@ void TcpSocketConnection::onReadyRead()
void TcpSocketConnection::connectServer(const QUrl &serverUrl)
{
- qCDebug(dcRemoteProxyClientTcpSocket()) << "Connecting to" << this->serverUrl().toString();
setServerUrl(serverUrl);
+ qCDebug(dcRemoteProxyClientTcpSocket()) << "Connecting to" << this->serverUrl().toString();
if (serverUrl.scheme() == "tcp") {
m_tcpSocket->connectToHost(QHostAddress(this->serverUrl().host()), static_cast(this->serverUrl().port()));
} else {
+ m_ssl = true;
m_tcpSocket->connectToHostEncrypted(this->serverUrl().host(), static_cast(this->serverUrl().port()));
}
}
diff --git a/libnymea-remoteproxyclient/tcpsocketconnection.h b/libnymea-remoteproxyclient/tcpsocketconnection.h
index f4fc187..934536e 100644
--- a/libnymea-remoteproxyclient/tcpsocketconnection.h
+++ b/libnymea-remoteproxyclient/tcpsocketconnection.h
@@ -48,6 +48,7 @@ public:
private:
QSslSocket *m_tcpSocket = nullptr;
+ bool m_ssl = false;
private slots:
void onDisconnected();
diff --git a/nymea-remoteproxy.pri b/nymea-remoteproxy.pri
index 314a20b..38806df 100644
--- a/nymea-remoteproxy.pri
+++ b/nymea-remoteproxy.pri
@@ -23,7 +23,7 @@ ccache {
QMAKE_CXX = ccache g++
}
-coverage {<
+coverage {
# Note: this works only if you build in the source dir
OBJECTS_DIR =
MOC_DIR =
diff --git a/nymea-remoteproxy.pro b/nymea-remoteproxy.pro
index 3d44545..2e38692 100644
--- a/nymea-remoteproxy.pro
+++ b/nymea-remoteproxy.pro
@@ -15,7 +15,9 @@ server.depends = libnymea-remoteproxy
client.depends = libnymea-remoteproxyclient
tests.depends = libnymea-remoteproxy libnymea-remoteproxyclient
-test.commands = LD_LIBRARY_PATH=$$top_builddir/libnymea-remoteproxy:$$top_builddir/libnymea-remoteproxyclient make check
+test.commands = LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:$$top_builddir/libnymea-remoteproxy:$$top_builddir/libnymea-remoteproxyclient \
+ LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:$$top_srcdir/libnymea-remoteproxy:$$top_srcdir/libnymea-remoteproxyclient \
+ make check
QMAKE_EXTRA_TARGETS += test
message("----------------------------------------------------------")
diff --git a/tests/resources/test-configuration.conf b/tests/resources/test-configuration.conf
index e0fb21e..54bec2c 100644
--- a/tests/resources/test-configuration.conf
+++ b/tests/resources/test-configuration.conf
@@ -3,10 +3,10 @@ name=test-nymea-remoteproxy
writeLogs=false
logFile=/var/log/nymea-remoteproxy.log
monitorSocket=/tmp/nymea-remoteproxy-test.sock
-jsonRpcTimeout=1000
-authenticationTimeout=1500
+jsonRpcTimeout=2000
+authenticationTimeout=1000
inactiveTimeout=1500
-aloneTimeout=1000
+aloneTimeout=1500
[SSL]
certificate=:/test-certificate.crt
diff --git a/tests/test-offline/nymea-remoteproxy-tests-offline.cpp b/tests/test-offline/nymea-remoteproxy-tests-offline.cpp
index 4a4ee39..b845662 100644
--- a/tests/test-offline/nymea-remoteproxy-tests-offline.cpp
+++ b/tests/test-offline/nymea-remoteproxy-tests-offline.cpp
@@ -53,9 +53,14 @@ void RemoteProxyOfflineTests::dummyAuthenticator()
{
cleanUpEngine();
+ m_configuration = new ProxyConfiguration(this);
+ loadConfiguration(":/test-configuration.conf");
+
+ m_dummyAuthenticator = new DummyAuthenticator(this);
+ m_authenticator = qobject_cast(m_dummyAuthenticator);
+
// Start proxy webserver
Engine::instance()->setAuthenticator(m_dummyAuthenticator);
- Engine::instance()->setAuthenticator(m_dummyAuthenticator);
QSignalSpy runningSpy(Engine::instance(), &Engine::runningChanged);
Engine::instance()->start(m_configuration);
runningSpy.wait();
@@ -209,16 +214,21 @@ void RemoteProxyOfflineTests::serverPortBlocked()
{
cleanUpEngine();
+ m_configuration = new ProxyConfiguration(this);
+ loadConfiguration(":/test-configuration.conf");
+
+ m_mockAuthenticator = new MockAuthenticator(this);
+ m_authenticator = qobject_cast(m_mockAuthenticator);
+
// Create a dummy server which blocks the port
QWebSocketServer dummyServer("dummy-server", QWebSocketServer::NonSecureMode);
- dummyServer.listen(QHostAddress::LocalHost, 1212);
+ QVERIFY(dummyServer.listen(QHostAddress::LocalHost, m_configuration->webSocketServerPort()));
// Start proxy webserver
QSignalSpy runningSpy(Engine::instance(), &Engine::runningChanged);
Engine::instance()->setAuthenticator(m_authenticator);
Engine::instance()->start(m_configuration);
runningSpy.wait();
- qDebug() << runningSpy.count();
QVERIFY(runningSpy.count() == 1);
// Make sure the server is not running
@@ -233,11 +243,49 @@ void RemoteProxyOfflineTests::serverPortBlocked()
QVERIFY(closedSpy.count() == 1);
// Try again
- cleanUpEngine();
startServer();
// Clean up
stopServer();
+
+ // Do the same with the tcp server
+ cleanUpEngine();
+
+ m_configuration = new ProxyConfiguration(this);
+ loadConfiguration(":/test-configuration.conf");
+
+ m_mockAuthenticator = new MockAuthenticator(this);
+ m_authenticator = qobject_cast(m_mockAuthenticator);
+
+ // Create a dummy server which blocks the port
+ QTcpServer *tcpDummyServer = new QTcpServer(this);
+ QVERIFY(tcpDummyServer->listen(QHostAddress::LocalHost, m_configuration->tcpServerPort()));
+
+ // Start proxy webserver
+ QSignalSpy runningSpy2(Engine::instance(), &Engine::runningChanged);
+ Engine::instance()->setAuthenticator(m_authenticator);
+ Engine::instance()->start(m_configuration);
+ runningSpy2.wait();
+ QVERIFY(runningSpy2.count() == 1);
+
+ // Make sure the engine is running
+ QVERIFY(Engine::instance()->running());
+
+ // Make sure the TCP server is not running
+ QVERIFY(!Engine::instance()->tcpSocketServer()->running());
+
+ tcpDummyServer->close();
+ delete tcpDummyServer;
+
+ // Try again
+ startServer();
+
+ // Make sure the TCP server is not running
+ QVERIFY(Engine::instance()->webSocketServer()->running());
+ QVERIFY(Engine::instance()->tcpSocketServer()->running());
+
+ // Clean up
+ stopServer();
}
void RemoteProxyOfflineTests::websocketBinaryData()
@@ -286,13 +334,70 @@ void RemoteProxyOfflineTests::websocketPing()
stopServer();
}
+//void RemoteProxyOfflineTests::apiBasicCallsTcp_data()
+//{
+// QTest::addColumn("data");
+// QTest::addColumn("responseId");
+// QTest::addColumn("responseStatus");
+
+// QTest::newRow("valid call") << QByteArray("{\"id\":42, \"method\":\"RemoteProxy.Hello\"}") << 42 << "success";
+// QTest::newRow("missing id") << QByteArray("{\"method\":\"RemoteProxy.Hello\"}") << -1 << "error";
+// QTest::newRow("missing method") << QByteArray("{\"id\":42}") << 42 << "error";
+// QTest::newRow("invalid json") << QByteArray("{\"id\":42, \"method\":\"RemoteProx") << -1 << "error";
+// QTest::newRow("invalid function") << QByteArray("{\"id\":42, \"method\":\"RemoteProxy.Explode\"}") << 42 << "error";
+// QTest::newRow("invalid namespace") << QByteArray("{\"id\":42, \"method\":\"ProxyRemote.Hello\"}") << 42 << "error";
+// QTest::newRow("missing dot") << QByteArray("{\"id\":42, \"method\":\"RemoteProxyHello\"}") << 42 << "error";
+// QTest::newRow("invalid params") << QByteArray("{\"id\":42, \"method\":\"RemoteProxy.Hello\", \"params\":{\"törööö\":\"chooo-chooo\"}}") << 42 << "error";
+// QTest::newRow("invalid authentication params") << QByteArray("{\"id\":42, \"method\":\"Authentication.Authenticate\", \"params\":{\"your\":\"mamma\"}}") << 42 << "error";
+//}
+
+//void RemoteProxyOfflineTests::apiBasicCallsTcp()
+//{
+// QFETCH(QByteArray, data);
+// QFETCH(int, responseId);
+// QFETCH(QString, responseStatus);
+
+// // Start the server
+// startServer();
+
+// QVariant response = injectTcpSocketData(data);
+// QVERIFY(!response.isNull());
+
+// qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
+
+// QCOMPARE(response.toMap().value("id").toInt(), responseId);
+// QCOMPARE(response.toMap().value("status").toString(), responseStatus);
+
+// // Clean up
+// stopServer();
+//}
+
void RemoteProxyOfflineTests::getIntrospect()
{
// Start the server
startServer();
- QVariant response = invokeWebSocketApiCall("RemoteProxy.Introspect");
- qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
+ QVariantMap response;
+
+ // WebSocket
+ response = invokeWebSocketApiCall("RemoteProxy.Introspect").toMap();
+ //qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
+ QVERIFY(!response.isEmpty());
+ QVERIFY(response.value("status").toString() == "success");
+ QVERIFY(response.value("params").toMap().contains("methods"));
+ QVERIFY(response.value("params").toMap().contains("notifications"));
+ QVERIFY(response.value("params").toMap().contains("types"));
+
+ // Tcp
+ response.clear();
+ response = invokeTcpSocketApiCall("RemoteProxy.Introspect").toMap();
+ //qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
+
+ QVERIFY(!response.isEmpty());
+ QVERIFY(response.value("status").toString() == "success");
+ QVERIFY(response.value("params").toMap().contains("methods"));
+ QVERIFY(response.value("params").toMap().contains("notifications"));
+ QVERIFY(response.value("params").toMap().contains("types"));
// Clean up
stopServer();
@@ -302,16 +407,32 @@ void RemoteProxyOfflineTests::getHello()
{
// Start the server
startServer();
+ QVariantMap response;
- QVariantMap response = invokeWebSocketApiCall("RemoteProxy.Hello").toMap();
- qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
+ // WebSocket
+ response = invokeWebSocketApiCall("RemoteProxy.Hello").toMap();
+ //qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
// Verify data
+ QVERIFY(!response.isEmpty());
QCOMPARE(response.value("params").toMap().value("name").toString(), Engine::instance()->configuration()->serverName());
QCOMPARE(response.value("params").toMap().value("server").toString(), QString(SERVER_NAME_STRING));
QCOMPARE(response.value("params").toMap().value("version").toString(), QString(SERVER_VERSION_STRING));
QCOMPARE(response.value("params").toMap().value("apiVersion").toString(), QString(API_VERSION_STRING));
+ // TCP
+ response.clear();
+ response = invokeTcpSocketApiCall("RemoteProxy.Hello").toMap();
+ //qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
+
+ // Verify data
+ QVERIFY(!response.isEmpty());
+ QCOMPARE(response.value("params").toMap().value("name").toString(), Engine::instance()->configuration()->serverName());
+ QCOMPARE(response.value("params").toMap().value("server").toString(), QString(SERVER_NAME_STRING));
+ QCOMPARE(response.value("params").toMap().value("version").toString(), QString(SERVER_VERSION_STRING));
+ QCOMPARE(response.value("params").toMap().value("apiVersion").toString(), QString(API_VERSION_STRING));
+
+
// Clean up
stopServer();
}
@@ -342,11 +463,22 @@ void RemoteProxyOfflineTests::apiBasicCalls()
// Start the server
startServer();
- QVariant response = injectWebSocketData(data);
- qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
+ QVariantMap response;
- QCOMPARE(response.toMap().value("id").toInt(), responseId);
- QCOMPARE(response.toMap().value("status").toString(), responseStatus);
+ // Websocket
+ response = injectWebSocketData(data).toMap();
+ //qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
+ QVERIFY(!response.isEmpty());
+ QCOMPARE(response.value("id").toInt(), responseId);
+ QCOMPARE(response.value("status").toString(), responseStatus);
+
+ // TCP
+ response.clear();
+ response = injectTcpSocketData(data).toMap();
+ //qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
+ QVERIFY(!response.isEmpty());
+ QCOMPARE(response.value("id").toInt(), responseId);
+ QCOMPARE(response.value("status").toString(), responseStatus);
// Clean up
stopServer();
@@ -409,8 +541,14 @@ void RemoteProxyOfflineTests::authenticate()
params.insert("token", token);
if (!nonce.isEmpty()) params.insert("nonce", nonce);
- QVariant response = invokeWebSocketApiCall("Authentication.Authenticate", params);
- qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
+ // WebSocket
+ QVariantMap response;
+ response = invokeWebSocketApiCall("Authentication.Authenticate", params).toMap();
+ //qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
+ verifyAuthenticationError(response, expectedError);
+
+ // TCP
+ response = invokeTcpSocketApiCall("Authentication.Authenticate", params).toMap();
verifyAuthenticationError(response, expectedError);
// Clean up
@@ -518,6 +656,9 @@ void RemoteProxyOfflineTests::authenticateSendData()
// Start the server
startServer();
+ m_mockAuthenticator->setTimeoutDuration(100);
+ m_mockAuthenticator->setExpectedAuthenticationError();
+
QVariantMap params;
params.insert("uuid", "uuid");
params.insert("name", "name");
@@ -533,18 +674,18 @@ void RemoteProxyOfflineTests::authenticateSendData()
// Connect socket
QWebSocket *socket = new QWebSocket("proxy-testclient", QWebSocketProtocol::Version13);
connect(socket, &QWebSocket::sslErrors, this, &BaseTest::sslErrors);
- QSignalSpy spyConnection(socket, SIGNAL(connected()));
+ QSignalSpy spyConnection(socket, &QWebSocket::connected);
socket->open(Engine::instance()->webSocketServer()->serverUrl());
spyConnection.wait();
QVERIFY(spyConnection.count() == 1);
// Authenticate
- QSignalSpy dataSpy(socket, SIGNAL(textMessageReceived(QString)));
+ QSignalSpy dataSpy(socket, &QWebSocket::textMessageReceived);
socket->sendTextMessage(QString(jsonDoc.toJson(QJsonDocument::Compact)));
dataSpy.wait();
QVERIFY(dataSpy.count() == 1);
- // Send data and make sure we get disconnected
+ // Send data again and make sure we get disconnected since sending data while waiting for the partner is forbidden
QSignalSpy disconnectedSpy(socket, SIGNAL(disconnected()));
socket->sendTextMessage(QString(jsonDoc.toJson(QJsonDocument::Compact)));
disconnectedSpy.wait();
@@ -556,7 +697,7 @@ void RemoteProxyOfflineTests::authenticateSendData()
stopServer();
}
-void RemoteProxyOfflineTests::clientConnection()
+void RemoteProxyOfflineTests::clientConnectionWebSocket()
{
// Start the server
startServer();
@@ -565,7 +706,7 @@ void RemoteProxyOfflineTests::clientConnection()
m_mockAuthenticator->setTimeoutDuration(100);
m_mockAuthenticator->setExpectedAuthenticationError();
- // Connect to the server (insecure disabled)
+ // Connect to the server using WebSocket (insecure disabled)
RemoteProxyConnection *connection = new RemoteProxyConnection(QUuid::createUuid(), "Test client one", this);
connect(connection, &RemoteProxyConnection::sslErrors, this, &BaseTest::ignoreConnectionSslError);
@@ -606,6 +747,56 @@ void RemoteProxyOfflineTests::clientConnection()
stopServer();
}
+void RemoteProxyOfflineTests::clientConnectionTcpSocket()
+{
+ // Start the server
+ startServer();
+
+ // Configure mock authenticator
+ m_mockAuthenticator->setTimeoutDuration(100);
+ m_mockAuthenticator->setExpectedAuthenticationError();
+
+ // Connect to the server using TCP (insecure disabled)
+ RemoteProxyConnection *connection = new RemoteProxyConnection(QUuid::createUuid(), "Test client one", RemoteProxyConnection::ConnectionTypeTcpSocket, this);
+ connect(connection, &RemoteProxyConnection::sslErrors, this, &BaseTest::ignoreConnectionSslError);
+
+ // Connect to server (insecue enabled for testing)
+ QSignalSpy readySpy(connection, &RemoteProxyConnection::ready);
+ QVERIFY(connection->connectServer(m_serverUrlTcp));
+ readySpy.wait();
+ QVERIFY(readySpy.count() == 1);
+ QVERIFY(connection->isConnected());
+ QVERIFY(!connection->isRemoteConnected());
+ QVERIFY(connection->state() == RemoteProxyConnection::StateReady);
+ QVERIFY(connection->error() == QAbstractSocket::UnknownSocketError);
+ QVERIFY(connection->serverUrl() == m_serverUrlTcp);
+ QVERIFY(connection->connectionType() == RemoteProxyConnection::ConnectionTypeTcpSocket);
+ QVERIFY(connection->serverName() == SERVER_NAME_STRING);
+ QVERIFY(connection->proxyServerName() == Engine::instance()->serverName());
+ QVERIFY(connection->proxyServerVersion() == SERVER_VERSION_STRING);
+ QVERIFY(connection->proxyServerApiVersion() == API_VERSION_STRING);
+
+ QSignalSpy authenticatedSpy(connection, &RemoteProxyConnection::authenticated);
+ QVERIFY(connection->authenticate("foobar"));
+ authenticatedSpy.wait();
+ QVERIFY(authenticatedSpy.count() == 1);
+ QVERIFY(connection->isConnected());
+ QVERIFY(connection->isAuthenticated());
+ QVERIFY(connection->state() == RemoteProxyConnection::StateAuthenticated);
+
+ // Disconnect and clean up
+ QSignalSpy spyDisconnected(connection, &RemoteProxyConnection::disconnected);
+ connection->disconnectServer();
+ // FIXME: check why it waits the full time here
+ spyDisconnected.wait(500);
+
+ QVERIFY(spyDisconnected.count() >= 1);
+ QVERIFY(!connection->isConnected());
+
+ connection->deleteLater();
+ stopServer();
+}
+
void RemoteProxyOfflineTests::remoteConnection()
{
// Start the server
@@ -912,6 +1103,10 @@ void RemoteProxyOfflineTests::jsonRpcTimeout()
// Start the server
startServer();
+ m_configuration->setAuthenticationTimeout(3000);
+ m_configuration->setJsonRpcTimeout(1000);
+ m_configuration->setInactiveTimeout(2000);
+
// Configure result (authentication takes longer than json rpc timeout
m_mockAuthenticator->setExpectedAuthenticationError();
m_mockAuthenticator->setTimeoutDuration(4000);
@@ -964,7 +1159,7 @@ void RemoteProxyOfflineTests::authenticationReplyTimeout()
// Configure result (authentication takes longer than json rpc timeout
m_mockAuthenticator->setExpectedAuthenticationError();
- m_mockAuthenticator->setTimeoutDuration(1000);
+ m_mockAuthenticator->setTimeoutDuration(2000);
m_configuration->setAuthenticationTimeout(500);
m_configuration->setJsonRpcTimeout(1000);
@@ -1017,4 +1212,98 @@ void RemoteProxyOfflineTests::authenticationReplyConnection()
stopServer();
}
+//void RemoteProxyOfflineTests::tcpRemoteConnection()
+//{
+// // Start the server
+// startServer();
+
+// // Configure mock authenticator
+// m_mockAuthenticator->setTimeoutDuration(100);
+// m_mockAuthenticator->setExpectedAuthenticationError();
+
+// QString nameConnectionOne = "Test client one";
+// QUuid uuidConnectionOne = QUuid::createUuid();
+
+// QString nameConnectionTwo = "Test client two";
+// QUuid uuidConnectionTwo = QUuid::createUuid();
+
+// QByteArray dataOne = "Hello from client one :-)";
+// QByteArray dataTwo = "Hello from client two :-)";
+
+// // Create two connection
+// RemoteProxyConnection *connectionOne = new RemoteProxyConnection(uuidConnectionOne, nameConnectionOne, RemoteProxyConnection::ConnectionTypeTcpSocket, this);
+// connect(connectionOne, &RemoteProxyConnection::sslErrors, this, &BaseTest::ignoreConnectionSslError);
+
+// RemoteProxyConnection *connectionTwo = new RemoteProxyConnection(uuidConnectionTwo, nameConnectionTwo, RemoteProxyConnection::ConnectionTypeTcpSocket, this);
+// connect(connectionTwo, &RemoteProxyConnection::sslErrors, this, &BaseTest::ignoreConnectionSslError);
+
+// // Connect one
+// QSignalSpy connectionOneReadySpy(connectionOne, &RemoteProxyConnection::ready);
+// QVERIFY(connectionOne->connectServer(m_serverUrlTcp));
+// connectionOneReadySpy.wait();
+// QVERIFY(connectionOneReadySpy.count() == 1);
+// QVERIFY(connectionOne->isConnected());
+
+// // Connect two
+// QSignalSpy connectionTwoReadySpy(connectionTwo, &RemoteProxyConnection::ready);
+// QVERIFY(connectionTwo->connectServer(m_serverUrlTcp));
+// connectionTwoReadySpy.wait();
+// QVERIFY(connectionTwoReadySpy.count() == 1);
+// QVERIFY(connectionTwo->isConnected());
+
+// // Authenticate one
+// QSignalSpy remoteConnectionEstablishedOne(connectionOne, &RemoteProxyConnection::remoteConnectionEstablished);
+// QSignalSpy connectionOneAuthenticatedSpy(connectionOne, &RemoteProxyConnection::authenticated);
+// QVERIFY(connectionOne->authenticate(m_testToken));
+// connectionOneAuthenticatedSpy.wait();
+// QVERIFY(connectionOneAuthenticatedSpy.count() == 1);
+// QVERIFY(connectionOne->isConnected());
+// QVERIFY(connectionOne->isAuthenticated());
+// QVERIFY(connectionOne->state() == RemoteProxyConnection::StateAuthenticated);
+
+// // Authenticate two
+// QSignalSpy remoteConnectionEstablishedTwo(connectionTwo, &RemoteProxyConnection::remoteConnectionEstablished);
+// QSignalSpy connectionTwoAuthenticatedSpy(connectionTwo, &RemoteProxyConnection::authenticated);
+// QVERIFY(connectionTwo->authenticate(m_testToken));
+// connectionTwoAuthenticatedSpy.wait();
+// qDebug() << connectionTwoAuthenticatedSpy.count();
+// QVERIFY(connectionTwoAuthenticatedSpy.count() == 1);
+// QVERIFY(connectionTwo->isConnected());
+// QVERIFY(connectionTwo->isAuthenticated());
+
+// // Wait for both to be connected
+// remoteConnectionEstablishedOne.wait(500);
+// remoteConnectionEstablishedTwo.wait(500);
+
+// QVERIFY(remoteConnectionEstablishedOne.count() == 1);
+// QVERIFY(remoteConnectionEstablishedTwo.count() == 1);
+// QVERIFY(connectionOne->state() == RemoteProxyConnection::StateRemoteConnected);
+// QVERIFY(connectionTwo->state() == RemoteProxyConnection::StateRemoteConnected);
+
+// QCOMPARE(connectionOne->tunnelPartnerName(), nameConnectionTwo);
+// QCOMPARE(connectionOne->tunnelPartnerUuid(), uuidConnectionTwo.toString());
+// QCOMPARE(connectionTwo->tunnelPartnerName(), nameConnectionOne);
+// QCOMPARE(connectionTwo->tunnelPartnerUuid(), uuidConnectionOne.toString());
+
+// // Pipe data trought the tunnel
+// QSignalSpy remoteConnectionDataOne(connectionOne, &RemoteProxyConnection::dataReady);
+// QSignalSpy remoteConnectionDataTwo(connectionTwo, &RemoteProxyConnection::dataReady);
+
+// connectionOne->sendData(dataOne);
+// remoteConnectionDataTwo.wait(500);
+// QVERIFY(remoteConnectionDataTwo.count() == 1);
+// QCOMPARE(remoteConnectionDataTwo.at(0).at(0).toByteArray().trimmed(), dataOne);
+
+// connectionTwo->sendData(dataTwo);
+// remoteConnectionDataOne.wait(500);
+// QVERIFY(remoteConnectionDataOne.count() == 1);
+// QCOMPARE(remoteConnectionDataOne.at(0).at(0).toByteArray().trimmed(), dataTwo);
+
+// connectionOne->deleteLater();
+// connectionTwo->deleteLater();
+
+// // Clean up
+// stopServer();
+//}
+
QTEST_MAIN(RemoteProxyOfflineTests)
diff --git a/tests/test-offline/nymea-remoteproxy-tests-offline.h b/tests/test-offline/nymea-remoteproxy-tests-offline.h
index af62b3c..e7fe61e 100644
--- a/tests/test-offline/nymea-remoteproxy-tests-offline.h
+++ b/tests/test-offline/nymea-remoteproxy-tests-offline.h
@@ -54,10 +54,7 @@ private slots:
void websocketBinaryData();
void websocketPing();
- // TCP socket connection
-
-
- // Api
+ // WebSocket connection API
void getIntrospect();
void getHello();
@@ -71,20 +68,21 @@ private slots:
void authenticateSendData();
// Client lib
- void clientConnection();
+ void clientConnectionTcpSocket();
+ void clientConnectionWebSocket();
void remoteConnection();
void multipleRemoteConnection();
void trippleConnection();
void duplicateUuid();
void sslConfigurations();
- void jsonRpcTimeout();
void inactiveTimeout();
+ void jsonRpcTimeout();
void authenticationReplyTimeout();
void authenticationReplyConnection();
// TCP Websocket combinations
-
+ //void tcpRemoteConnection();
};
diff --git a/tests/testbase/basetest.cpp b/tests/testbase/basetest.cpp
index 6b398cd..62d54eb 100644
--- a/tests/testbase/basetest.cpp
+++ b/tests/testbase/basetest.cpp
@@ -31,8 +31,10 @@
#include "loggingcategories.h"
#include "remoteproxyconnection.h"
+#include
#include
#include
+#include
#include
#include
#include
@@ -47,16 +49,34 @@ void BaseTest::loadConfiguration(const QString &fileName)
{
qDebug() << "Load test configurations" << fileName;
m_configuration->loadConfiguration(fileName);
- restartEngine();
+ //restartEngine();
}
void BaseTest::cleanUpEngine()
{
+ qDebug() << "Clean up engine";
if (Engine::exists()) {
Engine::instance()->stop();
Engine::instance()->destroy();
QVERIFY(!Engine::exists());
}
+
+ if (m_mockAuthenticator) {
+ delete m_mockAuthenticator;
+ m_mockAuthenticator = nullptr;
+ }
+
+ if (m_dummyAuthenticator) {
+ delete m_dummyAuthenticator;
+ m_dummyAuthenticator = nullptr;
+ }
+
+ m_authenticator = nullptr;
+
+ if (m_configuration) {
+ delete m_configuration;
+ m_configuration = nullptr;
+ }
}
void BaseTest::restartEngine()
@@ -67,22 +87,29 @@ void BaseTest::restartEngine()
void BaseTest::startEngine()
{
+ m_configuration = new ProxyConfiguration(this);
+ loadConfiguration(":/test-configuration.conf");
+
+ m_dummyAuthenticator = new DummyAuthenticator(this);
+ m_mockAuthenticator = new MockAuthenticator(this);
+ m_authenticator = qobject_cast(m_mockAuthenticator);
if (!Engine::exists()) {
Engine::instance()->setAuthenticator(m_authenticator);
Engine::instance()->setDeveloperModeEnabled(true);
QVERIFY(Engine::exists());
+ QVERIFY(!Engine::instance()->running());
}
}
void BaseTest::startServer()
{
- startEngine();
+ restartEngine();
if (!Engine::instance()->running()) {
QSignalSpy runningSpy(Engine::instance(), &Engine::runningChanged);
Engine::instance()->setDeveloperModeEnabled(true);
Engine::instance()->start(m_configuration);
- runningSpy.wait(100);
+ runningSpy.wait(200);
QVERIFY(runningSpy.count() == 1);
}
@@ -100,6 +127,8 @@ void BaseTest::stopServer()
Engine::instance()->stop();
QVERIFY(!Engine::instance()->running());
+
+ cleanUpEngine();
}
QVariant BaseTest::invokeWebSocketApiCall(const QString &method, const QVariantMap params, bool remainsConnected)
@@ -310,20 +339,117 @@ bool BaseTest::createRemoteConnection(const QString &token, const QString &nonce
return true;
}
+void BaseTest::initTestCase()
+{
+ Q_UNUSED(remainsConnected)
+
+ QVariantMap request;
+ request.insert("id", m_commandCounter);
+ request.insert("method", method);
+ request.insert("params", params);
+ QJsonDocument jsonDoc = QJsonDocument::fromVariant(request);
+
+ QSslSocket *socket = new QSslSocket(this);
+ typedef void (QSslSocket:: *sslErrorsSignal)(const QList &);
+ QObject::connect(socket, static_cast(&QSslSocket::sslErrors), this, &BaseTest::sslSocketSslErrors);
+
+ QSignalSpy spyConnection(socket, &QSslSocket::connected);
+ socket->connectToHostEncrypted(Engine::instance()->tcpSocketServer()->serverUrl().host(),
+ static_cast(Engine::instance()->tcpSocketServer()->serverUrl().port()));
+ spyConnection.wait();
+ if (spyConnection.count() == 0) {
+ return QVariant();
+ }
+
+ QSignalSpy dataSpy(socket, &QSslSocket::readyRead);
+ socket->write(jsonDoc.toJson(QJsonDocument::Compact) + '\n');
+ // FIXME: check why it waits the full time here
+ dataSpy.wait(500);
+ if (dataSpy.count() != 1) {
+ qWarning() << "No data received";
+ return QVariant();
+ }
+
+ QByteArray data = socket->readAll();
+ socket->close();
+ socket->deleteLater();
+
+ // Make sure the response ends with '}\n'
+ if (!data.endsWith("}\n")) {
+ qWarning() << "JSON data does not end with \"}\n\"";
+ return QVariant();
+ }
+
+ // Make sure the response it a valid JSON string
+ QJsonParseError error;
+ jsonDoc = QJsonDocument::fromJson(data, &error);
+ if (error.error != QJsonParseError::NoError) {
+ qWarning() << "JSON parser error" << error.errorString();
+ return QVariant();
+ }
+
+ QVariantMap response = jsonDoc.toVariant().toMap();
+
+ if (response.value("id").toInt() == m_commandCounter) {
+ m_commandCounter++;
+ return jsonDoc.toVariant();
+ }
+
+ m_commandCounter++;
+ return QVariant();
+}
+
+QVariant BaseTest::injectTcpSocketData(const QByteArray &data)
+{
+ QSslSocket *socket = new QSslSocket(this);
+ typedef void (QSslSocket:: *sslErrorsSignal)(const QList &);
+ QObject::connect(socket, static_cast(&QSslSocket::sslErrors), this, &BaseTest::sslSocketSslErrors);
+
+ QSignalSpy spyConnection(socket, &QSslSocket::connected);
+ socket->connectToHostEncrypted(Engine::instance()->tcpSocketServer()->serverUrl().host(),
+ static_cast(Engine::instance()->tcpSocketServer()->serverUrl().port()));
+ spyConnection.wait();
+ if (spyConnection.count() == 0) {
+ return QVariant();
+ }
+
+ QSignalSpy dataSpy(socket, &QSslSocket::readyRead);
+ socket->write(data + '\n');
+ dataSpy.wait();
+ // FIXME: check why it waits the full time here
+ dataSpy.wait(500);
+ if (dataSpy.count() != 1) {
+ qWarning() << "No data received";
+ return QVariant();
+ }
+
+ QByteArray socketData = socket->readAll();
+ socket->close();
+ socket->deleteLater();
+
+ // Make sure the response ends with '}\n'
+ if (!socketData.endsWith("}\n")) {
+ qWarning() << "JSON data does not end with \"}\n\"";
+ return QVariant();
+ }
+
+ // Make sure the response it a valid JSON string
+ QJsonParseError error;
+ QJsonDocument jsonDoc = QJsonDocument::fromJson(socketData, &error);
+ if (error.error != QJsonParseError::NoError) {
+ qWarning() << "JSON parser error" << error.errorString();
+ return QVariant();
+ }
+
+ m_commandCounter++;
+ return jsonDoc.toVariant();
+}
+
void BaseTest::initTestCase()
{
qRegisterMetaType();
qRegisterMetaType();
- m_configuration = new ProxyConfiguration(this);
- m_configuration->loadConfiguration(":/test-configuration.conf");
-
- m_mockAuthenticator = new MockAuthenticator(this);
- m_dummyAuthenticator = new DummyAuthenticator(this);
- //m_awsAuthenticator = new AwsAuthenticator(m_configuration->awsCredentialsUrl(), this);
-
- m_authenticator = qobject_cast(m_mockAuthenticator);
-
m_testToken = "eyJraWQiOiJXdnFFT3prVVh5VDlINzFyRUpoNWdxRnkxNFhnR2l3SFAzVEIzUFQ1V3ZrPSIsImFsZyI6IlJT"
"MjU2In0.eyJzdWIiOiJmZTJmZDNlNC1hMGJhLTQ1OTUtOWRiZS00ZDkxYjRiMjFlMzUiLCJhdWQiOiI4cmpoZ"
"mRsZjlqZjFzdW9rMmpjcmx0ZDZ2IiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImV2ZW50X2lkIjoiN2Y5NTRiNm"
@@ -337,20 +463,13 @@ void BaseTest::initTestCase()
"pQbj58v1vktaAEATdmKmlzmcix-HJK9wWHRSuv3TsNa8DGxvcPOoeTu8Vql7krZ-y7Zu-s2WsgeP4VxyT80VE"
"T_xh6pMkOhE6g";
- qCDebug(dcApplication()) << "Init test case.";
- restartEngine();
+ qCDebug(dcApplication()) << "Init test case done.";
+ //restartEngine();
}
void BaseTest::cleanupTestCase()
{
qCDebug(dcApplication()) << "Clean up test case.";
- delete m_configuration;
- delete m_mockAuthenticator;
- delete m_dummyAuthenticator;
- //delete m_awsAuthenticator;
-
- m_authenticator = nullptr;
-
cleanUpEngine();
}
diff --git a/tests/testbase/basetest.h b/tests/testbase/basetest.h
index 60c029c..a5f04ef 100644
--- a/tests/testbase/basetest.h
+++ b/tests/testbase/basetest.h
@@ -57,6 +57,7 @@ protected:
ProxyConfiguration *m_configuration = nullptr;
QUrl m_serverUrl = QUrl("wss://127.0.0.1:1212");
+ QUrl m_serverUrlTcp = QUrl("ssl://127.0.0.1:1213");
QSslConfiguration m_sslConfiguration;
@@ -88,8 +89,13 @@ protected slots:
void cleanupTestCase();
public slots:
+ inline void sslSocketSslErrors(const QList &) {
+ QSslSocket *socket = static_cast(sender());
+ socket->ignoreSslErrors();
+ }
+
inline void sslErrors(const QList &) {
- QWebSocket *socket = static_cast(sender());
+ QWebSocket *socket = static_cast(sender());
socket->ignoreSslErrors();
}
diff --git a/tests/testbase/mockauthenticator.cpp b/tests/testbase/mockauthenticator.cpp
index d699253..06731cf 100644
--- a/tests/testbase/mockauthenticator.cpp
+++ b/tests/testbase/mockauthenticator.cpp
@@ -55,8 +55,7 @@ void MockAuthenticator::replyFinished()
{
MockAuthenticationReply *reply = static_cast(sender());
- qCDebug(dcAuthentication()) << name() << "Authentication finished.";
-
+ qCDebug(dcAuthentication()) << name() << "Authentication finished" << reply << reply->authenticationReply();
setReplyError(reply->authenticationReply(), reply->error());
setReplyFinished(reply->authenticationReply());
reply->deleteLater();
@@ -64,7 +63,7 @@ void MockAuthenticator::replyFinished()
AuthenticationReply *MockAuthenticator::authenticate(ProxyClient *proxyClient)
{
- qCDebug(dcAuthentication()) << name() << "Start authentication for" << proxyClient << "using token" << proxyClient->token();
+ qCDebug(dcAuthentication()) << name() << "Start authentication for" << proxyClient << "using token" << proxyClient->token() << "Auth duration" << m_timeoutDuration << "[ms]";
AuthenticationReply *authenticationReply = createAuthenticationReply(proxyClient, proxyClient);
@@ -84,3 +83,8 @@ MockAuthenticationReply::MockAuthenticationReply(int timeout, Authenticator::Aut
QTimer::singleShot(timeout, this, &MockAuthenticationReply::finished);
}
+MockAuthenticationReply::~MockAuthenticationReply()
+{
+ qCCritical(dcAuthentication()) << "Destroy mock authentication reply";
+}
+
diff --git a/tests/testbase/mockauthenticator.h b/tests/testbase/mockauthenticator.h
index fe80b83..77bae35 100644
--- a/tests/testbase/mockauthenticator.h
+++ b/tests/testbase/mockauthenticator.h
@@ -40,6 +40,7 @@ class MockAuthenticationReply : public QObject
Q_OBJECT
public:
explicit MockAuthenticationReply(int timeout, Authenticator::AuthenticationError error, AuthenticationReply *authenticationReply, QObject *parent = nullptr);
+ ~MockAuthenticationReply();
AuthenticationReply *authenticationReply() const { return m_authenticationReply; }
Authenticator::AuthenticationError error() const { return m_error; }
@@ -66,7 +67,7 @@ public:
void setExpectedAuthenticationError(Authenticator::AuthenticationError error = AuthenticationErrorNoError);
private:
- int m_timeoutDuration = 1000;
+ int m_timeoutDuration = 500;
Authenticator::AuthenticationError m_expectedError;
private slots: