1322 lines
54 KiB
C++
1322 lines
54 KiB
C++
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||
*
|
||
* Copyright 2013 - 2022, nymea GmbH
|
||
* Contact: contact@nymea.io
|
||
*
|
||
* This file is part of nymea.
|
||
* This project including source code and documentation is protected by copyright law, and
|
||
* remains the property of nymea GmbH. All rights, including reproduction, publication,
|
||
* editing and translation, are reserved. The use of this project is subject to the terms of a
|
||
* license agreement to be concluded with nymea GmbH in accordance with the terms
|
||
* of use of nymea GmbH, available under https://nymea.io/license
|
||
*
|
||
* GNU General Public License Usage
|
||
* Alternatively, this project may be redistributed and/or modified under
|
||
* the terms of the GNU General Public License as published by the Free Software Foundation,
|
||
* GNU version 3. this project is distributed in the hope that it will be useful, but WITHOUT ANY
|
||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||
* PURPOSE. See the GNU General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU General Public License along with this project.
|
||
* If not, see <https://www.gnu.org/licenses/>.
|
||
*
|
||
* For any further details and any questions please contact us under contact@nymea.io
|
||
* or see our FAQ/Licensing Information on https://nymea.io/license/faq
|
||
*
|
||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||
|
||
#include "remoteproxyteststunnelproxy.h"
|
||
|
||
|
||
#include "engine.h"
|
||
#include "loggingcategories.h"
|
||
#include "../common/slipdataprocessor.h"
|
||
#include "../../version.h"
|
||
|
||
// Client
|
||
#include "tunnelproxy/tunnelproxysocketserver.h"
|
||
#include "tunnelproxy/tunnelproxyremoteconnection.h"
|
||
|
||
#include <QMetaType>
|
||
#include <QSignalSpy>
|
||
#include <QWebSocket>
|
||
#include <QJsonDocument>
|
||
#include <QWebSocketServer>
|
||
|
||
using namespace remoteproxyclient;
|
||
|
||
RemoteProxyTestsTunnelProxy::RemoteProxyTestsTunnelProxy(QObject *parent) :
|
||
BaseTest(parent)
|
||
{
|
||
|
||
}
|
||
|
||
void RemoteProxyTestsTunnelProxy::startStopServer()
|
||
{
|
||
resetDebugCategories();
|
||
addDebugCategory("Engine.debug=true");
|
||
addDebugCategory("JsonRpc.debug=true");
|
||
addDebugCategory("TcpSocketServer.debug=true");
|
||
addDebugCategory("WebSocketServer.debug=true");
|
||
addDebugCategory("TunnelProxyServer.debug=true");
|
||
|
||
startServer();
|
||
stopServer();
|
||
}
|
||
|
||
void RemoteProxyTestsTunnelProxy::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 RemoteProxyTestsTunnelProxy::apiBasicCallsTcp()
|
||
{
|
||
resetDebugCategories();
|
||
addDebugCategory("Engine.debug=true");
|
||
addDebugCategory("TcpSocketServer.debug=true");
|
||
|
||
QFETCH(QByteArray, data);
|
||
QFETCH(int, responseId);
|
||
QFETCH(QString, responseStatus);
|
||
|
||
// Start the server
|
||
startServer();
|
||
|
||
QVariant response = injectTcpSocketTunnelProxyData(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 RemoteProxyTestsTunnelProxy::getIntrospect()
|
||
{
|
||
// Start the server
|
||
startServer();
|
||
|
||
QVariantMap response;
|
||
|
||
// WebSocket
|
||
response = invokeWebSocketTunnelProxyApiCall("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 = invokeTcpSocketTunnelProxyApiCall("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();
|
||
}
|
||
|
||
void RemoteProxyTestsTunnelProxy::getHello()
|
||
{
|
||
// Start the server
|
||
startServer();
|
||
|
||
// WebSocket
|
||
QVariantMap response = invokeWebSocketTunnelProxyApiCall("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 = invokeTcpSocketTunnelProxyApiCall("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();
|
||
}
|
||
|
||
void RemoteProxyTestsTunnelProxy::monitorServer()
|
||
{
|
||
|
||
// Start the server
|
||
startServer();
|
||
|
||
|
||
// ** Create the server **
|
||
QString serverName = "nymea server";
|
||
QUuid serverUuid = QUuid::createUuid();
|
||
|
||
TunnelProxySocketServer *tunnelProxyServer = new TunnelProxySocketServer(serverUuid, serverName, this);
|
||
connect(tunnelProxyServer, &TunnelProxySocketServer::sslErrors, this, [=](const QList<QSslError> &errors){
|
||
tunnelProxyServer->ignoreSslErrors(errors);
|
||
});
|
||
|
||
tunnelProxyServer->startServer(m_serverUrlTunnelProxyTcp);
|
||
|
||
QSignalSpy serverRunningSpy(tunnelProxyServer, &TunnelProxySocketServer::runningChanged);
|
||
serverRunningSpy.wait();
|
||
QVERIFY(serverRunningSpy.count() == 1);
|
||
QList<QVariant> arguments = serverRunningSpy.takeFirst();
|
||
QVERIFY(arguments.at(0).toBool() == true);
|
||
QVERIFY(tunnelProxyServer->running());
|
||
QCOMPARE(tunnelProxyServer->serverUrl(), m_serverUrlTunnelProxyTcp);
|
||
QCOMPARE(tunnelProxyServer->remoteProxyServer(), QString(SERVER_NAME_STRING));
|
||
QCOMPARE(tunnelProxyServer->remoteProxyServerName(), Engine::instance()->configuration()->serverName());
|
||
QCOMPARE(tunnelProxyServer->remoteProxyServerVersion(), QString(SERVER_VERSION_STRING));
|
||
QCOMPARE(tunnelProxyServer->remoteProxyApiVersion(), QString(API_VERSION_STRING));
|
||
|
||
|
||
// ** Remote connection 1 **
|
||
|
||
QString clientOneName = "Client one";
|
||
QUuid clientOneUuid = QUuid::createUuid();
|
||
TunnelProxyRemoteConnection *remoteConnectionOne = new TunnelProxyRemoteConnection(clientOneUuid, clientOneName, this);
|
||
connect(remoteConnectionOne, &TunnelProxyRemoteConnection::sslErrors, this, [=](const QList<QSslError> &errors){
|
||
remoteConnectionOne->ignoreSslErrors(errors);
|
||
});
|
||
|
||
remoteConnectionOne->connectServer(m_serverUrlTunnelProxyTcp, serverUuid);
|
||
|
||
// ** Tunnel proxy server socket 1 **
|
||
QSignalSpy remoteConnectedOneSpy(tunnelProxyServer, &TunnelProxySocketServer::clientConnected);
|
||
QVERIFY(remoteConnectedOneSpy.wait());
|
||
QVERIFY(remoteConnectedOneSpy.count() == 1);
|
||
arguments = remoteConnectedOneSpy.takeFirst();
|
||
|
||
TunnelProxySocket *tunnelProxySocketOne = arguments.at(0).value<TunnelProxySocket *>();
|
||
QVERIFY(tunnelProxySocketOne->clientName() == clientOneName);
|
||
QVERIFY(tunnelProxySocketOne->clientUuid() == clientOneUuid);
|
||
QVERIFY(!tunnelProxySocketOne->clientPeerAddress().isNull());
|
||
QVERIFY(tunnelProxySocketOne->socketAddress() != 0x0000 && tunnelProxySocketOne->socketAddress() != 0xFFFF);
|
||
QVERIFY(tunnelProxySocketOne->connected());
|
||
|
||
qDebug() << "Have socket one" << tunnelProxySocketOne;
|
||
|
||
// ** Send data in both directions
|
||
QByteArray testData("#sdföiabi23u4b34b598gvndafjibnföQIUH34982HRIPURBFÖWLKDÜOQw9h934utbf ljBiH9FBLAJF RF AF,A§uu)(\"§)§(u$)($=$(((($((!");
|
||
|
||
// Socket -> Remote connection
|
||
QSignalSpy remoteConnectionOneDataSpy(remoteConnectionOne, &TunnelProxyRemoteConnection::dataReady);
|
||
tunnelProxySocketOne->writeData(testData);
|
||
QVERIFY(remoteConnectionOneDataSpy.wait());
|
||
QVERIFY(remoteConnectionOneDataSpy.count() == 1);
|
||
arguments = remoteConnectionOneDataSpy.takeFirst();
|
||
QByteArray receivedTestData = arguments.at(0).toByteArray();
|
||
QVERIFY(receivedTestData == testData);
|
||
|
||
|
||
// Remote connection -> Socket
|
||
QByteArray testData2("The biggest decision in life is about changing your life through changing your mind. – Albert Schweitzer");
|
||
QSignalSpy tunnelProxySocketOneDataSpy(tunnelProxySocketOne, &TunnelProxySocket::dataReceived);
|
||
remoteConnectionOne->sendData(testData2);
|
||
QVERIFY(tunnelProxySocketOneDataSpy.wait());
|
||
QVERIFY(tunnelProxySocketOneDataSpy.count() == 1);
|
||
arguments = tunnelProxySocketOneDataSpy.takeFirst();
|
||
QByteArray receivedTestData2 = arguments.at(0).toByteArray();
|
||
QVERIFY(receivedTestData2 == testData2);
|
||
|
||
|
||
// ** Remote connection 2 **
|
||
|
||
QString clientTwoName = "Client two";
|
||
QUuid clientTwoUuid = QUuid::createUuid();
|
||
TunnelProxyRemoteConnection *remoteConnectionTwo = new TunnelProxyRemoteConnection(clientTwoUuid, clientTwoName, this);
|
||
connect(remoteConnectionTwo, &TunnelProxyRemoteConnection::sslErrors, this, [=](const QList<QSslError> &errors){
|
||
remoteConnectionTwo->ignoreSslErrors(errors);
|
||
});
|
||
|
||
remoteConnectionTwo->connectServer(m_serverUrlTunnelProxyTcp, serverUuid);
|
||
|
||
// ** Tunnel proxy server socket 2 **
|
||
QSignalSpy remoteConnectedTwoSpy(tunnelProxyServer, &TunnelProxySocketServer::clientConnected);
|
||
QVERIFY(remoteConnectedTwoSpy.wait());
|
||
QVERIFY(remoteConnectedTwoSpy.count() == 1);
|
||
arguments = remoteConnectedTwoSpy.takeFirst();
|
||
|
||
TunnelProxySocket *tunnelProxySocketTwo = arguments.at(0).value<TunnelProxySocket *>();
|
||
QVERIFY(tunnelProxySocketTwo->clientName() == clientTwoName);
|
||
QVERIFY(tunnelProxySocketTwo->clientUuid() == clientTwoUuid);
|
||
QVERIFY(!tunnelProxySocketTwo->clientPeerAddress().isNull());
|
||
QVERIFY(tunnelProxySocketTwo->socketAddress() != 0x0000 && tunnelProxySocketTwo->socketAddress() != 0xFFFF);
|
||
QVERIFY(tunnelProxySocketTwo->connected());
|
||
|
||
qDebug() << "Have socket two" << tunnelProxySocketTwo;
|
||
|
||
// ** Send data in both directions
|
||
|
||
// Socket -> Remote connection
|
||
QSignalSpy remoteConnectionTwoDataSpy(remoteConnectionTwo, &TunnelProxyRemoteConnection::dataReady);
|
||
tunnelProxySocketTwo->writeData(testData);
|
||
QVERIFY(remoteConnectionTwoDataSpy.wait());
|
||
QVERIFY(remoteConnectionTwoDataSpy.count() == 1);
|
||
arguments = remoteConnectionTwoDataSpy.takeFirst();
|
||
receivedTestData = arguments.at(0).toByteArray();
|
||
QVERIFY(receivedTestData == testData);
|
||
|
||
// Remote connection -> Socket
|
||
QSignalSpy tunnelProxySocketTwoDataSpy(tunnelProxySocketTwo, &TunnelProxySocket::dataReceived);
|
||
remoteConnectionTwo->sendData(testData2);
|
||
QVERIFY(tunnelProxySocketTwoDataSpy.wait());
|
||
QVERIFY(tunnelProxySocketTwoDataSpy.count() == 1);
|
||
arguments = tunnelProxySocketTwoDataSpy.takeFirst();
|
||
receivedTestData2 = arguments.at(0).toByteArray();
|
||
QVERIFY(receivedTestData2 == testData2);
|
||
|
||
// Get monitor data
|
||
QLocalSocket *monitor = new QLocalSocket(this);
|
||
QSignalSpy connectedSpy(monitor, &QLocalSocket::connected);
|
||
monitor->connectToServer(m_configuration->monitorSocketFileName());
|
||
if (connectedSpy.count() < 1) connectedSpy.wait();
|
||
QVERIFY(connectedSpy.count() == 1);
|
||
|
||
QSignalSpy dataSpy(monitor, &QLocalSocket::readyRead);
|
||
|
||
QVariantMap request;
|
||
request.insert("method", "refresh");
|
||
QVariantMap params;
|
||
params.insert("printAll", true);
|
||
request.insert("params", params);
|
||
|
||
monitor->write(QJsonDocument::fromVariant(request).toJson(QJsonDocument::Compact) + "\n");
|
||
|
||
if (dataSpy.count() < 1) dataSpy.wait();
|
||
QVERIFY(dataSpy.count() == 1);
|
||
QByteArray data = monitor->readAll();
|
||
qDebug() << data;
|
||
|
||
// TODO: verify monitor data
|
||
|
||
QSignalSpy disconnectedSpy(monitor, &QLocalSocket::connected);
|
||
monitor->disconnectFromServer();
|
||
if (disconnectedSpy.count() < 1) disconnectedSpy.wait();
|
||
|
||
Engine::instance()->tunnelProxyServer()->stopServer();
|
||
|
||
QTest::qWait(100);
|
||
|
||
QVERIFY(!tunnelProxyServer->running());
|
||
QVERIFY(!remoteConnectionOne->remoteConnected());
|
||
QVERIFY(!remoteConnectionTwo->remoteConnected());
|
||
|
||
// Clean up
|
||
tunnelProxyServer->deleteLater();
|
||
remoteConnectionOne->deleteLater();
|
||
remoteConnectionTwo->deleteLater();
|
||
|
||
resetDebugCategories();
|
||
|
||
stopServer();
|
||
}
|
||
|
||
void RemoteProxyTestsTunnelProxy::configuration_data()
|
||
{
|
||
QTest::addColumn<QString>("fileName");
|
||
QTest::addColumn<bool>("success");
|
||
|
||
QTest::newRow("valid configuration") << ":/test-configuration.conf" << true;
|
||
QTest::newRow("valid configuration chain") << ":/test-configuration-chain.conf" << true;
|
||
QTest::newRow("faulty filename") << ":/not-exisitng-test-configuration.conf" << false;
|
||
QTest::newRow("faulty certificate") << ":/test-configuration-faulty-certificate.conf" << false;
|
||
QTest::newRow("faulty key") << ":/test-configuration-faulty-key.conf" << false;
|
||
QTest::newRow("faulty chain") << ":/test-configuration-faulty-chain.conf" << false;
|
||
}
|
||
|
||
void RemoteProxyTestsTunnelProxy::configuration()
|
||
{
|
||
QFETCH(QString, fileName);
|
||
QFETCH(bool, success);
|
||
|
||
ProxyConfiguration configuration;
|
||
QCOMPARE(configuration.loadConfiguration(fileName), success);
|
||
}
|
||
|
||
void RemoteProxyTestsTunnelProxy::serverPortBlocked()
|
||
{
|
||
cleanUpEngine();
|
||
|
||
m_configuration = new ProxyConfiguration(this);
|
||
loadConfiguration(":/test-configuration.conf");
|
||
|
||
// Create a dummy server which blocks the port
|
||
QWebSocketServer dummyServer("dummy-server", QWebSocketServer::NonSecureMode);
|
||
QVERIFY(dummyServer.listen(QHostAddress::LocalHost, m_configuration->webSocketServerTunnelProxyPort()));
|
||
|
||
// Start proxy webserver
|
||
QSignalSpy runningSpy(Engine::instance(), &Engine::runningChanged);
|
||
Engine::instance()->start(m_configuration);
|
||
runningSpy.wait();
|
||
QVERIFY(runningSpy.count() == 1);
|
||
|
||
// Make sure the server is not running
|
||
QVERIFY(Engine::instance()->running());
|
||
|
||
// Make sure the websocket server is not running
|
||
QVERIFY(!Engine::instance()->webSocketServerTunnelProxy()->running());
|
||
|
||
QSignalSpy closedSpy(&dummyServer, &QWebSocketServer::closed);
|
||
dummyServer.close();
|
||
closedSpy.wait();
|
||
QVERIFY(closedSpy.count() == 1);
|
||
|
||
// Try again
|
||
startServer();
|
||
|
||
// Clean up
|
||
stopServer();
|
||
|
||
// Do the same with the tcp server
|
||
cleanUpEngine();
|
||
|
||
m_configuration = new ProxyConfiguration(this);
|
||
loadConfiguration(":/test-configuration.conf");
|
||
|
||
// Create a dummy server which blocks the port
|
||
QTcpServer *tcpDummyServer = new QTcpServer(this);
|
||
QVERIFY(tcpDummyServer->listen(QHostAddress::LocalHost, m_configuration->tcpServerTunnelProxyPort()));
|
||
|
||
// Start proxy webserver
|
||
QSignalSpy runningSpy2(Engine::instance(), &Engine::runningChanged);
|
||
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()->tcpSocketServerTunnelProxy()->running());
|
||
|
||
tcpDummyServer->close();
|
||
delete tcpDummyServer;
|
||
|
||
// Try again
|
||
startServer();
|
||
|
||
// Make sure the TCP server is not running
|
||
QVERIFY(Engine::instance()->webSocketServerTunnelProxy()->running());
|
||
QVERIFY(Engine::instance()->tcpSocketServerTunnelProxy()->running());
|
||
|
||
// Clean up
|
||
stopServer();
|
||
}
|
||
|
||
void RemoteProxyTestsTunnelProxy::websocketBinaryData()
|
||
{
|
||
// Start the server
|
||
startServer();
|
||
|
||
QWebSocket *client = new QWebSocket("bad-client", QWebSocketProtocol::Version13);
|
||
connect(client, &QWebSocket::sslErrors, this, &BaseTest::sslErrors);
|
||
QSignalSpy spyConnection(client, SIGNAL(connected()));
|
||
client->open(Engine::instance()->webSocketServerTunnelProxy()->serverUrl());
|
||
spyConnection.wait();
|
||
|
||
// Send binary data and make sure the server disconnects this socket
|
||
QSignalSpy spyDisconnected(client, SIGNAL(disconnected()));
|
||
client->sendBinaryMessage("trying to upload stuff...stuff...more stuff... other stuff");
|
||
spyConnection.wait(1000);
|
||
QVERIFY(spyConnection.count() == 1);
|
||
|
||
// Clean up
|
||
stopServer();
|
||
}
|
||
|
||
void RemoteProxyTestsTunnelProxy::websocketPing()
|
||
{
|
||
// Start the server
|
||
startServer();
|
||
|
||
QWebSocket *client = new QWebSocket("bad-client", QWebSocketProtocol::Version13);
|
||
connect(client, &QWebSocket::sslErrors, this, &BaseTest::sslErrors);
|
||
QSignalSpy spyConnection(client, SIGNAL(connected()));
|
||
client->open(Engine::instance()->webSocketServerTunnelProxy()->serverUrl());
|
||
spyConnection.wait();
|
||
QVERIFY(spyConnection.count() == 1);
|
||
|
||
QByteArray pingMessage = QByteArray("ping!");
|
||
QSignalSpy pongSpy(client, &QWebSocket::pong);
|
||
client->ping(pingMessage);
|
||
pongSpy.wait();
|
||
QVERIFY(pongSpy.count() == 1);
|
||
qDebug() << pongSpy.at(0).at(0) << pongSpy.at(0).at(1);
|
||
|
||
QVERIFY(pongSpy.at(0).at(1).toByteArray() == pingMessage);
|
||
|
||
// Clean up
|
||
stopServer();
|
||
}
|
||
|
||
void RemoteProxyTestsTunnelProxy::apiBasicCalls_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 RemoteProxyTestsTunnelProxy::apiBasicCalls()
|
||
{
|
||
QFETCH(QByteArray, data);
|
||
QFETCH(int, responseId);
|
||
QFETCH(QString, responseStatus);
|
||
|
||
resetDebugCategories();
|
||
addDebugCategory("TunnelProxyServer.debug=true");
|
||
addDebugCategory("*.debug=true");
|
||
|
||
// Start the server
|
||
startServer();
|
||
|
||
QVariantMap response;
|
||
|
||
// Websocket
|
||
response = injectWebSocketTunnelProxyData(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 = injectTcpSocketTunnelProxyData(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();
|
||
}
|
||
|
||
|
||
void RemoteProxyTestsTunnelProxy::registerServer_data()
|
||
{
|
||
QTest::addColumn<QString>("name");
|
||
QTest::addColumn<QString>("uuid");
|
||
QTest::addColumn<TunnelProxyServer::TunnelProxyError>("expectedError");
|
||
|
||
QTest::newRow("valid call") << "valid server" << QUuid::createUuid().toString() << TunnelProxyServer::TunnelProxyErrorNoError;
|
||
QTest::newRow("valid uuid with brackets") << "valid server" << "{00323a95-d1ab-4752-88d4-dbc8b9015b0f}" << TunnelProxyServer::TunnelProxyErrorNoError;
|
||
QTest::newRow("valid uuid without brackets") << "valid server" << "00323a95-d1ab-4752-88d4-dbc8b9015b0f" << TunnelProxyServer::TunnelProxyErrorNoError;
|
||
QTest::newRow("invalid null uuid") << "valid server" << QUuid().toString() << TunnelProxyServer::TunnelProxyErrorInvalidUuid;
|
||
QTest::newRow("invalid null uuid") << "valid server" << "foo" << TunnelProxyServer::TunnelProxyErrorInvalidUuid;
|
||
}
|
||
|
||
|
||
void RemoteProxyTestsTunnelProxy::registerServer()
|
||
{
|
||
QFETCH(QString, name);
|
||
QFETCH(QString, uuid);
|
||
QFETCH(TunnelProxyServer::TunnelProxyError, expectedError);
|
||
|
||
// Start the server
|
||
startServer();
|
||
|
||
resetDebugCategories();
|
||
addDebugCategory("TunnelProxyServer.debug=true");
|
||
|
||
// Register a new server
|
||
QVariantMap params;
|
||
params.insert("serverName", name);
|
||
params.insert("serverUuid", uuid);
|
||
|
||
// Websocket
|
||
QVariantMap response = invokeWebSocketTunnelProxyApiCall("TunnelProxy.RegisterServer", params).toMap();
|
||
|
||
QVERIFY(!response.isEmpty());
|
||
QVERIFY(response.value("status").toString() == "success");
|
||
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
|
||
verifyTunnelProxyError(response, expectedError);
|
||
|
||
// TCP Socket
|
||
response = invokeTcpSocketTunnelProxyApiCall("TunnelProxy.RegisterServer", params).toMap();
|
||
QVERIFY(!response.isEmpty());
|
||
QVERIFY(response.value("status").toString() == "success");
|
||
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
|
||
verifyTunnelProxyError(response, expectedError);
|
||
|
||
// Clean up
|
||
stopServer();
|
||
}
|
||
|
||
void RemoteProxyTestsTunnelProxy::registerClient_data()
|
||
{
|
||
QTest::addColumn<QString>("name");
|
||
QTest::addColumn<QString>("uuid");
|
||
QTest::addColumn<TunnelProxyServer::TunnelProxyError>("expectedError");
|
||
QTest::addColumn<bool>("serverExists");
|
||
QTest::addColumn<QString>("serverUuid");
|
||
QTest::addColumn<TunnelProxyServer::TunnelProxyError>("expectedServerError");
|
||
|
||
QTest::newRow("valid client: valid server") << "Friendly client" << QUuid::createUuid().toString() << TunnelProxyServer::TunnelProxyErrorNoError << true << QUuid::createUuid().toString() << TunnelProxyServer::TunnelProxyErrorNoError;
|
||
QTest::newRow("valid client: no server") << "Friendly client" << QUuid::createUuid().toString() << TunnelProxyServer::TunnelProxyErrorServerNotFound << false << QUuid::createUuid().toString() << TunnelProxyServer::TunnelProxyErrorNoError;
|
||
QTest::newRow("valid client: invalid server uuid") << "Friendly client" << QUuid::createUuid().toString() << TunnelProxyServer::TunnelProxyErrorInvalidUuid << true << QUuid().toString() << TunnelProxyServer::TunnelProxyErrorInvalidUuid;
|
||
QTest::newRow("invalid client uuid: valid server uuid") << "Friendly client" << QUuid().toString() << TunnelProxyServer::TunnelProxyErrorInvalidUuid << true << QUuid::createUuid().toString() << TunnelProxyServer::TunnelProxyErrorNoError;
|
||
QTest::newRow("invalid client uuid: invalid server uuid") << "Friendly client" << "hello again" << TunnelProxyServer::TunnelProxyErrorInvalidUuid << true << "it's me" << TunnelProxyServer::TunnelProxyErrorInvalidUuid;
|
||
}
|
||
|
||
void RemoteProxyTestsTunnelProxy::registerClient()
|
||
{
|
||
QFETCH(QString, name);
|
||
QFETCH(QString, uuid);
|
||
QFETCH(TunnelProxyServer::TunnelProxyError, expectedError);
|
||
QFETCH(bool, serverExists);
|
||
QFETCH(QString, serverUuid);
|
||
QFETCH(TunnelProxyServer::TunnelProxyError, expectedServerError);
|
||
|
||
// Start the server
|
||
startServer();
|
||
|
||
resetDebugCategories();
|
||
addDebugCategory("TunnelProxyServer.debug=true");
|
||
|
||
QSslSocket *socket = nullptr;
|
||
if (serverExists) {
|
||
QVariantMap serverParams;
|
||
serverParams.insert("serverName", "dummy server");
|
||
serverParams.insert("serverUuid", serverUuid);
|
||
|
||
// TCP socket
|
||
QPair<QVariant, QSslSocket *> result = invokeTcpSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterServer", serverParams);
|
||
QVariantMap response = result.first.toMap();
|
||
socket = result.second;
|
||
|
||
QVERIFY(!response.isEmpty());
|
||
QVERIFY(response.value("status").toString() == "success");
|
||
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
|
||
QVERIFY(response.value("params").toMap().contains("slipEnabled"));
|
||
//QVERIFY(response.value("params").toMap().value("slipEnabled").toBool()));
|
||
verifyTunnelProxyError(response, expectedServerError);
|
||
}
|
||
|
||
// Register a new client
|
||
QVariantMap params;
|
||
params.insert("clientName", name);
|
||
params.insert("clientUuid", uuid);
|
||
params.insert("serverUuid", serverUuid);
|
||
|
||
// Websocket
|
||
QVariantMap response = invokeWebSocketTunnelProxyApiCall("TunnelProxy.RegisterClient", params).toMap();
|
||
QVERIFY(!response.isEmpty());
|
||
QVERIFY(response.value("status").toString() == "success");
|
||
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
|
||
verifyTunnelProxyError(response, expectedError);
|
||
|
||
QTest::qWait(100);
|
||
|
||
// TCP Socket
|
||
response = invokeTcpSocketTunnelProxyApiCall("TunnelProxy.RegisterClient", params).toMap();
|
||
QVERIFY(!response.isEmpty());
|
||
QVERIFY(response.value("status").toString() == "success");
|
||
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
|
||
verifyTunnelProxyError(response, expectedError);
|
||
|
||
QTest::qWait(100);
|
||
|
||
if (socket) {
|
||
// Close the tcp socket
|
||
socket->close();
|
||
delete socket;
|
||
}
|
||
|
||
// Clean up
|
||
stopServer();
|
||
}
|
||
|
||
void RemoteProxyTestsTunnelProxy::testSlip_data()
|
||
{
|
||
QTest::addColumn<QByteArray>("data");
|
||
QTest::addColumn<bool>("success");
|
||
|
||
QTest::newRow("valid: a lot of special characters") << QByteArray::fromHex("C0AABBCCDDEEFF12A1B2C3D4E5FFC0DBDCDDAA") << true;
|
||
QTest::newRow("valid: start and end with END protocol") << QByteArray::fromHex("C0C0C0C0C0C0C0C0C0C0DDDDCDCDCDCDCDCD") << true;
|
||
QTest::newRow("valid: normal text with a special characters") << QByteArray("Foo Bar text describing 123456770ß2123#+@$%/(!\"W=$*'*") << true;
|
||
QTest::newRow("invalid: escape followed by nor escaped special character") << QByteArray::fromHex("AADB12FFC0") << false;
|
||
|
||
}
|
||
|
||
void RemoteProxyTestsTunnelProxy::testSlip()
|
||
{
|
||
QFETCH(QByteArray, data);
|
||
QFETCH(bool, success);
|
||
|
||
if (success) {
|
||
QByteArray serializedData = SlipDataProcessor::serializeData(data);
|
||
QVERIFY(serializedData.endsWith(0xC0));
|
||
QByteArray deserializedData = SlipDataProcessor::deserializeData(serializedData);
|
||
QVERIFY(deserializedData == data);
|
||
} else {
|
||
QByteArray deserializedData = SlipDataProcessor::deserializeData(data);
|
||
QVERIFY(deserializedData.isEmpty());
|
||
}
|
||
}
|
||
|
||
void RemoteProxyTestsTunnelProxy::registerServerDuplicated()
|
||
{
|
||
// Start the server
|
||
startServer();
|
||
|
||
resetDebugCategories();
|
||
addDebugCategory("TunnelProxyServer.debug=true");
|
||
addDebugCategory("JsonRpcTraffic.debug=true");
|
||
|
||
// Register a new server
|
||
QString serverName = "tunnel proxy server awesome nymea installation";
|
||
QUuid serverUuid = QUuid::createUuid();
|
||
|
||
QVariantMap params;
|
||
params.insert("serverName", serverName);
|
||
params.insert("serverUuid", serverUuid.toString());
|
||
|
||
// TCP socket
|
||
QPair<QVariant, QSslSocket *> result = invokeTcpSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterServer", params);
|
||
QVariantMap response = result.first.toMap();
|
||
QSslSocket *socket = result.second;
|
||
|
||
QVERIFY(!response.isEmpty());
|
||
QVERIFY(response.value("status").toString() == "success");
|
||
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
|
||
QVERIFY(response.value("params").toMap().contains("slipEnabled"));
|
||
QVERIFY(response.value("params").toMap().value("slipEnabled").toBool());
|
||
verifyTunnelProxyError(response);
|
||
|
||
// SLIP Should be enabled now
|
||
|
||
// Try to register again with the same uuid on the same socket
|
||
result = invokeTcpSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterServer", params, true, socket);
|
||
response = result.first.toMap();
|
||
QVERIFY(response.value("status").toString() == "success");
|
||
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
|
||
verifyTunnelProxyError(response, TunnelProxyServer::TunnelProxyErrorAlreadyRegistered);
|
||
|
||
QSignalSpy disconnectedTcpSpy(socket, &QSslSocket::disconnected);
|
||
QVERIFY(disconnectedTcpSpy.wait());
|
||
QVERIFY(disconnectedTcpSpy.count() == 1);
|
||
|
||
// Close the tcp socket
|
||
delete socket;
|
||
|
||
QTest::qWait(100);
|
||
|
||
// WebSocket
|
||
// Try to register from a websocket with the same uuid
|
||
QPair<QVariant, QWebSocket *> resultWebSocket = invokeWebSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterServer", params);
|
||
response = resultWebSocket.first.toMap();
|
||
QVERIFY(!response.isEmpty());
|
||
QVERIFY(response.value("status").toString() == "success");
|
||
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
|
||
verifyTunnelProxyError(response);
|
||
|
||
resetDebugCategories();
|
||
|
||
// Clean up
|
||
stopServer();
|
||
}
|
||
|
||
void RemoteProxyTestsTunnelProxy::registerClientDuplicated()
|
||
{
|
||
// Start the server
|
||
startServer();
|
||
|
||
resetDebugCategories();
|
||
addDebugCategory("TunnelProxyServer.debug=true");
|
||
addDebugCategory("JsonRpcTraffic.debug=true");
|
||
|
||
// Create the server and keep it up
|
||
QString serverName = "creative server name";
|
||
QUuid serverUuid = QUuid::createUuid();
|
||
QVariantMap serverParams;
|
||
serverParams.insert("serverName", serverName);
|
||
serverParams.insert("serverUuid", serverUuid.toString());
|
||
|
||
// TCP socket
|
||
QPair<QVariant, QSslSocket *> serverResult = invokeTcpSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterServer", serverParams);
|
||
QVariantMap response = serverResult.first.toMap();
|
||
QSslSocket *serverSocket = serverResult.second;
|
||
|
||
QVERIFY(!response.isEmpty());
|
||
QVERIFY(response.value("status").toString() == "success");
|
||
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
|
||
verifyTunnelProxyError(response);
|
||
|
||
// Connect a client TCP
|
||
QString clientName = "creative server name";
|
||
QUuid clientUuid = QUuid::createUuid();
|
||
QVariantMap clientParams;
|
||
clientParams.insert("clientName", serverName);
|
||
clientParams.insert("clientUuid", clientUuid.toString());
|
||
clientParams.insert("serverUuid", serverUuid.toString());
|
||
|
||
QPair<QVariant, QSslSocket *> clientResult = invokeTcpSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterClient", clientParams);
|
||
response = clientResult.first.toMap();
|
||
QSslSocket *clientSocketTcp = clientResult.second;
|
||
QVERIFY(!response.isEmpty());
|
||
QVERIFY(response.value("status").toString() == "success");
|
||
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
|
||
verifyTunnelProxyError(response);
|
||
|
||
// Connect another client WebSocket
|
||
QPair<QVariant, QSslSocket *> clientResultWS = invokeTcpSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterClient", clientParams);
|
||
response = clientResultWS.first.toMap();
|
||
QSslSocket *clientSocketWs = clientResultWS.second;
|
||
QVERIFY(!response.isEmpty());
|
||
QVERIFY(response.value("status").toString() == "success");
|
||
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
|
||
verifyTunnelProxyError(response, TunnelProxyServer::TunnelProxyErrorAlreadyRegistered);
|
||
|
||
// CleanUp
|
||
if (clientSocketTcp) {
|
||
// Close the tcp socket
|
||
clientSocketTcp->close();
|
||
delete clientSocketTcp;
|
||
}
|
||
|
||
if (clientSocketWs) {
|
||
// Close the tcp socket
|
||
clientSocketWs->close();
|
||
delete clientSocketWs;
|
||
}
|
||
|
||
if (serverSocket) {
|
||
// Close the tcp socket
|
||
serverSocket->close();
|
||
delete serverSocket;
|
||
}
|
||
|
||
resetDebugCategories();
|
||
|
||
// Clean up
|
||
stopServer();
|
||
}
|
||
|
||
void RemoteProxyTestsTunnelProxy::crossRegisterServerClient()
|
||
{
|
||
// Start the server
|
||
startServer();
|
||
|
||
resetDebugCategories();
|
||
resetDebugCategories();
|
||
addDebugCategory("TunnelProxyServer.debug=true");
|
||
addDebugCategory("TunnelProxyServerTraffic.debug=true");
|
||
addDebugCategory("JsonRpcTraffic.debug=true");
|
||
|
||
// Create the server and keep it up
|
||
QString serverName = "creative server name";
|
||
QUuid serverUuid = QUuid::createUuid();
|
||
QVariantMap serverParams;
|
||
serverParams.insert("serverName", serverName);
|
||
serverParams.insert("serverUuid", serverUuid.toString());
|
||
|
||
// TCP server
|
||
QPair<QVariant, QSslSocket *> serverResult = invokeTcpSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterServer", serverParams);
|
||
QVariantMap response = serverResult.first.toMap();
|
||
QSslSocket *serverSocket = serverResult.second;
|
||
QVERIFY(!response.isEmpty());
|
||
QVERIFY(response.value("status").toString() == "success");
|
||
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
|
||
verifyTunnelProxyError(response);
|
||
|
||
// SLIP is enabled now
|
||
|
||
// Now try to register as client
|
||
QVariantMap clientParams;
|
||
clientParams.insert("clientName", "creative client name");
|
||
clientParams.insert("clientUuid", QUuid::createUuid().toString());
|
||
clientParams.insert("serverUuid", serverUuid.toString());
|
||
|
||
QPair<QVariant, QSslSocket *> result = invokeTcpSocketTunnelProxyApiCallPersistant("TunnelProxy.RegisterClient", clientParams, true, serverSocket);
|
||
response = result.first.toMap();
|
||
QVERIFY(!response.isEmpty());
|
||
QVERIFY(response.value("status").toString() == "success");
|
||
QVERIFY(response.value("params").toMap().contains("tunnelProxyError"));
|
||
verifyTunnelProxyError(response, TunnelProxyServer::TunnelProxyErrorAlreadyRegistered);
|
||
|
||
QSignalSpy disconnectedSpy(serverSocket, &QSslSocket::disconnected);
|
||
QVERIFY(disconnectedSpy.wait());
|
||
QVERIFY(disconnectedSpy.count() == 1);
|
||
|
||
serverSocket->close();
|
||
delete serverSocket;
|
||
|
||
resetDebugCategories();
|
||
|
||
// Clean up
|
||
stopServer();
|
||
}
|
||
|
||
void RemoteProxyTestsTunnelProxy::testTunnelProxyServer()
|
||
{
|
||
// Start the server
|
||
startServer();
|
||
|
||
resetDebugCategories();
|
||
addDebugCategory("TunnelProxyServer.debug=true");
|
||
addDebugCategory("TunnelProxyServerTraffic.debug=true");
|
||
addDebugCategory("JsonRpcTraffic.debug=true");
|
||
addDebugCategory("TunnelProxySocketServer.debug=true");
|
||
addDebugCategory("TunnelProxyRemoteConnection.debug=true");
|
||
addDebugCategory("TunnelProxyRemoteConnectionTraffic.debug=true");
|
||
addDebugCategory("RemoteProxyClientJsonRpcTraffic.debug=true");
|
||
|
||
// Tunnel proxy socket server
|
||
QString serverName = "SuperDuper server name";
|
||
QUuid serverUuid = QUuid::createUuid();
|
||
|
||
TunnelProxySocketServer *tunnelProxyServer = new TunnelProxySocketServer(serverUuid, serverName, this);
|
||
connect(tunnelProxyServer, &TunnelProxySocketServer::sslErrors, this, [=](const QList<QSslError> &errors){
|
||
tunnelProxyServer->ignoreSslErrors(errors);
|
||
});
|
||
|
||
tunnelProxyServer->startServer(m_serverUrlTunnelProxyTcp);
|
||
|
||
QSignalSpy serverRunningSpy(tunnelProxyServer, &TunnelProxySocketServer::runningChanged);
|
||
serverRunningSpy.wait();
|
||
QVERIFY(serverRunningSpy.count() == 1);
|
||
QList<QVariant> arguments = serverRunningSpy.takeFirst();
|
||
QVERIFY(arguments.at(0).toBool() == true);
|
||
QVERIFY(tunnelProxyServer->running());
|
||
|
||
QCOMPARE(tunnelProxyServer->serverUrl(), m_serverUrlTunnelProxyTcp);
|
||
QCOMPARE(tunnelProxyServer->remoteProxyServer(), QString(SERVER_NAME_STRING));
|
||
QCOMPARE(tunnelProxyServer->remoteProxyServerName(), Engine::instance()->configuration()->serverName());
|
||
QCOMPARE(tunnelProxyServer->remoteProxyServerVersion(), QString(SERVER_VERSION_STRING));
|
||
QCOMPARE(tunnelProxyServer->remoteProxyApiVersion(), QString(API_VERSION_STRING));
|
||
|
||
|
||
// Tunnel proxy client connection
|
||
QString clientName = "Awesome client name";
|
||
QUuid clientUuid = QUuid::createUuid();
|
||
|
||
TunnelProxyRemoteConnection *clientConnection = new TunnelProxyRemoteConnection(clientUuid, clientName, this);
|
||
connect(clientConnection, &TunnelProxyRemoteConnection::sslErrors, this, [=](const QList<QSslError> &errors){
|
||
clientConnection->ignoreSslErrors(errors);
|
||
});
|
||
|
||
clientConnection->connectServer(m_serverUrlTunnelProxyTcp, serverUuid);
|
||
|
||
QSignalSpy clientConnectedSpy(tunnelProxyServer, &TunnelProxySocketServer::clientConnected);
|
||
QVERIFY(clientConnectedSpy.wait());
|
||
QVERIFY(clientConnectedSpy.count() == 1);
|
||
arguments = clientConnectedSpy.takeFirst();
|
||
TunnelProxySocket *tunnelProxySocket = arguments.at(0).value<TunnelProxySocket *>();
|
||
QVERIFY(tunnelProxySocket->clientName() == clientName);
|
||
QVERIFY(tunnelProxySocket->clientUuid() == clientUuid);
|
||
QVERIFY(!tunnelProxySocket->clientPeerAddress().isNull());
|
||
QVERIFY(tunnelProxySocket->socketAddress() != 0x0000 && tunnelProxySocket->socketAddress() != 0xFFFF);
|
||
QVERIFY(tunnelProxySocket->connected());
|
||
|
||
QCOMPARE(clientConnection->serverUrl(), m_serverUrlTunnelProxyTcp);
|
||
QCOMPARE(clientConnection->remoteProxyServer(), QString(SERVER_NAME_STRING));
|
||
QCOMPARE(clientConnection->remoteProxyServerName(), Engine::instance()->configuration()->serverName());
|
||
QCOMPARE(clientConnection->remoteProxyServerVersion(), QString(SERVER_VERSION_STRING));
|
||
QCOMPARE(clientConnection->remoteProxyApiVersion(), QString(API_VERSION_STRING));
|
||
|
||
// We have a remote connection, now disconnect the client and verify the socket dissapears on th server side
|
||
QSignalSpy clientDisconnectedSpy(tunnelProxyServer, &TunnelProxySocketServer::clientDisconnected);
|
||
|
||
clientConnection->disconnectServer();
|
||
|
||
QVERIFY(clientDisconnectedSpy.wait());
|
||
QVERIFY(clientDisconnectedSpy.count() == 1);
|
||
arguments = clientDisconnectedSpy.takeFirst();
|
||
tunnelProxySocket = arguments.at(0).value<TunnelProxySocket *>();
|
||
QVERIFY(tunnelProxySocket->clientName() == clientName);
|
||
QVERIFY(tunnelProxySocket->clientUuid() == clientUuid);
|
||
QVERIFY(!tunnelProxySocket->clientPeerAddress().isNull());
|
||
QVERIFY(tunnelProxySocket->socketAddress() != 0x0000 && tunnelProxySocket->socketAddress() != 0xFFFF);
|
||
QVERIFY(!tunnelProxySocket->connected());
|
||
|
||
|
||
// Stop the server connection and verify the client gets disconnected
|
||
QSignalSpy serverNotRunningSpy(tunnelProxyServer, &TunnelProxySocketServer::runningChanged);
|
||
|
||
tunnelProxyServer->stopServer();
|
||
|
||
// Verify the remote connection is disconnected
|
||
serverNotRunningSpy.wait();
|
||
QVERIFY(serverNotRunningSpy.count() == 1);
|
||
arguments = serverNotRunningSpy.takeFirst();
|
||
QVERIFY(arguments.at(0).toBool() == false);
|
||
QVERIFY(!tunnelProxyServer->running());
|
||
|
||
// Clean up
|
||
tunnelProxyServer->deleteLater();
|
||
clientConnection->deleteLater();
|
||
|
||
resetDebugCategories();
|
||
|
||
stopServer();
|
||
}
|
||
|
||
void RemoteProxyTestsTunnelProxy::testTunnelProxyClient()
|
||
{
|
||
// Start the server
|
||
startServer();
|
||
|
||
resetDebugCategories();
|
||
addDebugCategory("TunnelProxyServer.debug=true");
|
||
addDebugCategory("TunnelProxyServerTraffic.debug=true");
|
||
addDebugCategory("JsonRpcTraffic.debug=true");
|
||
addDebugCategory("TunnelProxySocketServer.debug=true");
|
||
addDebugCategory("TunnelProxyRemoteConnection.debug=true");
|
||
addDebugCategory("RemoteProxyClientJsonRpcTraffic.debug=true");
|
||
|
||
// Tunnel proxy socket server
|
||
QString serverName = "SuperDuper server name";
|
||
QUuid serverUuid = QUuid::createUuid();
|
||
|
||
TunnelProxySocketServer *tunnelProxyServer = new TunnelProxySocketServer(serverUuid, serverName, this);
|
||
connect(tunnelProxyServer, &TunnelProxySocketServer::sslErrors, this, [=](const QList<QSslError> &errors){
|
||
qDebug() << errors;
|
||
tunnelProxyServer->ignoreSslErrors(errors);
|
||
});
|
||
|
||
tunnelProxyServer->startServer(m_serverUrlTunnelProxyTcp);
|
||
|
||
QSignalSpy serverRunningSpy(tunnelProxyServer, &TunnelProxySocketServer::runningChanged);
|
||
serverRunningSpy.wait();
|
||
QVERIFY(serverRunningSpy.count() == 1);
|
||
QList<QVariant> arguments = serverRunningSpy.takeFirst();
|
||
QVERIFY(arguments.at(0).toBool() == true);
|
||
QVERIFY(tunnelProxyServer->running());
|
||
|
||
QCOMPARE(tunnelProxyServer->serverUrl(), m_serverUrlTunnelProxyTcp);
|
||
QCOMPARE(tunnelProxyServer->remoteProxyServer(), QString(SERVER_NAME_STRING));
|
||
QCOMPARE(tunnelProxyServer->remoteProxyServerName(), Engine::instance()->configuration()->serverName());
|
||
QCOMPARE(tunnelProxyServer->remoteProxyServerVersion(), QString(SERVER_VERSION_STRING));
|
||
QCOMPARE(tunnelProxyServer->remoteProxyApiVersion(), QString(API_VERSION_STRING));
|
||
|
||
|
||
// Tunnel proxy client connection
|
||
QString clientName = "Awesome client name";
|
||
QUuid clientUuid = QUuid::createUuid();
|
||
|
||
TunnelProxyRemoteConnection *clientConnection = new TunnelProxyRemoteConnection(clientUuid, clientName, this);
|
||
connect(clientConnection, &TunnelProxyRemoteConnection::sslErrors, this, [=](const QList<QSslError> &errors){
|
||
clientConnection->ignoreSslErrors(errors);
|
||
});
|
||
|
||
clientConnection->connectServer(m_serverUrlTunnelProxyTcp, serverUuid);
|
||
|
||
QSignalSpy clientRemoteConnectedSpy(clientConnection, &TunnelProxyRemoteConnection::remoteConnectedChanged);
|
||
QVERIFY(clientRemoteConnectedSpy.wait());
|
||
QVERIFY(clientRemoteConnectedSpy.count() == 1);
|
||
arguments = clientRemoteConnectedSpy.takeFirst();
|
||
QVERIFY(arguments.at(0).toBool() == true);
|
||
QVERIFY(clientConnection->remoteConnected());
|
||
|
||
QCOMPARE(clientConnection->serverUrl(), m_serverUrlTunnelProxyTcp);
|
||
QCOMPARE(clientConnection->remoteProxyServer(), QString(SERVER_NAME_STRING));
|
||
QCOMPARE(clientConnection->remoteProxyServerName(), Engine::instance()->configuration()->serverName());
|
||
QCOMPARE(clientConnection->remoteProxyServerVersion(), QString(SERVER_VERSION_STRING));
|
||
QCOMPARE(clientConnection->remoteProxyApiVersion(), QString(API_VERSION_STRING));
|
||
|
||
// Stop the server and make sure the client gets disconnected
|
||
tunnelProxyServer->stopServer();
|
||
|
||
QSignalSpy clientRemoteDisonnectedSpy(clientConnection, &TunnelProxyRemoteConnection::remoteConnectedChanged);
|
||
QVERIFY(clientRemoteDisonnectedSpy.wait());
|
||
QVERIFY(clientRemoteDisonnectedSpy.count() == 1);
|
||
arguments = clientRemoteDisonnectedSpy.takeFirst();
|
||
QVERIFY(arguments.at(0).toBool() == false);
|
||
QVERIFY(!clientConnection->remoteConnected());
|
||
|
||
|
||
// Clean up
|
||
tunnelProxyServer->deleteLater();
|
||
clientConnection->deleteLater();
|
||
|
||
resetDebugCategories();
|
||
|
||
stopServer();
|
||
}
|
||
|
||
void RemoteProxyTestsTunnelProxy::testTunnelProxyServerSocketDisconnect()
|
||
{
|
||
// Start the server
|
||
startServer();
|
||
|
||
resetDebugCategories();
|
||
addDebugCategory("TunnelProxyServer.debug=true");
|
||
addDebugCategory("TunnelProxyServerTraffic.debug=true");
|
||
addDebugCategory("JsonRpcTraffic.debug=true");
|
||
addDebugCategory("TunnelProxySocketServer.debug=true");
|
||
addDebugCategory("TunnelProxyRemoteConnection.debug=true");
|
||
addDebugCategory("TunnelProxyRemoteConnectionTraffic.debug=true");
|
||
addDebugCategory("RemoteProxyClientJsonRpcTraffic.debug=true");
|
||
|
||
// Tunnel proxy socket server
|
||
QString serverName = "SuperDuper server name";
|
||
QUuid serverUuid = QUuid::createUuid();
|
||
|
||
TunnelProxySocketServer *tunnelProxyServer = new TunnelProxySocketServer(serverUuid, serverName, this);
|
||
connect(tunnelProxyServer, &TunnelProxySocketServer::sslErrors, this, [=](const QList<QSslError> &errors){
|
||
tunnelProxyServer->ignoreSslErrors(errors);
|
||
});
|
||
|
||
tunnelProxyServer->startServer(m_serverUrlTunnelProxyTcp);
|
||
|
||
QSignalSpy serverRunningSpy(tunnelProxyServer, &TunnelProxySocketServer::runningChanged);
|
||
serverRunningSpy.wait();
|
||
QVERIFY(serverRunningSpy.count() == 1);
|
||
QList<QVariant> arguments = serverRunningSpy.takeFirst();
|
||
QVERIFY(arguments.at(0).toBool() == true);
|
||
QVERIFY(tunnelProxyServer->running());
|
||
|
||
QCOMPARE(tunnelProxyServer->serverUrl(), m_serverUrlTunnelProxyTcp);
|
||
QCOMPARE(tunnelProxyServer->remoteProxyServer(), QString(SERVER_NAME_STRING));
|
||
QCOMPARE(tunnelProxyServer->remoteProxyServerName(), Engine::instance()->configuration()->serverName());
|
||
QCOMPARE(tunnelProxyServer->remoteProxyServerVersion(), QString(SERVER_VERSION_STRING));
|
||
QCOMPARE(tunnelProxyServer->remoteProxyApiVersion(), QString(API_VERSION_STRING));
|
||
|
||
|
||
// Tunnel proxy client connection
|
||
QString clientName = "Awesome client name";
|
||
QUuid clientUuid = QUuid::createUuid();
|
||
|
||
TunnelProxyRemoteConnection *clientConnection = new TunnelProxyRemoteConnection(clientUuid, clientName, this);
|
||
connect(clientConnection, &TunnelProxyRemoteConnection::sslErrors, this, [=](const QList<QSslError> &errors){
|
||
clientConnection->ignoreSslErrors(errors);
|
||
});
|
||
|
||
clientConnection->connectServer(m_serverUrlTunnelProxyTcp, serverUuid);
|
||
|
||
QSignalSpy clientConnectedSpy(tunnelProxyServer, &TunnelProxySocketServer::clientConnected);
|
||
QVERIFY(clientConnectedSpy.wait());
|
||
QVERIFY(clientConnectedSpy.count() == 1);
|
||
arguments = clientConnectedSpy.takeFirst();
|
||
TunnelProxySocket *tunnelProxySocket = arguments.at(0).value<TunnelProxySocket *>();
|
||
QVERIFY(tunnelProxySocket->clientName() == clientName);
|
||
QVERIFY(tunnelProxySocket->clientUuid() == clientUuid);
|
||
QVERIFY(!tunnelProxySocket->clientPeerAddress().isNull());
|
||
QVERIFY(tunnelProxySocket->socketAddress() != 0x0000 && tunnelProxySocket->socketAddress() != 0xFFFF);
|
||
QVERIFY(tunnelProxySocket->connected());
|
||
|
||
QCOMPARE(clientConnection->serverUrl(), m_serverUrlTunnelProxyTcp);
|
||
QCOMPARE(clientConnection->remoteProxyServer(), QString(SERVER_NAME_STRING));
|
||
QCOMPARE(clientConnection->remoteProxyServerName(), Engine::instance()->configuration()->serverName());
|
||
QCOMPARE(clientConnection->remoteProxyServerVersion(), QString(SERVER_VERSION_STRING));
|
||
QCOMPARE(clientConnection->remoteProxyApiVersion(), QString(API_VERSION_STRING));
|
||
QVERIFY(clientConnection->remoteConnected() == true);
|
||
|
||
// Now request the TunnelProxySocket to disconnect and verify the client Connection really gets disconnected
|
||
QSignalSpy clientRemoteDisonnectedSpy(clientConnection, &TunnelProxyRemoteConnection::remoteConnectedChanged);
|
||
|
||
tunnelProxySocket->disconnectSocket();
|
||
|
||
QVERIFY(clientRemoteDisonnectedSpy.wait());
|
||
QVERIFY(clientRemoteDisonnectedSpy.count() == 1);
|
||
arguments = clientRemoteDisonnectedSpy.takeFirst();
|
||
QVERIFY(arguments.at(0).toBool() == false);
|
||
QVERIFY(!clientConnection->remoteConnected());
|
||
|
||
QTest::qWait(100);
|
||
|
||
// Clean up
|
||
tunnelProxyServer->deleteLater();
|
||
clientConnection->deleteLater();
|
||
|
||
resetDebugCategories();
|
||
|
||
stopServer();
|
||
}
|
||
|
||
void RemoteProxyTestsTunnelProxy::tunnelProxyEndToEndTest()
|
||
{
|
||
// Start the server
|
||
startServer();
|
||
|
||
resetDebugCategories();
|
||
addDebugCategory("TunnelProxyServer.debug=true");
|
||
addDebugCategory("TunnelProxyServerTraffic.debug=true");
|
||
addDebugCategory("JsonRpcTraffic.debug=true");
|
||
addDebugCategory("TunnelProxySocketServer.debug=true");
|
||
addDebugCategory("TunnelProxyRemoteConnection.debug=true");
|
||
addDebugCategory("TunnelProxyRemoteConnectionTraffic.debug=true");
|
||
addDebugCategory("RemoteProxyClientJsonRpcTraffic.debug=true");
|
||
|
||
// ** Create the server **
|
||
QString serverName = "nymea server";
|
||
QUuid serverUuid = QUuid::createUuid();
|
||
|
||
TunnelProxySocketServer *tunnelProxyServer = new TunnelProxySocketServer(serverUuid, serverName, this);
|
||
connect(tunnelProxyServer, &TunnelProxySocketServer::sslErrors, this, [=](const QList<QSslError> &errors){
|
||
tunnelProxyServer->ignoreSslErrors(errors);
|
||
});
|
||
|
||
tunnelProxyServer->startServer(m_serverUrlTunnelProxyTcp);
|
||
|
||
QSignalSpy serverRunningSpy(tunnelProxyServer, &TunnelProxySocketServer::runningChanged);
|
||
serverRunningSpy.wait();
|
||
QVERIFY(serverRunningSpy.count() == 1);
|
||
QList<QVariant> arguments = serverRunningSpy.takeFirst();
|
||
QVERIFY(arguments.at(0).toBool() == true);
|
||
QVERIFY(tunnelProxyServer->running());
|
||
QCOMPARE(tunnelProxyServer->serverUrl(), m_serverUrlTunnelProxyTcp);
|
||
QCOMPARE(tunnelProxyServer->remoteProxyServer(), QString(SERVER_NAME_STRING));
|
||
QCOMPARE(tunnelProxyServer->remoteProxyServerName(), Engine::instance()->configuration()->serverName());
|
||
QCOMPARE(tunnelProxyServer->remoteProxyServerVersion(), QString(SERVER_VERSION_STRING));
|
||
QCOMPARE(tunnelProxyServer->remoteProxyApiVersion(), QString(API_VERSION_STRING));
|
||
|
||
|
||
// ** Remote connection 1 **
|
||
|
||
QString clientOneName = "Client one";
|
||
QUuid clientOneUuid = QUuid::createUuid();
|
||
TunnelProxyRemoteConnection *remoteConnectionOne = new TunnelProxyRemoteConnection(clientOneUuid, clientOneName, this);
|
||
connect(remoteConnectionOne, &TunnelProxyRemoteConnection::sslErrors, this, [=](const QList<QSslError> &errors){
|
||
remoteConnectionOne->ignoreSslErrors(errors);
|
||
});
|
||
|
||
remoteConnectionOne->connectServer(m_serverUrlTunnelProxyTcp, serverUuid);
|
||
|
||
// ** Tunnel proxy server socket 1 **
|
||
QSignalSpy remoteConnectedOneSpy(tunnelProxyServer, &TunnelProxySocketServer::clientConnected);
|
||
QVERIFY(remoteConnectedOneSpy.wait());
|
||
QVERIFY(remoteConnectedOneSpy.count() == 1);
|
||
arguments = remoteConnectedOneSpy.takeFirst();
|
||
|
||
TunnelProxySocket *tunnelProxySocketOne = arguments.at(0).value<TunnelProxySocket *>();
|
||
QVERIFY(tunnelProxySocketOne->clientName() == clientOneName);
|
||
QVERIFY(tunnelProxySocketOne->clientUuid() == clientOneUuid);
|
||
QVERIFY(!tunnelProxySocketOne->clientPeerAddress().isNull());
|
||
QVERIFY(tunnelProxySocketOne->socketAddress() != 0x0000 && tunnelProxySocketOne->socketAddress() != 0xFFFF);
|
||
QVERIFY(tunnelProxySocketOne->connected());
|
||
|
||
qDebug() << "Have socket one" << tunnelProxySocketOne;
|
||
|
||
// ** Send data in both directions
|
||
QByteArray testData("#sdföiabi23u4b34b598gvndafjibnföQIUH34982HRIPURBFÖWLKDÜOQw9h934utbf ljBiH9FBLAJF RF AF,A§uu)(\"§)§(u$)($=$(((($((!");
|
||
|
||
// Socket -> Remote connection
|
||
QSignalSpy remoteConnectionOneDataSpy(remoteConnectionOne, &TunnelProxyRemoteConnection::dataReady);
|
||
tunnelProxySocketOne->writeData(testData);
|
||
QVERIFY(remoteConnectionOneDataSpy.wait());
|
||
QVERIFY(remoteConnectionOneDataSpy.count() == 1);
|
||
arguments = remoteConnectionOneDataSpy.takeFirst();
|
||
QByteArray receivedTestData = arguments.at(0).toByteArray();
|
||
QVERIFY(receivedTestData == testData);
|
||
|
||
|
||
// Remote connection -> Socket
|
||
QByteArray testData2("The biggest decision in life is about changing your life through changing your mind. – Albert Schweitzer");
|
||
QSignalSpy tunnelProxySocketOneDataSpy(tunnelProxySocketOne, &TunnelProxySocket::dataReceived);
|
||
remoteConnectionOne->sendData(testData2);
|
||
QVERIFY(tunnelProxySocketOneDataSpy.wait());
|
||
QVERIFY(tunnelProxySocketOneDataSpy.count() == 1);
|
||
arguments = tunnelProxySocketOneDataSpy.takeFirst();
|
||
QByteArray receivedTestData2 = arguments.at(0).toByteArray();
|
||
QVERIFY(receivedTestData2 == testData2);
|
||
|
||
|
||
// ** Remote connection 2 **
|
||
|
||
QString clientTwoName = "Client two";
|
||
QUuid clientTwoUuid = QUuid::createUuid();
|
||
TunnelProxyRemoteConnection *remoteConnectionTwo = new TunnelProxyRemoteConnection(clientTwoUuid, clientTwoName, this);
|
||
connect(remoteConnectionTwo, &TunnelProxyRemoteConnection::sslErrors, this, [=](const QList<QSslError> &errors){
|
||
remoteConnectionTwo->ignoreSslErrors(errors);
|
||
});
|
||
|
||
remoteConnectionTwo->connectServer(m_serverUrlTunnelProxyTcp, serverUuid);
|
||
|
||
// ** Tunnel proxy server socket 2 **
|
||
QSignalSpy remoteConnectedTwoSpy(tunnelProxyServer, &TunnelProxySocketServer::clientConnected);
|
||
QVERIFY(remoteConnectedTwoSpy.wait());
|
||
QVERIFY(remoteConnectedTwoSpy.count() == 1);
|
||
arguments = remoteConnectedTwoSpy.takeFirst();
|
||
|
||
TunnelProxySocket *tunnelProxySocketTwo = arguments.at(0).value<TunnelProxySocket *>();
|
||
QVERIFY(tunnelProxySocketTwo->clientName() == clientTwoName);
|
||
QVERIFY(tunnelProxySocketTwo->clientUuid() == clientTwoUuid);
|
||
QVERIFY(!tunnelProxySocketTwo->clientPeerAddress().isNull());
|
||
QVERIFY(tunnelProxySocketTwo->socketAddress() != 0x0000 && tunnelProxySocketTwo->socketAddress() != 0xFFFF);
|
||
QVERIFY(tunnelProxySocketTwo->connected());
|
||
|
||
qDebug() << "Have socket two" << tunnelProxySocketTwo;
|
||
|
||
// ** Send data in both directions
|
||
|
||
// Socket -> Remote connection
|
||
QSignalSpy remoteConnectionTwoDataSpy(remoteConnectionTwo, &TunnelProxyRemoteConnection::dataReady);
|
||
tunnelProxySocketTwo->writeData(testData);
|
||
QVERIFY(remoteConnectionTwoDataSpy.wait());
|
||
QVERIFY(remoteConnectionTwoDataSpy.count() == 1);
|
||
arguments = remoteConnectionTwoDataSpy.takeFirst();
|
||
receivedTestData = arguments.at(0).toByteArray();
|
||
QVERIFY(receivedTestData == testData);
|
||
|
||
// Remote connection -> Socket
|
||
QSignalSpy tunnelProxySocketTwoDataSpy(tunnelProxySocketTwo, &TunnelProxySocket::dataReceived);
|
||
remoteConnectionTwo->sendData(testData2);
|
||
QVERIFY(tunnelProxySocketTwoDataSpy.wait());
|
||
QVERIFY(tunnelProxySocketTwoDataSpy.count() == 1);
|
||
arguments = tunnelProxySocketTwoDataSpy.takeFirst();
|
||
receivedTestData2 = arguments.at(0).toByteArray();
|
||
QVERIFY(receivedTestData2 == testData2);
|
||
|
||
Engine::instance()->tunnelProxyServer()->stopServer();
|
||
|
||
QTest::qWait(100);
|
||
|
||
QVERIFY(!tunnelProxyServer->running());
|
||
QVERIFY(!remoteConnectionOne->remoteConnected());
|
||
QVERIFY(!remoteConnectionTwo->remoteConnected());
|
||
|
||
// Clean up
|
||
tunnelProxyServer->deleteLater();
|
||
remoteConnectionOne->deleteLater();
|
||
remoteConnectionTwo->deleteLater();
|
||
|
||
resetDebugCategories();
|
||
|
||
stopServer();
|
||
|
||
}
|
||
|
||
|
||
QTEST_MAIN(RemoteProxyTestsTunnelProxy)
|