1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
|
// SPDX-FileCopyrightText: 2021 Daniel Vrátil <dvratil@kde.org>
//
// SPDX-License-Identifier: MIT
#include "testobject.h"
#include "qcoro/network/qcorotcpserver.h"
#include "qcoro/network/qcoroabstractsocket.h"
#include <QTcpServer>
#include <QTcpSocket>
#include <thread>
#include <mutex>
using namespace std::chrono_literals;
class Client {
public:
Client(uint16_t serverPort, std::mutex &mutex, bool &ok)
: mThread([serverPort, &mutex, &ok]() mutable {
std::this_thread::sleep_for(500ms);
std::lock_guard lock{mutex};
QTcpSocket socket;
socket.connectToHost(QHostAddress::LocalHost, serverPort);
if (!socket.waitForConnected(10'000)) {
qWarning() << "Not connected within timeout" << socket.errorString();
ok = false;
return;
}
socket.write("Hello World!");
socket.flush();
socket.close();
ok = true;
})
{}
~Client() {
mThread.join();
}
private:
std::thread mThread;
};
class QCoroTcpServerTest: public QCoro::TestObject<QCoroTcpServerTest> {
Q_OBJECT
private:
QCoro::Task<> testWaitForNewConnectionTriggers_coro(QCoro::TestContext) {
QTcpServer server;
QCORO_VERIFY(server.listen(QHostAddress::LocalHost));
QCORO_VERIFY(server.isListening());
const quint16 serverPort = server.serverPort();
std::mutex mutex;
bool ok = false;
Client client(serverPort, mutex, ok);
auto *connection = co_await qCoro(server).waitForNewConnection(10s);
QCORO_VERIFY(connection != nullptr);
const auto data = co_await qCoro(connection).readAll();
QCORO_COMPARE(data, QByteArray{"Hello World!"});
std::lock_guard lock{mutex};
QCORO_VERIFY(ok);
}
void testThenWaitForNewConnectionTriggers_coro(TestLoop &el) {
QTcpServer server;
QVERIFY(server.listen(QHostAddress::LocalHost));
const quint16 serverPort = server.serverPort();
std::mutex mutex;
bool ok = false;
Client client(serverPort, mutex, ok);
bool called = false;
qCoro(server).waitForNewConnection(10s).then([&](QTcpSocket *socket) -> QCoro::Task<void> {
called = true;
if (!socket) {
el.quit();
co_return;
}
const auto data = co_await qCoro(socket).readAll();
QCORO_COMPARE(data, QByteArray("Hello World!"));
el.quit();
});
el.exec();
std::lock_guard lock{mutex};
QVERIFY(called);
QVERIFY(ok);
}
QCoro::Task<> testDoesntCoAwaitPendingConnection_coro(QCoro::TestContext testContext) {
testContext.setShouldNotSuspend();
QTcpServer server;
QCORO_VERIFY(server.listen(QHostAddress::LocalHost));
const int serverPort = server.serverPort();
bool ok = false;
std::mutex mutex;
Client client(serverPort, mutex, ok);
QCORO_VERIFY(server.waitForNewConnection(10'000));
auto *connection = co_await qCoro(server).waitForNewConnection(10s);
connection->waitForReadyRead(); // can't use coroutine, it might suspend or not, depending on how eventloop
// gets triggered, which fails the test since it's setShouldNotSuspend()
QCORO_COMPARE(connection->readAll(), QByteArray{"Hello World!"});
std::lock_guard lock{mutex};
QCORO_VERIFY(ok);
}
private Q_SLOTS:
addCoroAndThenTests(WaitForNewConnectionTriggers)
addTest(DoesntCoAwaitPendingConnection)
};
QTEST_GUILESS_MAIN(QCoroTcpServerTest)
#include "qcorotcpserver.moc"
|