diff options
Diffstat (limited to 'tests/manual/wasm/network/sockify_sockets_auto')
3 files changed, 359 insertions, 0 deletions
diff --git a/tests/manual/wasm/network/sockify_sockets_auto/CMakeLists.txt b/tests/manual/wasm/network/sockify_sockets_auto/CMakeLists.txt new file mode 100644 index 0000000000..68a3993778 --- /dev/null +++ b/tests/manual/wasm/network/sockify_sockets_auto/CMakeLists.txt @@ -0,0 +1,24 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause +qt_internal_add_manual_test(sockify_sockets_auto + SOURCES + main.cpp + ../../qtwasmtestlib/qtwasmtestlib.cpp + LIBRARIES + Qt::Core + Qt::Network +) + +include_directories(../../qtwasmtestlib/) + +add_custom_command( + TARGET sockify_sockets_auto POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/sockify_sockets_auto.html + ${CMAKE_CURRENT_BINARY_DIR}/sockify_sockets_auto.html) + +add_custom_command( + TARGET sockify_sockets_auto POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/../../qtwasmtestlib/qtwasmtestlib.js + ${CMAKE_CURRENT_BINARY_DIR}/qtwasmtestlib.js) diff --git a/tests/manual/wasm/network/sockify_sockets_auto/main.cpp b/tests/manual/wasm/network/sockify_sockets_auto/main.cpp new file mode 100644 index 0000000000..b6aa232b4a --- /dev/null +++ b/tests/manual/wasm/network/sockify_sockets_auto/main.cpp @@ -0,0 +1,318 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <qtwasmtestlib.h> +#include <QtCore> +#include <QtNetwork> + +const int socketWait = 1000; +const QString hostName = "localhost"; +const int port = 1515; + +class SockifySocketsTest: public QObject +{ + Q_OBJECT + +private slots: + void echo(); + void echoMultipleMessages(); + void echoMultipleSockets(); + void remoteClose(); + +#if QT_CONFIG(thread) + void thread_echo(); + void thread_remoteClose(); + void thread_echoMultipleSockets(); +#endif + +#ifdef QT_HAVE_EMSCRIPTEN_ASYNCIFY + void asyncify_echo(); + void asyncify_remoteClose(); +#endif +}; + +class CompleteTestFunctionRefGuard { +public: + CompleteTestFunctionRefGuard(CompleteTestFunctionRefGuard const&) = delete; + CompleteTestFunctionRefGuard& operator=(CompleteTestFunctionRefGuard const&) = delete; + + static CompleteTestFunctionRefGuard *create() { + return new CompleteTestFunctionRefGuard(); + } + + void ref() { + QMutexLocker lock(&mutex); + ++counter; + } + + void deref() { + bool itsTheFinalDeref = [this] { + QMutexLocker lock(&mutex); + return --counter == 0; + }(); + + if (itsTheFinalDeref) { + delete this; + QtWasmTest::completeTestFunction(); + } + } +private: + CompleteTestFunctionRefGuard() { }; + + QMutex mutex; + int counter = 0; +}; + +#if QT_CONFIG(thread) + +class TestThread : public QThread +{ +public: + static QThread *create(std::function<void()> started, std::function<void()> finished) + { + TestThread *thread = new TestThread(); + connect(thread, &QThread::started, [started]() { + started(); + }); + connect(thread, &QThread::finished, [thread, finished]() { + finished(); + thread->deleteLater(); + }); + thread->start(); + return thread; + } +}; + +#endif + +void blockingEchoTest() +{ + QTcpSocket socket; + socket.connectToHost(hostName, port); + if (!socket.waitForConnected(socketWait)) + qFatal("socket connect error"); + + QByteArray message = "Hello, echo server!"; + + QByteArray command = "echo:" + message + ';'; + socket.write(command); + socket.flush(); + + socket.waitForReadyRead(socketWait); + QByteArray expectedReply = message + ';'; + QByteArray reply = socket.readAll(); + if (reply != expectedReply) + qFatal("echo_multiple received incorrect reply"); + socket.disconnectFromHost(); +} + +void blockingRemoteClose() +{ + QTcpSocket socket; + + qDebug() << "## connectToHost"; + socket.connectToHost(hostName, port); + + qDebug() << "## waitForConnected"; + socket.waitForConnected(socketWait); + socket.write("close;"); + socket.flush(); + + qDebug() << "## waitForBytesWritten"; + socket.waitForBytesWritten(socketWait); + + qDebug() << "## waitForReadyRead"; + socket.waitForReadyRead(200); + + qDebug() << "## waitForDisconnected"; + socket.waitForDisconnected(socketWait); + qDebug() << "## done"; +} + +// Verify that sending one echo command and receiving the reply works +void SockifySocketsTest::echo() +{ + QTcpSocket *socket = new QTcpSocket(); + socket->connectToHost(hostName, port); + + QByteArray message = "Hello, echo server!"; + + QObject::connect(socket, &QAbstractSocket::connected, [socket, message]() { + QByteArray command = "echo:" + message + ';'; + socket->write(command); + socket->flush(); + }); + + QByteArray *reply = new QByteArray(); + QObject::connect(socket, &QIODevice::readyRead, [socket, reply, message]() { + *reply += socket->readAll(); + if (reply->contains(';')) { + bool match = (*reply == message + ';'); + socket->disconnectFromHost(); + socket->deleteLater(); + delete reply; + QtWasmTest::completeTestFunction(match ? QtWasmTest::TestResult::Pass : QtWasmTest::TestResult::Fail, std::string()); + } + }); +} + +void SockifySocketsTest::echoMultipleMessages() +{ + const int count = 20; + + QTcpSocket *socket = new QTcpSocket(); + socket->connectToHost(hostName, port); + QByteArray message = "Hello, echo server!"; + + QObject::connect(socket, &QAbstractSocket::connected, [socket, message]() { + QByteArray command = "echo:" + message + ';'; + for (int i = 0; i < count; ++i) { + quint64 written = socket->write(command); + if (written != quint64(command.size())) + qFatal("Unable to write to socket"); + } + socket->flush(); + }); + + QByteArray expectedReply; + for (int i = 0; i < count; ++i) + expectedReply += (message + ';'); + QByteArray *receivedReply = new QByteArray; + QObject::connect(socket, &QIODevice::readyRead, [socket, receivedReply, expectedReply]() { + QByteArray reply = socket->readAll(); + *receivedReply += reply; + + if (*receivedReply == expectedReply) { + socket->disconnectFromHost(); + socket->deleteLater(); + delete receivedReply; + QtWasmTest::completeTestFunction(); + } + }); +} + +void SockifySocketsTest::echoMultipleSockets() +{ + const int connections = 5; + auto guard = CompleteTestFunctionRefGuard::create(); + + QByteArray message = "Hello, echo server!"; + + for (int i = 0; i < connections; ++i) { + guard->ref(); + + QTcpSocket *socket = new QTcpSocket(); + socket->connectToHost(hostName, port); + + QObject::connect(socket, &QAbstractSocket::connected, [socket, message]() { + QByteArray command = "echo:" + message + ';'; + socket->write(command); + socket->flush(); + }); + + QObject::connect(socket, &QIODevice::readyRead, [guard, socket, message]() { + QByteArray reply = socket->readAll(); + socket->disconnectFromHost(); + socket->deleteLater(); + if (reply != (message + ';')) + qFatal("echo_multiple received incorrect reply"); + guard->deref(); + }); + } +} + +void SockifySocketsTest::remoteClose() +{ + QTcpSocket *socket = new QTcpSocket(); + socket->connectToHost(hostName, port); + QObject::connect(socket, &QAbstractSocket::connected, [socket]() { + socket->write("close;"); + socket->flush(); + }); + QObject::connect(socket, &QAbstractSocket::disconnected, [socket]() { + qDebug() << "disconnected"; + socket->deleteLater(); + QtWasmTest::completeTestFunction(); + }); +} + +#if QT_CONFIG(thread) + +void SockifySocketsTest::thread_echo() +{ + auto started = []() { + blockingEchoTest(); + QThread::currentThread()->quit(); + }; + + auto finished = [](){ + QtWasmTest::completeTestFunction(); + }; + + TestThread::create(started, finished); +} + +void SockifySocketsTest::thread_echoMultipleSockets() +{ + const int connections = 2; // TODO: test more threads + auto guard = CompleteTestFunctionRefGuard::create(); + guard->ref(); + + for (int i = 0; i < connections; ++i) { + guard->ref(); + auto started = [](){ + blockingEchoTest(); + QThread::currentThread()->quit(); + }; + + auto finished = [guard](){ + guard->deref(); + }; + + TestThread::create(started, finished); + } + + guard->deref(); +} + +void SockifySocketsTest::thread_remoteClose() +{ + auto started = [](){ + blockingRemoteClose(); + QThread::currentThread()->quit(); + }; + + auto finished = [](){ + QtWasmTest::completeTestFunction(); + }; + + TestThread::create(started, finished); +} + +#endif + +#ifdef QT_HAVE_EMSCRIPTEN_ASYNCIFY + +// Post an event to the main thread and asyncify wait for it +void SockifySocketsTest::asyncify_echo() +{ + blockingEchoTest(); + QtWasmTest::completeTestFunction(); +} + +void SockifySocketsTest::asyncify_remoteClose() +{ + blockingRemoteClose(); + QtWasmTest::completeTestFunction(); +} + +#endif + +int main(int argc, char **argv) +{ + auto testObject = std::make_shared<SockifySocketsTest>(); + QtWasmTest::initTestCase<QCoreApplication>(argc, argv, testObject); + return 0; +} + +#include "main.moc" diff --git a/tests/manual/wasm/network/sockify_sockets_auto/sockify_sockets_auto.html b/tests/manual/wasm/network/sockify_sockets_auto/sockify_sockets_auto.html new file mode 100644 index 0000000000..080ada94e7 --- /dev/null +++ b/tests/manual/wasm/network/sockify_sockets_auto/sockify_sockets_auto.html @@ -0,0 +1,17 @@ +<!doctype html> +<script type="text/javascript" src="qtwasmtestlib.js"></script> +<script type="text/javascript" src="sockify_sockets_auto.js"></script> +<script> + window.onload = async () => { + runTestCase(sockify_sockets_auto_entry, document.getElementById("log")); + }; +</script> +<p> Sockify tunneled sockets auto test. + +<p>This test requires running echo_server and <a href=https://github.com/novnc/websockify>websockify</a> (or equivalent) on the host: +<pre> + /path/to/qtbase/tests/manual/wasm/network/echo_server/echo_server + websockify 1515 localhost:1516 +</pre> + +<div id="log"></div> |