Fix tests and improve proxy client handling in authentication and json layer
This commit is contained in:
parent
8fff4c6685
commit
52ce0b5084
@ -6,7 +6,7 @@ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(pwd)/libnymea-remoteproxy:$(pwd)/libny
|
|||||||
# Build
|
# Build
|
||||||
qmake CONFIG+=coverage CONFIG+=ccache
|
qmake CONFIG+=coverage CONFIG+=ccache
|
||||||
make -j$(nproc)
|
make -j$(nproc)
|
||||||
#make check
|
#make test
|
||||||
make coverage-html
|
make coverage-html
|
||||||
|
|
||||||
# Clean build
|
# Clean build
|
||||||
|
|||||||
@ -26,23 +26,30 @@
|
|||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
#include "engine.h"
|
#include "engine.h"
|
||||||
|
#include "loggingcategories.h"
|
||||||
#include "authenticationreply.h"
|
#include "authenticationreply.h"
|
||||||
#include "authentication/authenticator.h"
|
#include "authentication/authenticator.h"
|
||||||
|
|
||||||
namespace remoteproxy {
|
namespace remoteproxy {
|
||||||
|
|
||||||
AuthenticationReply::AuthenticationReply(ProxyClient *proxyClient, QObject *parent) :
|
AuthenticationReply::AuthenticationReply(ProxyClient *proxyClient, QObject *parent) :
|
||||||
QObject(parent),
|
QObject(parent)
|
||||||
m_proxyClient(proxyClient)
|
|
||||||
{
|
{
|
||||||
|
m_proxyClient = proxyClient;
|
||||||
|
|
||||||
m_timer = new QTimer(this);
|
m_timer = new QTimer(this);
|
||||||
m_timer->setSingleShot(true);
|
m_timer->setSingleShot(true);
|
||||||
connect(m_timer, &QTimer::timeout, this, &AuthenticationReply::onTimeout);
|
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());
|
m_timer->start(Engine::instance()->configuration()->authenticationTimeout());
|
||||||
}
|
}
|
||||||
|
|
||||||
ProxyClient *AuthenticationReply::proxyClient() const
|
AuthenticationReply::~AuthenticationReply()
|
||||||
|
{
|
||||||
|
qCCritical(dcAuthentication()) << "Destroy authentication reply";
|
||||||
|
}
|
||||||
|
|
||||||
|
QPointer<ProxyClient> AuthenticationReply::proxyClient() const
|
||||||
{
|
{
|
||||||
return m_proxyClient;
|
return m_proxyClient;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,6 +31,7 @@
|
|||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QPointer>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <QElapsedTimer>
|
#include <QElapsedTimer>
|
||||||
|
|
||||||
@ -44,7 +45,7 @@ class AuthenticationReply : public QObject
|
|||||||
public:
|
public:
|
||||||
friend class Authenticator;
|
friend class Authenticator;
|
||||||
|
|
||||||
ProxyClient *proxyClient() const;
|
QPointer<ProxyClient> proxyClient() const;
|
||||||
|
|
||||||
bool isTimedOut() const;
|
bool isTimedOut() const;
|
||||||
bool isFinished() const;
|
bool isFinished() const;
|
||||||
@ -53,7 +54,9 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
explicit AuthenticationReply(ProxyClient *proxyClient, QObject *parent = nullptr);
|
explicit AuthenticationReply(ProxyClient *proxyClient, QObject *parent = nullptr);
|
||||||
ProxyClient *m_proxyClient = nullptr;
|
~AuthenticationReply();
|
||||||
|
|
||||||
|
QPointer<ProxyClient> m_proxyClient;
|
||||||
QTimer *m_timer = nullptr;
|
QTimer *m_timer = nullptr;
|
||||||
|
|
||||||
bool m_timedOut = false;
|
bool m_timedOut = false;
|
||||||
|
|||||||
@ -37,6 +37,11 @@ Authenticator::Authenticator(QObject *parent) :
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Authenticator::~Authenticator()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void Authenticator::setReplyError(AuthenticationReply *reply, Authenticator::AuthenticationError error)
|
void Authenticator::setReplyError(AuthenticationReply *reply, Authenticator::AuthenticationError error)
|
||||||
{
|
{
|
||||||
reply->setError(error);
|
reply->setError(error);
|
||||||
@ -52,9 +57,4 @@ AuthenticationReply *Authenticator::createAuthenticationReply(ProxyClient *proxy
|
|||||||
return new AuthenticationReply(proxyClient, parent);
|
return new AuthenticationReply(proxyClient, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
Authenticator::~Authenticator()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -89,7 +89,7 @@ void AuthenticationHandler::onAuthenticationFinished()
|
|||||||
AuthenticationReply *authenticationReply = static_cast<AuthenticationReply *>(sender());
|
AuthenticationReply *authenticationReply = static_cast<AuthenticationReply *>(sender());
|
||||||
authenticationReply->deleteLater();
|
authenticationReply->deleteLater();
|
||||||
|
|
||||||
qCDebug(dcJsonRpc()) << "Authentication response ready for" << authenticationReply->proxyClient() << authenticationReply->error();
|
qCDebug(dcJsonRpc()) << "Authentication reply finished";
|
||||||
JsonReply *jsonReply = m_runningAuthentications.take(authenticationReply);
|
JsonReply *jsonReply = m_runningAuthentications.take(authenticationReply);
|
||||||
|
|
||||||
if (authenticationReply->error() != Authenticator::AuthenticationErrorNoError) {
|
if (authenticationReply->error() != Authenticator::AuthenticationErrorNoError) {
|
||||||
@ -100,10 +100,12 @@ void AuthenticationHandler::onAuthenticationFinished()
|
|||||||
jsonReply->setSuccess(true);
|
jsonReply->setSuccess(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set client authenticated
|
// Set client authenticated if still there
|
||||||
authenticationReply->proxyClient()->setAuthenticated(authenticationReply->error() == Authenticator::AuthenticationErrorNoError);
|
if (!authenticationReply->proxyClient().isNull()) {
|
||||||
|
authenticationReply->proxyClient()->setAuthenticated(authenticationReply->error() == Authenticator::AuthenticationErrorNoError);
|
||||||
|
jsonReply->setData(errorToReply(authenticationReply->error()));
|
||||||
|
}
|
||||||
|
|
||||||
jsonReply->setData(errorToReply(authenticationReply->error()));
|
|
||||||
jsonReply->finished();
|
jsonReply->finished();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -188,7 +188,7 @@ void JsonRpcServer::asyncReplyFinished()
|
|||||||
qCDebug(dcJsonRpc()) << "Async reply finished" << reply->handler()->name() << reply->method() << reply->clientId().toString();
|
qCDebug(dcJsonRpc()) << "Async reply finished" << reply->handler()->name() << reply->method() << reply->clientId().toString();
|
||||||
|
|
||||||
if (!proxyClient) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,6 +210,7 @@ void JsonRpcServer::asyncReplyFinished()
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
qCWarning(dcJsonRpc()) << "The reply timeouted.";
|
||||||
sendErrorResponse(proxyClient, reply->commandId(), "Command timed out");
|
sendErrorResponse(proxyClient, reply->commandId(), "Command timed out");
|
||||||
// Disconnect this client since he requested something that created a timeout
|
// Disconnect this client since he requested something that created a timeout
|
||||||
proxyClient->killConnection("API call timeouted.");
|
proxyClient->killConnection("API call timeouted.");
|
||||||
@ -233,8 +234,14 @@ void JsonRpcServer::unregisterClient(ProxyClient *proxyClient)
|
|||||||
qCWarning(dcJsonRpc()) << "Client was not registered" << proxyClient;
|
qCWarning(dcJsonRpc()) << "Client was not registered" << proxyClient;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_clients.removeAll(proxyClient);
|
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)
|
void JsonRpcServer::processData(ProxyClient *proxyClient, const QByteArray &data)
|
||||||
@ -246,7 +253,6 @@ void JsonRpcServer::processData(ProxyClient *proxyClient, const QByteArray &data
|
|||||||
|
|
||||||
QJsonParseError error;
|
QJsonParseError error;
|
||||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error);
|
||||||
|
|
||||||
if(error.error != QJsonParseError::NoError) {
|
if(error.error != QJsonParseError::NoError) {
|
||||||
qCWarning(dcJsonRpc) << "Failed to parse JSON data" << data << ":" << error.errorString();
|
qCWarning(dcJsonRpc) << "Failed to parse JSON data" << data << ":" << error.errorString();
|
||||||
sendErrorResponse(proxyClient, -1, QString("Failed to parse JSON data: %1").arg(error.errorString()));
|
sendErrorResponse(proxyClient, -1, QString("Failed to parse JSON data: %1").arg(error.errorString()));
|
||||||
|
|||||||
@ -40,9 +40,10 @@ ProxyClient::ProxyClient(TransportInterface *interface, const QUuid &clientId, c
|
|||||||
{
|
{
|
||||||
m_creationTimeStamp = QDateTime::currentDateTime().toTime_t();
|
m_creationTimeStamp = QDateTime::currentDateTime().toTime_t();
|
||||||
|
|
||||||
connect(&m_timer, &QTimer::timeout, this, &ProxyClient::timeoutOccured);
|
m_timer = new QTimer(this);
|
||||||
m_timer.setSingleShot(true);
|
connect(m_timer, &QTimer::timeout, this, &ProxyClient::timeoutOccured);
|
||||||
m_timer.start(Engine::instance()->configuration()->inactiveTimeout());
|
m_timer->setSingleShot(true);
|
||||||
|
resetTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
QUuid ProxyClient::clientId() const
|
QUuid ProxyClient::clientId() const
|
||||||
@ -74,8 +75,8 @@ void ProxyClient::setAuthenticated(bool isAuthenticated)
|
|||||||
{
|
{
|
||||||
m_authenticated = isAuthenticated;
|
m_authenticated = isAuthenticated;
|
||||||
if (m_authenticated) {
|
if (m_authenticated) {
|
||||||
m_timer.stop();
|
m_timerWaitState = TimerWaitStateAlone;
|
||||||
m_timer.start(Engine::instance()->configuration()->aloneTimeout());
|
resetTimer();
|
||||||
emit authenticated();
|
emit authenticated();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -89,7 +90,7 @@ void ProxyClient::setTunnelConnected(bool isTunnelConnected)
|
|||||||
{
|
{
|
||||||
m_tunnelConnected = isTunnelConnected;
|
m_tunnelConnected = isTunnelConnected;
|
||||||
if (m_tunnelConnected) {
|
if (m_tunnelConnected) {
|
||||||
m_timer.stop();
|
m_timer->stop();
|
||||||
emit tunnelConnected();
|
emit tunnelConnected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,6 +175,25 @@ void ProxyClient::addTxDataCount(int dataCount)
|
|||||||
m_txDataCount += static_cast<quint64>(dataCount);
|
m_txDataCount += static_cast<quint64>(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)
|
void ProxyClient::sendData(const QByteArray &data)
|
||||||
{
|
{
|
||||||
if (!m_interface)
|
if (!m_interface)
|
||||||
@ -200,8 +220,8 @@ QDebug operator<<(QDebug debug, ProxyClient *proxyClient)
|
|||||||
debug.nospace() << ", " << proxyClient->clientId().toString();
|
debug.nospace() << ", " << proxyClient->clientId().toString();
|
||||||
debug.nospace() << ", " << proxyClient->userName();
|
debug.nospace() << ", " << proxyClient->userName();
|
||||||
debug.nospace() << ", " << proxyClient->peerAddress().toString();
|
debug.nospace() << ", " << proxyClient->peerAddress().toString();
|
||||||
debug.nospace() << ", " << proxyClient->creationTimeString() << ") ";
|
debug.nospace() << ", " << proxyClient->creationTimeString() << ")";
|
||||||
return debug;
|
return debug.space();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,6 +43,12 @@ class ProxyClient : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum TimerWaitState {
|
||||||
|
TimerWaitStateInactive,
|
||||||
|
TimerWaitStateAlone
|
||||||
|
};
|
||||||
|
Q_ENUM(TimerWaitState)
|
||||||
|
|
||||||
explicit ProxyClient(TransportInterface *interface, const QUuid &clientId, const QHostAddress &address, QObject *parent = nullptr);
|
explicit ProxyClient(TransportInterface *interface, const QUuid &clientId, const QHostAddress &address, QObject *parent = nullptr);
|
||||||
|
|
||||||
QUuid clientId() const;
|
QUuid clientId() const;
|
||||||
@ -84,12 +90,15 @@ public:
|
|||||||
void addTxDataCount(int dataCount);
|
void addTxDataCount(int dataCount);
|
||||||
|
|
||||||
// Actions for this client
|
// Actions for this client
|
||||||
|
TimerWaitState timerWaitState() const;
|
||||||
|
void resetTimer();
|
||||||
void sendData(const QByteArray &data);
|
void sendData(const QByteArray &data);
|
||||||
void killConnection(const QString &reason);
|
void killConnection(const QString &reason);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TransportInterface *m_interface = nullptr;
|
TransportInterface *m_interface = nullptr;
|
||||||
QTimer m_timer;
|
QTimer *m_timer = nullptr;
|
||||||
|
TimerWaitState m_timerWaitState = TimerWaitStateInactive;
|
||||||
|
|
||||||
QUuid m_clientId;
|
QUuid m_clientId;
|
||||||
QHostAddress m_peerAddress;
|
QHostAddress m_peerAddress;
|
||||||
|
|||||||
@ -274,6 +274,8 @@ void ProxyServer::onClientDataAvailable(const QUuid &clientId, const QByteArray
|
|||||||
if (!proxyClient->isAuthenticated() && !proxyClient->isTunnelConnected()) {
|
if (!proxyClient->isAuthenticated() && !proxyClient->isTunnelConnected()) {
|
||||||
qCDebug(dcProxyServerTraffic()) << "Client data available" << proxyClient << qUtf8Printable(data);
|
qCDebug(dcProxyServerTraffic()) << "Client data available" << proxyClient << qUtf8Printable(data);
|
||||||
m_jsonRpcServer->processData(proxyClient, data);
|
m_jsonRpcServer->processData(proxyClient, data);
|
||||||
|
// Reset the inactive timer
|
||||||
|
proxyClient->resetTimer();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,8 +375,15 @@ void ProxyServer::onProxyClientAuthenticated()
|
|||||||
void ProxyServer::onProxyClientTimeoutOccured()
|
void ProxyServer::onProxyClientTimeoutOccured()
|
||||||
{
|
{
|
||||||
ProxyClient *proxyClient = static_cast<ProxyClient *>(sender());
|
ProxyClient *proxyClient = static_cast<ProxyClient *>(sender());
|
||||||
qCDebug(dcProxyServer()) << "Timeout occured for" << proxyClient;
|
qCDebug(dcProxyServer()) << "Timeout occured for" << proxyClient;
|
||||||
proxyClient->killConnection("Proxy timeout occuret");
|
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()
|
void ProxyServer::startServer()
|
||||||
|
|||||||
@ -46,7 +46,10 @@ void TcpSocketServer::sendData(const QUuid &clientId, const QByteArray &data)
|
|||||||
return;
|
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)
|
void TcpSocketServer::killClientConnection(const QUuid &clientId, const QString &killReason)
|
||||||
@ -56,7 +59,7 @@ void TcpSocketServer::killClientConnection(const QUuid &clientId, const QString
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
qCWarning(dcTcpSocketServer()) << "Killing client connection" << clientId.toString() << "Reason:" << killReason;
|
qCWarning(dcTcpSocketServer()) << "Killing client connection" << clientId.toString() << "Reason:" << killReason;
|
||||||
client->abort();
|
client->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TcpSocketServer::running() const
|
bool TcpSocketServer::running() const
|
||||||
@ -69,7 +72,7 @@ bool TcpSocketServer::running() const
|
|||||||
|
|
||||||
void TcpSocketServer::onDataAvailable(QSslSocket *client, const QByteArray &data)
|
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<QTcpSocket *>(client));
|
QUuid clientId = m_clientList.key(qobject_cast<QTcpSocket *>(client));
|
||||||
emit dataAvailable(clientId, data);
|
emit dataAvailable(clientId, data);
|
||||||
}
|
}
|
||||||
@ -85,7 +88,7 @@ void TcpSocketServer::onClientConnected(QSslSocket *client)
|
|||||||
void TcpSocketServer::onClientDisconnected(QSslSocket *client)
|
void TcpSocketServer::onClientDisconnected(QSslSocket *client)
|
||||||
{
|
{
|
||||||
QUuid clientId = m_clientList.key(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);
|
m_clientList.take(clientId);
|
||||||
// Note: the SslServer is deleting the socket object
|
// Note: the SslServer is deleting the socket object
|
||||||
emit clientDisconnected(clientId);
|
emit clientDisconnected(clientId);
|
||||||
@ -138,12 +141,13 @@ SslServer::SslServer(bool sslEnabled, const QSslConfiguration &config, QObject *
|
|||||||
void SslServer::incomingConnection(qintptr socketDescriptor)
|
void SslServer::incomingConnection(qintptr socketDescriptor)
|
||||||
{
|
{
|
||||||
QSslSocket *sslSocket = new QSslSocket(this);
|
QSslSocket *sslSocket = new QSslSocket(this);
|
||||||
|
qCDebug(dcTcpSocketServer()) << "Incomming connection" << sslSocket;
|
||||||
qCDebug(dcTcpSocketServer()) << "New client connected:" << sslSocket << sslSocket->peerAddress().toString();
|
|
||||||
|
|
||||||
connect(sslSocket, &QSslSocket::encrypted, [this, sslSocket](){ emit clientConnected(sslSocket); });
|
|
||||||
connect(sslSocket, &QSslSocket::readyRead, this, &SslServer::onSocketReadyRead);
|
connect(sslSocket, &QSslSocket::readyRead, this, &SslServer::onSocketReadyRead);
|
||||||
connect(sslSocket, &QSslSocket::disconnected, this, &SslServer::onClientDisconnected);
|
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)) {
|
if (!sslSocket->setSocketDescriptor(socketDescriptor)) {
|
||||||
qCWarning(dcTcpSocketServer()) << "Failed to set SSL socket descriptor.";
|
qCWarning(dcTcpSocketServer()) << "Failed to set SSL socket descriptor.";
|
||||||
@ -153,6 +157,7 @@ void SslServer::incomingConnection(qintptr socketDescriptor)
|
|||||||
|
|
||||||
if (m_sslEnabled) {
|
if (m_sslEnabled) {
|
||||||
sslSocket->setSslConfiguration(m_config);
|
sslSocket->setSslConfiguration(m_config);
|
||||||
|
qCDebug(dcTcpSocketServer()) << "Start SSL encryption for" << sslSocket;
|
||||||
sslSocket->startServerEncryption();
|
sslSocket->startServerEncryption();
|
||||||
} else {
|
} else {
|
||||||
emit clientConnected(sslSocket);
|
emit clientConnected(sslSocket);
|
||||||
|
|||||||
@ -78,8 +78,6 @@ void WebSocketServer::killClientConnection(const QUuid &clientId, const QString
|
|||||||
|
|
||||||
qCWarning(dcWebSocketServer()) << "Killing client connection" << clientId.toString() << "Reason:" << killReason;
|
qCWarning(dcWebSocketServer()) << "Killing client connection" << clientId.toString() << "Reason:" << killReason;
|
||||||
client->close(QWebSocketProtocol::CloseCodeBadOperation, killReason);
|
client->close(QWebSocketProtocol::CloseCodeBadOperation, killReason);
|
||||||
client->flush();
|
|
||||||
client->abort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebSocketServer::onClientConnected()
|
void WebSocketServer::onClientConnected()
|
||||||
@ -95,9 +93,7 @@ void WebSocketServer::onClientConnected()
|
|||||||
if (client->version() != QWebSocketProtocol::Version13) {
|
if (client->version() != QWebSocketProtocol::Version13) {
|
||||||
qCWarning(dcWebSocketServer()) << "Client with invalid protocol version" << client->version() << ". Rejecting.";
|
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->close(QWebSocketProtocol::CloseCodeProtocolError, QString("invalid protocol version: %1 != Supported Version 13").arg(client->version()));
|
||||||
client->flush();
|
client->deleteLater();
|
||||||
client->abort();
|
|
||||||
delete client;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,8 +121,6 @@ void WebSocketServer::onClientDisconnected()
|
|||||||
|
|
||||||
// Manually close it in any case
|
// Manually close it in any case
|
||||||
client->close();
|
client->close();
|
||||||
client->flush();
|
|
||||||
client->abort();
|
|
||||||
|
|
||||||
m_clientList.take(clientId)->deleteLater();
|
m_clientList.take(clientId)->deleteLater();
|
||||||
emit clientDisconnected(clientId);
|
emit clientDisconnected(clientId);
|
||||||
@ -145,8 +139,6 @@ void WebSocketServer::onBinaryMessageReceived(const QByteArray &data)
|
|||||||
qCWarning(dcWebSocketServerTraffic()) << "<-- Binary message from" << client->peerAddress().toString() << ":" << data;
|
qCWarning(dcWebSocketServerTraffic()) << "<-- Binary message from" << client->peerAddress().toString() << ":" << data;
|
||||||
// Note: this is not expected, so close this client connection.
|
// Note: this is not expected, so close this client connection.
|
||||||
client->close(QWebSocketProtocol::CloseCodeBadOperation, "Binary message not expected.");
|
client->close(QWebSocketProtocol::CloseCodeBadOperation, "Binary message not expected.");
|
||||||
client->flush();
|
|
||||||
client->abort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebSocketServer::onClientError(QAbstractSocket::SocketError error)
|
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
|
// Note: on any error which can occure, make sure the socket will be closed in any case
|
||||||
client->close();
|
client->close();
|
||||||
client->flush();
|
|
||||||
client->abort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebSocketServer::onAcceptError(QAbstractSocket::SocketError error)
|
void WebSocketServer::onAcceptError(QAbstractSocket::SocketError error)
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
INCLUDEPATH += $${PWD}
|
INCLUDEPATH += $${PWD}
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
$$PWD/tcpsocketconnection.h \
|
$${PWD}/tcpsocketconnection.h \
|
||||||
$${PWD}/proxyjsonrpcclient.h \
|
$${PWD}/proxyjsonrpcclient.h \
|
||||||
$${PWD}/jsonreply.h \
|
$${PWD}/jsonreply.h \
|
||||||
$${PWD}/remoteproxyconnection.h \
|
$${PWD}/remoteproxyconnection.h \
|
||||||
@ -9,7 +9,7 @@ HEADERS += \
|
|||||||
$${PWD}/websocketconnection.h
|
$${PWD}/websocketconnection.h
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
$$PWD/tcpsocketconnection.cpp \
|
$${PWD}/tcpsocketconnection.cpp \
|
||||||
$${PWD}/proxyjsonrpcclient.cpp \
|
$${PWD}/proxyjsonrpcclient.cpp \
|
||||||
$${PWD}/jsonreply.cpp \
|
$${PWD}/jsonreply.cpp \
|
||||||
$${PWD}/remoteproxyconnection.cpp \
|
$${PWD}/remoteproxyconnection.cpp \
|
||||||
|
|||||||
@ -319,23 +319,18 @@ void RemoteProxyConnection::onTunnelEstablished(const QString &clientName, const
|
|||||||
|
|
||||||
bool RemoteProxyConnection::connectServer(const QUrl &url)
|
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_serverUrl = url;
|
||||||
m_connectionType = ConnectionTypeWebSocket;
|
|
||||||
m_error = QAbstractSocket::UnknownSocketError;
|
m_error = QAbstractSocket::UnknownSocketError;
|
||||||
|
|
||||||
cleanUp();
|
cleanUp();
|
||||||
|
|
||||||
switch (m_connectionType) {
|
switch (m_connectionType) {
|
||||||
case ConnectionTypeWebSocket:
|
case ConnectionTypeWebSocket:
|
||||||
|
qCDebug(dcRemoteProxyClientConnection()) << "Creating a web socket connection to" << url.toString();
|
||||||
m_connection = qobject_cast<ProxyConnection *>(new WebSocketConnection(this));
|
m_connection = qobject_cast<ProxyConnection *>(new WebSocketConnection(this));
|
||||||
break;
|
break;
|
||||||
case ConnectionTypeTcpSocket:
|
case ConnectionTypeTcpSocket:
|
||||||
|
qCDebug(dcRemoteProxyClientConnection()) << "Creating a TCP socket connection to" << url.toString();
|
||||||
m_connection = qobject_cast<ProxyConnection *>(new TcpSocketConnection(this));
|
m_connection = qobject_cast<ProxyConnection *>(new TcpSocketConnection(this));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,6 +31,7 @@ TcpSocketConnection::TcpSocketConnection(QObject *parent) :
|
|||||||
|
|
||||||
connect(m_tcpSocket, &QSslSocket::disconnected, this, &TcpSocketConnection::onDisconnected);
|
connect(m_tcpSocket, &QSslSocket::disconnected, this, &TcpSocketConnection::onDisconnected);
|
||||||
connect(m_tcpSocket, &QSslSocket::encrypted, this, &TcpSocketConnection::onEncrypted);
|
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(error(QAbstractSocket::SocketError)), this, SLOT(onError(QAbstractSocket::SocketError)));
|
||||||
connect(m_tcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onStateChanged(QAbstractSocket::SocketState)));
|
connect(m_tcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onStateChanged(QAbstractSocket::SocketState)));
|
||||||
connect(m_tcpSocket, SIGNAL(sslErrors(QList<QSslError>)), this, SIGNAL(sslErrors(QList<QSslError>)));
|
connect(m_tcpSocket, SIGNAL(sslErrors(QList<QSslError>)), this, SIGNAL(sslErrors(QList<QSslError>)));
|
||||||
@ -65,6 +66,7 @@ void TcpSocketConnection::onDisconnected()
|
|||||||
void TcpSocketConnection::onEncrypted()
|
void TcpSocketConnection::onEncrypted()
|
||||||
{
|
{
|
||||||
qCDebug(dcRemoteProxyClientTcpSocket()) << "Connection encrypted";
|
qCDebug(dcRemoteProxyClientTcpSocket()) << "Connection encrypted";
|
||||||
|
setConnected(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TcpSocketConnection::onError(QAbstractSocket::SocketError error)
|
void TcpSocketConnection::onError(QAbstractSocket::SocketError error)
|
||||||
@ -80,7 +82,9 @@ void TcpSocketConnection::onStateChanged(QAbstractSocket::SocketState state)
|
|||||||
switch (state) {
|
switch (state) {
|
||||||
case QAbstractSocket::ConnectedState:
|
case QAbstractSocket::ConnectedState:
|
||||||
qCDebug(dcRemoteProxyClientTcpSocket()) << "Connected with" << serverUrl().toString();
|
qCDebug(dcRemoteProxyClientTcpSocket()) << "Connected with" << serverUrl().toString();
|
||||||
setConnected(true);
|
if (!m_ssl) {
|
||||||
|
setConnected(true);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
setConnected(false);
|
setConnected(false);
|
||||||
@ -97,12 +101,13 @@ void TcpSocketConnection::onReadyRead()
|
|||||||
|
|
||||||
void TcpSocketConnection::connectServer(const QUrl &serverUrl)
|
void TcpSocketConnection::connectServer(const QUrl &serverUrl)
|
||||||
{
|
{
|
||||||
qCDebug(dcRemoteProxyClientTcpSocket()) << "Connecting to" << this->serverUrl().toString();
|
|
||||||
setServerUrl(serverUrl);
|
setServerUrl(serverUrl);
|
||||||
|
qCDebug(dcRemoteProxyClientTcpSocket()) << "Connecting to" << this->serverUrl().toString();
|
||||||
|
|
||||||
if (serverUrl.scheme() == "tcp") {
|
if (serverUrl.scheme() == "tcp") {
|
||||||
m_tcpSocket->connectToHost(QHostAddress(this->serverUrl().host()), static_cast<quint16>(this->serverUrl().port()));
|
m_tcpSocket->connectToHost(QHostAddress(this->serverUrl().host()), static_cast<quint16>(this->serverUrl().port()));
|
||||||
} else {
|
} else {
|
||||||
|
m_ssl = true;
|
||||||
m_tcpSocket->connectToHostEncrypted(this->serverUrl().host(), static_cast<quint16>(this->serverUrl().port()));
|
m_tcpSocket->connectToHostEncrypted(this->serverUrl().host(), static_cast<quint16>(this->serverUrl().port()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,6 +48,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QSslSocket *m_tcpSocket = nullptr;
|
QSslSocket *m_tcpSocket = nullptr;
|
||||||
|
bool m_ssl = false;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onDisconnected();
|
void onDisconnected();
|
||||||
|
|||||||
@ -23,7 +23,7 @@ ccache {
|
|||||||
QMAKE_CXX = ccache g++
|
QMAKE_CXX = ccache g++
|
||||||
}
|
}
|
||||||
|
|
||||||
coverage {<
|
coverage {
|
||||||
# Note: this works only if you build in the source dir
|
# Note: this works only if you build in the source dir
|
||||||
OBJECTS_DIR =
|
OBJECTS_DIR =
|
||||||
MOC_DIR =
|
MOC_DIR =
|
||||||
|
|||||||
@ -15,7 +15,9 @@ server.depends = libnymea-remoteproxy
|
|||||||
client.depends = libnymea-remoteproxyclient
|
client.depends = libnymea-remoteproxyclient
|
||||||
tests.depends = libnymea-remoteproxy 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
|
QMAKE_EXTRA_TARGETS += test
|
||||||
|
|
||||||
message("----------------------------------------------------------")
|
message("----------------------------------------------------------")
|
||||||
|
|||||||
@ -3,10 +3,10 @@ name=test-nymea-remoteproxy
|
|||||||
writeLogs=false
|
writeLogs=false
|
||||||
logFile=/var/log/nymea-remoteproxy.log
|
logFile=/var/log/nymea-remoteproxy.log
|
||||||
monitorSocket=/tmp/nymea-remoteproxy-test.sock
|
monitorSocket=/tmp/nymea-remoteproxy-test.sock
|
||||||
jsonRpcTimeout=1000
|
jsonRpcTimeout=2000
|
||||||
authenticationTimeout=1500
|
authenticationTimeout=1000
|
||||||
inactiveTimeout=1500
|
inactiveTimeout=1500
|
||||||
aloneTimeout=1000
|
aloneTimeout=1500
|
||||||
|
|
||||||
[SSL]
|
[SSL]
|
||||||
certificate=:/test-certificate.crt
|
certificate=:/test-certificate.crt
|
||||||
|
|||||||
@ -53,9 +53,14 @@ void RemoteProxyOfflineTests::dummyAuthenticator()
|
|||||||
{
|
{
|
||||||
cleanUpEngine();
|
cleanUpEngine();
|
||||||
|
|
||||||
|
m_configuration = new ProxyConfiguration(this);
|
||||||
|
loadConfiguration(":/test-configuration.conf");
|
||||||
|
|
||||||
|
m_dummyAuthenticator = new DummyAuthenticator(this);
|
||||||
|
m_authenticator = qobject_cast<Authenticator *>(m_dummyAuthenticator);
|
||||||
|
|
||||||
// Start proxy webserver
|
// Start proxy webserver
|
||||||
Engine::instance()->setAuthenticator(m_dummyAuthenticator);
|
Engine::instance()->setAuthenticator(m_dummyAuthenticator);
|
||||||
Engine::instance()->setAuthenticator(m_dummyAuthenticator);
|
|
||||||
QSignalSpy runningSpy(Engine::instance(), &Engine::runningChanged);
|
QSignalSpy runningSpy(Engine::instance(), &Engine::runningChanged);
|
||||||
Engine::instance()->start(m_configuration);
|
Engine::instance()->start(m_configuration);
|
||||||
runningSpy.wait();
|
runningSpy.wait();
|
||||||
@ -209,16 +214,21 @@ void RemoteProxyOfflineTests::serverPortBlocked()
|
|||||||
{
|
{
|
||||||
cleanUpEngine();
|
cleanUpEngine();
|
||||||
|
|
||||||
|
m_configuration = new ProxyConfiguration(this);
|
||||||
|
loadConfiguration(":/test-configuration.conf");
|
||||||
|
|
||||||
|
m_mockAuthenticator = new MockAuthenticator(this);
|
||||||
|
m_authenticator = qobject_cast<Authenticator *>(m_mockAuthenticator);
|
||||||
|
|
||||||
// Create a dummy server which blocks the port
|
// Create a dummy server which blocks the port
|
||||||
QWebSocketServer dummyServer("dummy-server", QWebSocketServer::NonSecureMode);
|
QWebSocketServer dummyServer("dummy-server", QWebSocketServer::NonSecureMode);
|
||||||
dummyServer.listen(QHostAddress::LocalHost, 1212);
|
QVERIFY(dummyServer.listen(QHostAddress::LocalHost, m_configuration->webSocketServerPort()));
|
||||||
|
|
||||||
// Start proxy webserver
|
// Start proxy webserver
|
||||||
QSignalSpy runningSpy(Engine::instance(), &Engine::runningChanged);
|
QSignalSpy runningSpy(Engine::instance(), &Engine::runningChanged);
|
||||||
Engine::instance()->setAuthenticator(m_authenticator);
|
Engine::instance()->setAuthenticator(m_authenticator);
|
||||||
Engine::instance()->start(m_configuration);
|
Engine::instance()->start(m_configuration);
|
||||||
runningSpy.wait();
|
runningSpy.wait();
|
||||||
qDebug() << runningSpy.count();
|
|
||||||
QVERIFY(runningSpy.count() == 1);
|
QVERIFY(runningSpy.count() == 1);
|
||||||
|
|
||||||
// Make sure the server is not running
|
// Make sure the server is not running
|
||||||
@ -233,11 +243,49 @@ void RemoteProxyOfflineTests::serverPortBlocked()
|
|||||||
QVERIFY(closedSpy.count() == 1);
|
QVERIFY(closedSpy.count() == 1);
|
||||||
|
|
||||||
// Try again
|
// Try again
|
||||||
cleanUpEngine();
|
|
||||||
startServer();
|
startServer();
|
||||||
|
|
||||||
// Clean up
|
// Clean up
|
||||||
stopServer();
|
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<Authenticator *>(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()
|
void RemoteProxyOfflineTests::websocketBinaryData()
|
||||||
@ -286,13 +334,70 @@ void RemoteProxyOfflineTests::websocketPing()
|
|||||||
stopServer();
|
stopServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//void RemoteProxyOfflineTests::apiBasicCallsTcp_data()
|
||||||
|
//{
|
||||||
|
// QTest::addColumn<QByteArray>("data");
|
||||||
|
// QTest::addColumn<int>("responseId");
|
||||||
|
// QTest::addColumn<QString>("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()
|
void RemoteProxyOfflineTests::getIntrospect()
|
||||||
{
|
{
|
||||||
// Start the server
|
// Start the server
|
||||||
startServer();
|
startServer();
|
||||||
|
|
||||||
QVariant response = invokeWebSocketApiCall("RemoteProxy.Introspect");
|
QVariantMap response;
|
||||||
qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
|
|
||||||
|
// 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
|
// Clean up
|
||||||
stopServer();
|
stopServer();
|
||||||
@ -302,16 +407,32 @@ void RemoteProxyOfflineTests::getHello()
|
|||||||
{
|
{
|
||||||
// Start the server
|
// Start the server
|
||||||
startServer();
|
startServer();
|
||||||
|
QVariantMap response;
|
||||||
|
|
||||||
QVariantMap response = invokeWebSocketApiCall("RemoteProxy.Hello").toMap();
|
// WebSocket
|
||||||
qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
|
response = invokeWebSocketApiCall("RemoteProxy.Hello").toMap();
|
||||||
|
//qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
|
||||||
|
|
||||||
// Verify data
|
// Verify data
|
||||||
|
QVERIFY(!response.isEmpty());
|
||||||
QCOMPARE(response.value("params").toMap().value("name").toString(), Engine::instance()->configuration()->serverName());
|
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("server").toString(), QString(SERVER_NAME_STRING));
|
||||||
QCOMPARE(response.value("params").toMap().value("version").toString(), QString(SERVER_VERSION_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));
|
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
|
// Clean up
|
||||||
stopServer();
|
stopServer();
|
||||||
}
|
}
|
||||||
@ -342,11 +463,22 @@ void RemoteProxyOfflineTests::apiBasicCalls()
|
|||||||
// Start the server
|
// Start the server
|
||||||
startServer();
|
startServer();
|
||||||
|
|
||||||
QVariant response = injectWebSocketData(data);
|
QVariantMap response;
|
||||||
qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
|
|
||||||
|
|
||||||
QCOMPARE(response.toMap().value("id").toInt(), responseId);
|
// Websocket
|
||||||
QCOMPARE(response.toMap().value("status").toString(), responseStatus);
|
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
|
// Clean up
|
||||||
stopServer();
|
stopServer();
|
||||||
@ -409,8 +541,14 @@ void RemoteProxyOfflineTests::authenticate()
|
|||||||
params.insert("token", token);
|
params.insert("token", token);
|
||||||
if (!nonce.isEmpty()) params.insert("nonce", nonce);
|
if (!nonce.isEmpty()) params.insert("nonce", nonce);
|
||||||
|
|
||||||
QVariant response = invokeWebSocketApiCall("Authentication.Authenticate", params);
|
// WebSocket
|
||||||
qDebug() << qUtf8Printable(QJsonDocument::fromVariant(response).toJson(QJsonDocument::Indented));
|
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);
|
verifyAuthenticationError(response, expectedError);
|
||||||
|
|
||||||
// Clean up
|
// Clean up
|
||||||
@ -518,6 +656,9 @@ void RemoteProxyOfflineTests::authenticateSendData()
|
|||||||
// Start the server
|
// Start the server
|
||||||
startServer();
|
startServer();
|
||||||
|
|
||||||
|
m_mockAuthenticator->setTimeoutDuration(100);
|
||||||
|
m_mockAuthenticator->setExpectedAuthenticationError();
|
||||||
|
|
||||||
QVariantMap params;
|
QVariantMap params;
|
||||||
params.insert("uuid", "uuid");
|
params.insert("uuid", "uuid");
|
||||||
params.insert("name", "name");
|
params.insert("name", "name");
|
||||||
@ -533,18 +674,18 @@ void RemoteProxyOfflineTests::authenticateSendData()
|
|||||||
// Connect socket
|
// Connect socket
|
||||||
QWebSocket *socket = new QWebSocket("proxy-testclient", QWebSocketProtocol::Version13);
|
QWebSocket *socket = new QWebSocket("proxy-testclient", QWebSocketProtocol::Version13);
|
||||||
connect(socket, &QWebSocket::sslErrors, this, &BaseTest::sslErrors);
|
connect(socket, &QWebSocket::sslErrors, this, &BaseTest::sslErrors);
|
||||||
QSignalSpy spyConnection(socket, SIGNAL(connected()));
|
QSignalSpy spyConnection(socket, &QWebSocket::connected);
|
||||||
socket->open(Engine::instance()->webSocketServer()->serverUrl());
|
socket->open(Engine::instance()->webSocketServer()->serverUrl());
|
||||||
spyConnection.wait();
|
spyConnection.wait();
|
||||||
QVERIFY(spyConnection.count() == 1);
|
QVERIFY(spyConnection.count() == 1);
|
||||||
|
|
||||||
// Authenticate
|
// Authenticate
|
||||||
QSignalSpy dataSpy(socket, SIGNAL(textMessageReceived(QString)));
|
QSignalSpy dataSpy(socket, &QWebSocket::textMessageReceived);
|
||||||
socket->sendTextMessage(QString(jsonDoc.toJson(QJsonDocument::Compact)));
|
socket->sendTextMessage(QString(jsonDoc.toJson(QJsonDocument::Compact)));
|
||||||
dataSpy.wait();
|
dataSpy.wait();
|
||||||
QVERIFY(dataSpy.count() == 1);
|
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()));
|
QSignalSpy disconnectedSpy(socket, SIGNAL(disconnected()));
|
||||||
socket->sendTextMessage(QString(jsonDoc.toJson(QJsonDocument::Compact)));
|
socket->sendTextMessage(QString(jsonDoc.toJson(QJsonDocument::Compact)));
|
||||||
disconnectedSpy.wait();
|
disconnectedSpy.wait();
|
||||||
@ -556,7 +697,7 @@ void RemoteProxyOfflineTests::authenticateSendData()
|
|||||||
stopServer();
|
stopServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteProxyOfflineTests::clientConnection()
|
void RemoteProxyOfflineTests::clientConnectionWebSocket()
|
||||||
{
|
{
|
||||||
// Start the server
|
// Start the server
|
||||||
startServer();
|
startServer();
|
||||||
@ -565,7 +706,7 @@ void RemoteProxyOfflineTests::clientConnection()
|
|||||||
m_mockAuthenticator->setTimeoutDuration(100);
|
m_mockAuthenticator->setTimeoutDuration(100);
|
||||||
m_mockAuthenticator->setExpectedAuthenticationError();
|
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);
|
RemoteProxyConnection *connection = new RemoteProxyConnection(QUuid::createUuid(), "Test client one", this);
|
||||||
connect(connection, &RemoteProxyConnection::sslErrors, this, &BaseTest::ignoreConnectionSslError);
|
connect(connection, &RemoteProxyConnection::sslErrors, this, &BaseTest::ignoreConnectionSslError);
|
||||||
|
|
||||||
@ -606,6 +747,56 @@ void RemoteProxyOfflineTests::clientConnection()
|
|||||||
stopServer();
|
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()
|
void RemoteProxyOfflineTests::remoteConnection()
|
||||||
{
|
{
|
||||||
// Start the server
|
// Start the server
|
||||||
@ -912,6 +1103,10 @@ void RemoteProxyOfflineTests::jsonRpcTimeout()
|
|||||||
// Start the server
|
// Start the server
|
||||||
startServer();
|
startServer();
|
||||||
|
|
||||||
|
m_configuration->setAuthenticationTimeout(3000);
|
||||||
|
m_configuration->setJsonRpcTimeout(1000);
|
||||||
|
m_configuration->setInactiveTimeout(2000);
|
||||||
|
|
||||||
// Configure result (authentication takes longer than json rpc timeout
|
// Configure result (authentication takes longer than json rpc timeout
|
||||||
m_mockAuthenticator->setExpectedAuthenticationError();
|
m_mockAuthenticator->setExpectedAuthenticationError();
|
||||||
m_mockAuthenticator->setTimeoutDuration(4000);
|
m_mockAuthenticator->setTimeoutDuration(4000);
|
||||||
@ -964,7 +1159,7 @@ void RemoteProxyOfflineTests::authenticationReplyTimeout()
|
|||||||
|
|
||||||
// Configure result (authentication takes longer than json rpc timeout
|
// Configure result (authentication takes longer than json rpc timeout
|
||||||
m_mockAuthenticator->setExpectedAuthenticationError();
|
m_mockAuthenticator->setExpectedAuthenticationError();
|
||||||
m_mockAuthenticator->setTimeoutDuration(1000);
|
m_mockAuthenticator->setTimeoutDuration(2000);
|
||||||
|
|
||||||
m_configuration->setAuthenticationTimeout(500);
|
m_configuration->setAuthenticationTimeout(500);
|
||||||
m_configuration->setJsonRpcTimeout(1000);
|
m_configuration->setJsonRpcTimeout(1000);
|
||||||
@ -1017,4 +1212,98 @@ void RemoteProxyOfflineTests::authenticationReplyConnection()
|
|||||||
stopServer();
|
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)
|
QTEST_MAIN(RemoteProxyOfflineTests)
|
||||||
|
|||||||
@ -54,10 +54,7 @@ private slots:
|
|||||||
void websocketBinaryData();
|
void websocketBinaryData();
|
||||||
void websocketPing();
|
void websocketPing();
|
||||||
|
|
||||||
// TCP socket connection
|
// WebSocket connection API
|
||||||
|
|
||||||
|
|
||||||
// Api
|
|
||||||
void getIntrospect();
|
void getIntrospect();
|
||||||
void getHello();
|
void getHello();
|
||||||
|
|
||||||
@ -71,20 +68,21 @@ private slots:
|
|||||||
void authenticateSendData();
|
void authenticateSendData();
|
||||||
|
|
||||||
// Client lib
|
// Client lib
|
||||||
void clientConnection();
|
void clientConnectionTcpSocket();
|
||||||
|
void clientConnectionWebSocket();
|
||||||
void remoteConnection();
|
void remoteConnection();
|
||||||
void multipleRemoteConnection();
|
void multipleRemoteConnection();
|
||||||
void trippleConnection();
|
void trippleConnection();
|
||||||
void duplicateUuid();
|
void duplicateUuid();
|
||||||
void sslConfigurations();
|
void sslConfigurations();
|
||||||
|
|
||||||
void jsonRpcTimeout();
|
|
||||||
void inactiveTimeout();
|
void inactiveTimeout();
|
||||||
|
void jsonRpcTimeout();
|
||||||
void authenticationReplyTimeout();
|
void authenticationReplyTimeout();
|
||||||
void authenticationReplyConnection();
|
void authenticationReplyConnection();
|
||||||
|
|
||||||
// TCP Websocket combinations
|
// TCP Websocket combinations
|
||||||
|
//void tcpRemoteConnection();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -31,8 +31,10 @@
|
|||||||
#include "loggingcategories.h"
|
#include "loggingcategories.h"
|
||||||
#include "remoteproxyconnection.h"
|
#include "remoteproxyconnection.h"
|
||||||
|
|
||||||
|
#include <QSslError>
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
#include <QSignalSpy>
|
#include <QSignalSpy>
|
||||||
|
#include <QSslSocket>
|
||||||
#include <QWebSocket>
|
#include <QWebSocket>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QWebSocketServer>
|
#include <QWebSocketServer>
|
||||||
@ -47,16 +49,34 @@ void BaseTest::loadConfiguration(const QString &fileName)
|
|||||||
{
|
{
|
||||||
qDebug() << "Load test configurations" << fileName;
|
qDebug() << "Load test configurations" << fileName;
|
||||||
m_configuration->loadConfiguration(fileName);
|
m_configuration->loadConfiguration(fileName);
|
||||||
restartEngine();
|
//restartEngine();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseTest::cleanUpEngine()
|
void BaseTest::cleanUpEngine()
|
||||||
{
|
{
|
||||||
|
qDebug() << "Clean up engine";
|
||||||
if (Engine::exists()) {
|
if (Engine::exists()) {
|
||||||
Engine::instance()->stop();
|
Engine::instance()->stop();
|
||||||
Engine::instance()->destroy();
|
Engine::instance()->destroy();
|
||||||
QVERIFY(!Engine::exists());
|
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()
|
void BaseTest::restartEngine()
|
||||||
@ -67,22 +87,29 @@ void BaseTest::restartEngine()
|
|||||||
|
|
||||||
void BaseTest::startEngine()
|
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<Authenticator *>(m_mockAuthenticator);
|
||||||
if (!Engine::exists()) {
|
if (!Engine::exists()) {
|
||||||
Engine::instance()->setAuthenticator(m_authenticator);
|
Engine::instance()->setAuthenticator(m_authenticator);
|
||||||
Engine::instance()->setDeveloperModeEnabled(true);
|
Engine::instance()->setDeveloperModeEnabled(true);
|
||||||
QVERIFY(Engine::exists());
|
QVERIFY(Engine::exists());
|
||||||
|
QVERIFY(!Engine::instance()->running());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseTest::startServer()
|
void BaseTest::startServer()
|
||||||
{
|
{
|
||||||
startEngine();
|
restartEngine();
|
||||||
|
|
||||||
if (!Engine::instance()->running()) {
|
if (!Engine::instance()->running()) {
|
||||||
QSignalSpy runningSpy(Engine::instance(), &Engine::runningChanged);
|
QSignalSpy runningSpy(Engine::instance(), &Engine::runningChanged);
|
||||||
Engine::instance()->setDeveloperModeEnabled(true);
|
Engine::instance()->setDeveloperModeEnabled(true);
|
||||||
Engine::instance()->start(m_configuration);
|
Engine::instance()->start(m_configuration);
|
||||||
runningSpy.wait(100);
|
runningSpy.wait(200);
|
||||||
QVERIFY(runningSpy.count() == 1);
|
QVERIFY(runningSpy.count() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,6 +127,8 @@ void BaseTest::stopServer()
|
|||||||
|
|
||||||
Engine::instance()->stop();
|
Engine::instance()->stop();
|
||||||
QVERIFY(!Engine::instance()->running());
|
QVERIFY(!Engine::instance()->running());
|
||||||
|
|
||||||
|
cleanUpEngine();
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant BaseTest::invokeWebSocketApiCall(const QString &method, const QVariantMap params, bool remainsConnected)
|
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;
|
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<QSslError> &);
|
||||||
|
QObject::connect(socket, static_cast<sslErrorsSignal>(&QSslSocket::sslErrors), this, &BaseTest::sslSocketSslErrors);
|
||||||
|
|
||||||
|
QSignalSpy spyConnection(socket, &QSslSocket::connected);
|
||||||
|
socket->connectToHostEncrypted(Engine::instance()->tcpSocketServer()->serverUrl().host(),
|
||||||
|
static_cast<quint16>(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<QSslError> &);
|
||||||
|
QObject::connect(socket, static_cast<sslErrorsSignal>(&QSslSocket::sslErrors), this, &BaseTest::sslSocketSslErrors);
|
||||||
|
|
||||||
|
QSignalSpy spyConnection(socket, &QSslSocket::connected);
|
||||||
|
socket->connectToHostEncrypted(Engine::instance()->tcpSocketServer()->serverUrl().host(),
|
||||||
|
static_cast<quint16>(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()
|
void BaseTest::initTestCase()
|
||||||
{
|
{
|
||||||
qRegisterMetaType<RemoteProxyConnection::State>();
|
qRegisterMetaType<RemoteProxyConnection::State>();
|
||||||
qRegisterMetaType<RemoteProxyConnection::ConnectionType>();
|
qRegisterMetaType<RemoteProxyConnection::ConnectionType>();
|
||||||
|
|
||||||
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<Authenticator *>(m_mockAuthenticator);
|
|
||||||
|
|
||||||
m_testToken = "eyJraWQiOiJXdnFFT3prVVh5VDlINzFyRUpoNWdxRnkxNFhnR2l3SFAzVEIzUFQ1V3ZrPSIsImFsZyI6IlJT"
|
m_testToken = "eyJraWQiOiJXdnFFT3prVVh5VDlINzFyRUpoNWdxRnkxNFhnR2l3SFAzVEIzUFQ1V3ZrPSIsImFsZyI6IlJT"
|
||||||
"MjU2In0.eyJzdWIiOiJmZTJmZDNlNC1hMGJhLTQ1OTUtOWRiZS00ZDkxYjRiMjFlMzUiLCJhdWQiOiI4cmpoZ"
|
"MjU2In0.eyJzdWIiOiJmZTJmZDNlNC1hMGJhLTQ1OTUtOWRiZS00ZDkxYjRiMjFlMzUiLCJhdWQiOiI4cmpoZ"
|
||||||
"mRsZjlqZjFzdW9rMmpjcmx0ZDZ2IiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImV2ZW50X2lkIjoiN2Y5NTRiNm"
|
"mRsZjlqZjFzdW9rMmpjcmx0ZDZ2IiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImV2ZW50X2lkIjoiN2Y5NTRiNm"
|
||||||
@ -337,20 +463,13 @@ void BaseTest::initTestCase()
|
|||||||
"pQbj58v1vktaAEATdmKmlzmcix-HJK9wWHRSuv3TsNa8DGxvcPOoeTu8Vql7krZ-y7Zu-s2WsgeP4VxyT80VE"
|
"pQbj58v1vktaAEATdmKmlzmcix-HJK9wWHRSuv3TsNa8DGxvcPOoeTu8Vql7krZ-y7Zu-s2WsgeP4VxyT80VE"
|
||||||
"T_xh6pMkOhE6g";
|
"T_xh6pMkOhE6g";
|
||||||
|
|
||||||
qCDebug(dcApplication()) << "Init test case.";
|
qCDebug(dcApplication()) << "Init test case done.";
|
||||||
restartEngine();
|
//restartEngine();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseTest::cleanupTestCase()
|
void BaseTest::cleanupTestCase()
|
||||||
{
|
{
|
||||||
qCDebug(dcApplication()) << "Clean up test case.";
|
qCDebug(dcApplication()) << "Clean up test case.";
|
||||||
delete m_configuration;
|
|
||||||
delete m_mockAuthenticator;
|
|
||||||
delete m_dummyAuthenticator;
|
|
||||||
//delete m_awsAuthenticator;
|
|
||||||
|
|
||||||
m_authenticator = nullptr;
|
|
||||||
|
|
||||||
cleanUpEngine();
|
cleanUpEngine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -57,6 +57,7 @@ protected:
|
|||||||
ProxyConfiguration *m_configuration = nullptr;
|
ProxyConfiguration *m_configuration = nullptr;
|
||||||
|
|
||||||
QUrl m_serverUrl = QUrl("wss://127.0.0.1:1212");
|
QUrl m_serverUrl = QUrl("wss://127.0.0.1:1212");
|
||||||
|
QUrl m_serverUrlTcp = QUrl("ssl://127.0.0.1:1213");
|
||||||
|
|
||||||
QSslConfiguration m_sslConfiguration;
|
QSslConfiguration m_sslConfiguration;
|
||||||
|
|
||||||
@ -88,8 +89,13 @@ protected slots:
|
|||||||
void cleanupTestCase();
|
void cleanupTestCase();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
inline void sslSocketSslErrors(const QList<QSslError> &) {
|
||||||
|
QSslSocket *socket = static_cast<QSslSocket *>(sender());
|
||||||
|
socket->ignoreSslErrors();
|
||||||
|
}
|
||||||
|
|
||||||
inline void sslErrors(const QList<QSslError> &) {
|
inline void sslErrors(const QList<QSslError> &) {
|
||||||
QWebSocket *socket = static_cast<QWebSocket*>(sender());
|
QWebSocket *socket = static_cast<QWebSocket *>(sender());
|
||||||
socket->ignoreSslErrors();
|
socket->ignoreSslErrors();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -55,8 +55,7 @@ void MockAuthenticator::replyFinished()
|
|||||||
{
|
{
|
||||||
MockAuthenticationReply *reply = static_cast<MockAuthenticationReply *>(sender());
|
MockAuthenticationReply *reply = static_cast<MockAuthenticationReply *>(sender());
|
||||||
|
|
||||||
qCDebug(dcAuthentication()) << name() << "Authentication finished.";
|
qCDebug(dcAuthentication()) << name() << "Authentication finished" << reply << reply->authenticationReply();
|
||||||
|
|
||||||
setReplyError(reply->authenticationReply(), reply->error());
|
setReplyError(reply->authenticationReply(), reply->error());
|
||||||
setReplyFinished(reply->authenticationReply());
|
setReplyFinished(reply->authenticationReply());
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
@ -64,7 +63,7 @@ void MockAuthenticator::replyFinished()
|
|||||||
|
|
||||||
AuthenticationReply *MockAuthenticator::authenticate(ProxyClient *proxyClient)
|
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);
|
AuthenticationReply *authenticationReply = createAuthenticationReply(proxyClient, proxyClient);
|
||||||
|
|
||||||
@ -84,3 +83,8 @@ MockAuthenticationReply::MockAuthenticationReply(int timeout, Authenticator::Aut
|
|||||||
QTimer::singleShot(timeout, this, &MockAuthenticationReply::finished);
|
QTimer::singleShot(timeout, this, &MockAuthenticationReply::finished);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MockAuthenticationReply::~MockAuthenticationReply()
|
||||||
|
{
|
||||||
|
qCCritical(dcAuthentication()) << "Destroy mock authentication reply";
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -40,6 +40,7 @@ class MockAuthenticationReply : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit MockAuthenticationReply(int timeout, Authenticator::AuthenticationError error, AuthenticationReply *authenticationReply, QObject *parent = nullptr);
|
explicit MockAuthenticationReply(int timeout, Authenticator::AuthenticationError error, AuthenticationReply *authenticationReply, QObject *parent = nullptr);
|
||||||
|
~MockAuthenticationReply();
|
||||||
|
|
||||||
AuthenticationReply *authenticationReply() const { return m_authenticationReply; }
|
AuthenticationReply *authenticationReply() const { return m_authenticationReply; }
|
||||||
Authenticator::AuthenticationError error() const { return m_error; }
|
Authenticator::AuthenticationError error() const { return m_error; }
|
||||||
@ -66,7 +67,7 @@ public:
|
|||||||
void setExpectedAuthenticationError(Authenticator::AuthenticationError error = AuthenticationErrorNoError);
|
void setExpectedAuthenticationError(Authenticator::AuthenticationError error = AuthenticationErrorNoError);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_timeoutDuration = 1000;
|
int m_timeoutDuration = 500;
|
||||||
Authenticator::AuthenticationError m_expectedError;
|
Authenticator::AuthenticationError m_expectedError;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|||||||
Reference in New Issue
Block a user