From afa8824d941731d85116e0d08d619581939af734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Vr=C3=A1til?= Date: Sat, 30 Apr 2022 14:31:53 +0200 Subject: [PATCH] Make sure the test server waits for incoming connection The socket state is local, so it's possible to report 'connected', resume to coroutine finish it and destroy the socket before the server has time to actually get the incoming connection. This results in the test server being stopped by the test before it actually starts waiting for incoming connection, causing the server to incorrectly report the test as time out. The fix is for the test to wait at the end for the server to confirm it has gotten the incoming connection. --- tests/qcoroabstractsocket.cpp | 23 +++++++++++++++++++++++ tests/qcorolocalsocket.cpp | 18 ++++++++++++++++++ tests/testhttpserver.h | 12 ++++++++++++ 3 files changed, 53 insertions(+) diff --git a/tests/qcoroabstractsocket.cpp b/tests/qcoroabstractsocket.cpp index df4754b..6207fb4 100644 --- a/tests/qcoroabstractsocket.cpp +++ b/tests/qcoroabstractsocket.cpp @@ -24,6 +24,9 @@ class QCoroAbstractSocketTest : public QCoro::TestObject testWaitForDisconnectedTriggers_coro(QCoro::TestContext) { @@ -49,6 +53,8 @@ class QCoroAbstractSocketTest : public QCoro::TestObject testDoesntCoAwaitConnectedSocket_coro(QCoro::TestContext context) { @@ -82,6 +90,8 @@ class QCoroAbstractSocketTest : public QCoro::TestObject testDoesntCoAwaitDisconnectedSocket_coro(QCoro::TestContext context) { @@ -138,6 +150,7 @@ class QCoroAbstractSocketTest : public QCoro::TestObject testWaitForConnectedTimeout_coro(QCoro::TestContext) { @@ -186,6 +200,8 @@ class QCoroAbstractSocketTest : public QCoro::TestObject testReadAllTriggers_coro(QCoro::TestContext) { @@ -218,6 +235,7 @@ class QCoroAbstractSocketTest : public QCoro::TestObject testReadTriggers_coro(QCoro::TestContext) { @@ -252,6 +271,7 @@ class QCoroAbstractSocketTest : public QCoro::TestObject testReadLineTriggers_coro(QCoro::TestContext) { @@ -287,6 +308,7 @@ class QCoroAbstractSocketTest : public QCoro::TestObject { co_await qCoro(socket).waitForConnected(); QCORO_COMPARE(socket.state(), QLocalSocket::ConnectedState); + QCORO_VERIFY(mServer.waitForConnection()); } void testThenWaitForConnectedTriggers_coro(TestLoop &el) { @@ -38,6 +39,7 @@ class QCoroLocalSocketTest : public QCoro::TestObject { }); el.exec(); QVERIFY(called); + QVERIFY(mServer.waitForConnection()); } QCoro::Task<> testWaitForDisconnectedTriggers_coro(QCoro::TestContext) { @@ -50,6 +52,7 @@ class QCoroLocalSocketTest : public QCoro::TestObject { co_await qCoro(socket).waitForDisconnected(); QCORO_COMPARE(socket.state(), QLocalSocket::UnconnectedState); + QCORO_VERIFY(mServer.waitForConnection()); } void testThenWaitForDisconnectedTriggers_coro(TestLoop &el) { @@ -66,6 +69,7 @@ class QCoroLocalSocketTest : public QCoro::TestObject { }); el.exec(); QVERIFY(called); + QVERIFY(mServer.waitForConnection()); } // On Linux at least, QLocalSocket connects immediately and synchronously @@ -78,6 +82,7 @@ class QCoroLocalSocketTest : public QCoro::TestObject { QCORO_COMPARE(socket.state(), QLocalSocket::ConnectedState); co_await qCoro(socket).waitForConnected(); + QCORO_VERIFY(mServer.waitForConnection()); } void testThenDoesntCoAwaitConnectedSocket_coro(TestLoop &el) { @@ -93,6 +98,7 @@ class QCoroLocalSocketTest : public QCoro::TestObject { }); el.exec(); QVERIFY(called); + QVERIFY(mServer.waitForConnection()); } QCoro::Task<> testDoesntCoAwaitDisconnectedSocket_coro(QCoro::TestContext context) { @@ -128,6 +134,7 @@ class QCoroLocalSocketTest : public QCoro::TestObject { co_await qCoro(socket).connectToServer(QCoroLocalSocketTest::getSocketName()); QCORO_COMPARE(socket.state(), QLocalSocket::ConnectedState); + QCORO_VERIFY(mServer.waitForConnection()); } void testThenConnectToServerWithArgs_coro(TestLoop &el) { @@ -140,6 +147,7 @@ class QCoroLocalSocketTest : public QCoro::TestObject { }); el.exec(); QVERIFY(called); + QVERIFY(mServer.waitForConnection()); } QCoro::Task<> testConnectToServer_coro(QCoro::TestContext context) { @@ -151,6 +159,7 @@ class QCoroLocalSocketTest : public QCoro::TestObject { co_await qCoro(socket).connectToServer(); QCORO_COMPARE(socket.state(), QLocalSocket::ConnectedState); + QCORO_VERIFY(mServer.waitForConnection()); } void testThenConnectToServer_coro(TestLoop &el) { @@ -164,6 +173,7 @@ class QCoroLocalSocketTest : public QCoro::TestObject { }); el.exec(); QVERIFY(called); + QVERIFY(mServer.waitForConnection()); } QCoro::Task<> testWaitForConnectedTimeout_coro(QCoro::TestContext) { @@ -198,6 +208,7 @@ class QCoroLocalSocketTest : public QCoro::TestObject { QCORO_COMPARE(socket.state(), QLocalSocket::ConnectedState); QCORO_TEST_TIMEOUT(co_await qCoro(socket).waitForDisconnected(10ms)); + QCORO_VERIFY(mServer.waitForConnection()); } void testThenWaitForDisconnectedTimeout_coro(TestLoop &el) { @@ -215,6 +226,7 @@ class QCoroLocalSocketTest : public QCoro::TestObject { const auto end = std::chrono::steady_clock::now(); QVERIFY(end - start < 500ms); QVERIFY(called); + QVERIFY(mServer.waitForConnection()); } QCoro::Task<> testReadAllTriggers_coro(QCoro::TestContext) { @@ -225,6 +237,7 @@ class QCoroLocalSocketTest : public QCoro::TestObject { socket.write("GET /stream HTTP/1.1\r\n"); QCORO_TEST_IODEVICE_READALL(socket); + QCORO_VERIFY(mServer.waitForConnection()); } void testThenReadAllTriggers_coro(TestLoop &el) { @@ -241,6 +254,7 @@ class QCoroLocalSocketTest : public QCoro::TestObject { el.exec(); QVERIFY(called); + QVERIFY(mServer.waitForConnection()); } QCoro::Task<> testReadTriggers_coro(QCoro::TestContext) { @@ -251,6 +265,7 @@ class QCoroLocalSocketTest : public QCoro::TestObject { socket.write("GET /stream HTTP/1.1\r\n"); QCORO_TEST_IODEVICE_READ(socket); + QCORO_VERIFY(mServer.waitForConnection()); } void testThenReadTriggers_coro(TestLoop &el) { @@ -266,6 +281,7 @@ class QCoroLocalSocketTest : public QCoro::TestObject { socket.write("GET /block HTTP/1.1\r\n"); el.exec(); QVERIFY(called); + QVERIFY(mServer.waitForConnection()); } QCoro::Task<> testReadLineTriggers_coro(QCoro::TestContext) { @@ -277,6 +293,7 @@ class QCoroLocalSocketTest : public QCoro::TestObject { QCORO_TEST_IODEVICE_READLINE(socket); QCORO_COMPARE(lines.size(), 14); + QCORO_VERIFY(mServer.waitForConnection()); } void testThenReadLineTriggers_coro(TestLoop &el) { @@ -293,6 +310,7 @@ class QCoroLocalSocketTest : public QCoro::TestObject { el.exec(); QVERIFY(called); + QVERIFY(mServer.waitForConnection()); } private Q_SLOTS: diff --git a/tests/testhttpserver.h b/tests/testhttpserver.h index 005a5ba..b65a4bf 100644 --- a/tests/testhttpserver.h +++ b/tests/testhttpserver.h @@ -52,6 +52,8 @@ class TestHttpServer { public: template void start(const T &name) { + mPort = 0; + mHasConnection = false; mStop = false; mExpectTimeout = false; // Can't use QThread::create, it's only available when Qt is built with C++17, @@ -69,6 +71,7 @@ class TestHttpServer { } mThread.reset(); mPort = 0; + mHasConnection = false; } uint16_t port() const { @@ -79,6 +82,11 @@ class TestHttpServer { mExpectTimeout = expectTimeout; } + bool waitForConnection() { + std::unique_lock lock(mReadyMutex); + return mServerReady.wait_for(lock, std::chrono::seconds(5), [this]() { return mHasConnection; }); + } + private: template void run(const T &name) { @@ -117,6 +125,9 @@ class TestHttpServer { return; } + mHasConnection = true; + mServerReady.notify_all(); + if (conn->waitForReadyRead(1000)) { const auto request = conn->readLine(); qDebug() << request; @@ -171,6 +182,7 @@ class TestHttpServer { std::mutex mReadyMutex; std::condition_variable mServerReady; uint16_t mPort = 0; + bool mHasConnection = false; std::atomic_bool mStop = false; std::atomic_bool mExpectTimeout = false; };