diff options
Diffstat (limited to 'tests')
4 files changed, 282 insertions, 27 deletions
diff --git a/tests/auto/websockets/dataprocessor/tst_dataprocessor.cpp b/tests/auto/websockets/dataprocessor/tst_dataprocessor.cpp index f9a91d5..5390ff0 100644 --- a/tests/auto/websockets/dataprocessor/tst_dataprocessor.cpp +++ b/tests/auto/websockets/dataprocessor/tst_dataprocessor.cpp @@ -193,7 +193,7 @@ private: //sequences void nonCharacterSequence(const char *sequence); - void doTest(); + void doTest(int timeout = 0); void doCloseFrameTest(); QString opCodeToString(quint8 opCode); @@ -744,6 +744,7 @@ void tst_DataProcessor::frameTooSmall() dataProcessor.process(&buffer); + QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), 7000); QCOMPARE(errorSpy.count(), 1); QCOMPARE(closeSpy.count(), 0); QCOMPARE(pingMessageSpy.count(), 0); @@ -776,6 +777,7 @@ void tst_DataProcessor::frameTooSmall() dataProcessor.process(&buffer); + QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), 7000); QCOMPARE(errorSpy.count(), 1); QCOMPARE(closeSpy.count(), 0); QCOMPARE(pingMessageSpy.count(), 0); @@ -808,6 +810,24 @@ void tst_DataProcessor::frameTooSmall() dataProcessor.process(&buffer); + QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), 7000); + QCOMPARE(errorSpy.count(), 1); + QCOMPARE(closeSpy.count(), 0); + QCOMPARE(pingMessageSpy.count(), 0); + QCOMPARE(pongMessageSpy.count(), 0); + QCOMPARE(textMessageSpy.count(), 0); + QCOMPARE(binaryMessageSpy.count(), 0); + QCOMPARE(textFrameSpy.count(), 1); + QCOMPARE(binaryFrameSpy.count(), 0); + + errorSpy.clear(); + closeSpy.clear(); + pingMessageSpy.clear(); + pongMessageSpy.clear(); + textMessageSpy.clear(); + binaryMessageSpy.clear(); + textFrameSpy.clear(); + binaryFrameSpy.clear(); buffer.close(); data.clear(); @@ -816,17 +836,16 @@ void tst_DataProcessor::frameTooSmall() //meaning the socket will be closed buffer.setData(data); buffer.open(QIODevice::ReadOnly); - QSignalSpy errorSpy(&dataProcessor, - SIGNAL(errorEncountered(QWebSocketProtocol::CloseCode,QString))); dataProcessor.process(&buffer); + QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), 7000); QCOMPARE(errorSpy.count(), 1); QCOMPARE(closeSpy.count(), 0); QCOMPARE(pingMessageSpy.count(), 0); QCOMPARE(pongMessageSpy.count(), 0); QCOMPARE(textMessageSpy.count(), 0); QCOMPARE(binaryMessageSpy.count(), 0); - QCOMPARE(textFrameSpy.count(), 1); + QCOMPARE(textFrameSpy.count(), 0); QCOMPARE(binaryFrameSpy.count(), 0); QList<QVariant> arguments = errorSpy.takeFirst(); @@ -849,6 +868,7 @@ void tst_DataProcessor::frameTooSmall() buffer.open(QIODevice::ReadOnly); dataProcessor.process(&buffer); + QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), 7000); QCOMPARE(errorSpy.count(), 1); QCOMPARE(closeSpy.count(), 0); QCOMPARE(pingMessageSpy.count(), 0); @@ -877,6 +897,7 @@ void tst_DataProcessor::frameTooSmall() buffer.open(QIODevice::ReadOnly); dataProcessor.process(&buffer); + QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), 7000); QCOMPARE(errorSpy.count(), 1); QCOMPARE(closeSpy.count(), 0); QCOMPARE(pingMessageSpy.count(), 0); @@ -1400,7 +1421,7 @@ void tst_DataProcessor::incompletePayload_data() void tst_DataProcessor::incompletePayload() { - doTest(); + doTest(7000); } void tst_DataProcessor::incompleteSizeField_data() @@ -1430,13 +1451,13 @@ void tst_DataProcessor::incompleteSizeField_data() void tst_DataProcessor::incompleteSizeField() { - doTest(); + doTest(7000); } ////////////////////////////////////////////////////////////////////////////////////////// /// HELPER FUNCTIONS ////////////////////////////////////////////////////////////////////////////////////////// -void tst_DataProcessor::doTest() +void tst_DataProcessor::doTest(int timeout) { QFETCH(quint8, firstByte); QFETCH(quint8, secondByte); @@ -1465,6 +1486,7 @@ void tst_DataProcessor::doTest() buffer.setData(data); buffer.open(QIODevice::ReadOnly); dataProcessor.process(&buffer); + QTRY_VERIFY_WITH_TIMEOUT(errorSpy.count(), timeout); QCOMPARE(errorSpy.count(), 1); QCOMPARE(textMessageSpy.count(), 0); QCOMPARE(binaryMessageSpy.count(), 0); diff --git a/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp b/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp index 2bb5d16..71e1262 100644 --- a/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp +++ b/tests/auto/websockets/qwebsocket/tst_qwebsocket.cpp @@ -457,12 +457,46 @@ void tst_QWebSocket::tst_sendTextMessage() QVERIFY(isLastFrame); socket.close(); + socketConnectedSpy.clear(); + textMessageReceived.clear(); + textFrameReceived.clear(); - //QTBUG-36762: QWebSocket emits multiplied signals when socket was reopened + // QTBUG-74464 QWebsocket doesn't receive text (binary) message with size > 32 kb + socket.open(url); + + QTRY_COMPARE(socketConnectedSpy.count(), 1); + QCOMPARE(socketError.count(), 0); + QCOMPARE(socket.state(), QAbstractSocket::ConnectedState); + arguments = serverConnectedSpy.takeFirst(); + urlConnected = arguments.at(0).toUrl(); + QCOMPARE(urlConnected, url); + QCOMPARE(socket.bytesToWrite(), 0); + + // transmit a long text message with 1 MB + QString longString(0x100000, 'a'); + socket.sendTextMessage(longString); + QVERIFY(socket.bytesToWrite() > longString.length()); + QVERIFY(textMessageReceived.wait()); + QCOMPARE(socket.bytesToWrite(), 0); + + QCOMPARE(textMessageReceived.count(), 1); + QCOMPARE(binaryMessageReceived.count(), 0); + QCOMPARE(binaryFrameReceived.count(), 0); + arguments = textMessageReceived.takeFirst(); + messageReceived = arguments.at(0).toString(); + QCOMPARE(messageReceived.length(), longString.length()); + QCOMPARE(messageReceived, longString); + + arguments = textFrameReceived.takeLast(); + isLastFrame = arguments.at(1).toBool(); + QVERIFY(isLastFrame); + + socket.close(); socketConnectedSpy.clear(); textMessageReceived.clear(); textFrameReceived.clear(); + //QTBUG-36762: QWebSocket emits multiplied signals when socket was reopened socket.open(QUrl(QStringLiteral("ws://") + echoServer.hostAddress().toString() + QStringLiteral(":") + QString::number(echoServer.port()))); diff --git a/tests/auto/websockets/qwebsocketserver/tst_qwebsocketserver.cpp b/tests/auto/websockets/qwebsocketserver/tst_qwebsocketserver.cpp index 64b2489..c40bb01 100644 --- a/tests/auto/websockets/qwebsocketserver/tst_qwebsocketserver.cpp +++ b/tests/auto/websockets/qwebsocketserver/tst_qwebsocketserver.cpp @@ -28,7 +28,9 @@ #include <QString> #include <QtTest> #include <QNetworkProxy> +#include <QTcpSocket> #include <QTcpServer> +#include <QtCore/QScopedPointer> #ifndef QT_NO_OPENSSL #include <QtNetwork/qsslpresharedkeyauthenticator.h> #endif @@ -113,6 +115,8 @@ private Q_SLOTS: void tst_serverDestroyedWhileSocketConnected(); void tst_scheme(); // qtbug-55927 void tst_handleConnection(); + void tst_handshakeTimeout(); // qtbug-63312, qtbug-57026 + void multipleFrames(); private: bool m_shouldSkipUnsupportedIpv6Test; @@ -290,6 +294,18 @@ void tst_QWebSocketServer::tst_settersAndGetters() QCOMPARE(sslServer.sslConfiguration(), sslConfiguration); QVERIFY(sslServer.sslConfiguration() != QSslConfiguration::defaultConfiguration()); #endif + + server.setHandshakeTimeout(64); + QCOMPARE(server.handshakeTimeoutMS(), 64); +#if QT_HAS_INCLUDE(<chrono>) + auto expected = std::chrono::milliseconds(64); + QCOMPARE(server.handshakeTimeout(), expected); + + expected = std::chrono::milliseconds(242); + server.setHandshakeTimeout(expected); + QCOMPARE(server.handshakeTimeoutMS(), 242); + QCOMPARE(server.handshakeTimeout(), expected); +#endif } void tst_QWebSocketServer::tst_listening() @@ -387,7 +403,7 @@ void tst_QWebSocketServer::tst_preSharedKey() QWebSocketServer server(QString(), QWebSocketServer::SecureMode); bool cipherFound = false; - const QList<QSslCipher> supportedCiphers = QSslSocket::supportedCiphers(); + const QList<QSslCipher> supportedCiphers = QSslConfiguration::supportedCiphers(); for (const QSslCipher &cipher : supportedCiphers) { if (cipher.name() == PSK_CIPHER_WITHOUT_AUTH) { cipherFound = true; @@ -573,6 +589,26 @@ void tst_QWebSocketServer::tst_serverDestroyedWhileSocketConnected() QTRY_COMPARE(socketDisconnectedSpy.count(), 1); } +#ifndef QT_NO_SSL +static void setupSecureServer(QWebSocketServer *secureServer) +{ + QSslConfiguration sslConfiguration; + QFile certFile(QStringLiteral(":/localhost.cert")); + QFile keyFile(QStringLiteral(":/localhost.key")); + QVERIFY(certFile.open(QIODevice::ReadOnly)); + QVERIFY(keyFile.open(QIODevice::ReadOnly)); + QSslCertificate certificate(&certFile, QSsl::Pem); + QSslKey sslKey(&keyFile, QSsl::Rsa, QSsl::Pem); + certFile.close(); + keyFile.close(); + sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone); + sslConfiguration.setLocalCertificate(certificate); + sslConfiguration.setPrivateKey(sslKey); + sslConfiguration.setProtocol(QSsl::TlsV1SslV3); + secureServer->setSslConfiguration(sslConfiguration); +} +#endif + void tst_QWebSocketServer::tst_scheme() { if (m_shouldSkipUnsupportedIpv6Test) @@ -594,20 +630,9 @@ void tst_QWebSocketServer::tst_scheme() #ifndef QT_NO_SSL QWebSocketServer secureServer(QString(), QWebSocketServer::SecureMode); - QSslConfiguration sslConfiguration; - QFile certFile(QStringLiteral(":/localhost.cert")); - QFile keyFile(QStringLiteral(":/localhost.key")); - QVERIFY(certFile.open(QIODevice::ReadOnly)); - QVERIFY(keyFile.open(QIODevice::ReadOnly)); - QSslCertificate certificate(&certFile, QSsl::Pem); - QSslKey sslKey(&keyFile, QSsl::Rsa, QSsl::Pem); - certFile.close(); - keyFile.close(); - sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone); - sslConfiguration.setLocalCertificate(certificate); - sslConfiguration.setPrivateKey(sslKey); - sslConfiguration.setProtocol(QSsl::TlsV1SslV3); - secureServer.setSslConfiguration(sslConfiguration); + setupSecureServer(&secureServer); + if (QTest::currentTestFailed()) + return; QSignalSpy secureServerConnectionSpy(&secureServer, SIGNAL(newConnection())); QVERIFY(secureServer.listen()); @@ -668,6 +693,176 @@ void tst_QWebSocketServer::tst_handleConnection() QCOMPARE(arguments.first().toString(), QString("hello")); } +struct SocketSpy { + QTcpSocket *socket; + QSignalSpy *disconnectSpy; + ~SocketSpy() { + delete socket; + delete disconnectSpy; + } +}; + +static void openManyConnections(QList<SocketSpy *> *sockets, quint16 port, int numConnections) +{ + for (int i = 0; i < numConnections; i++) { + QTcpSocket *c = new QTcpSocket; + QSignalSpy *spy = new QSignalSpy(c, &QTcpSocket::disconnected); + + c->connectToHost("127.0.0.1", port); + + sockets->append(new SocketSpy{c, spy}); + } +} + +// Sum the counts together, for better output on failure (e.g. "FAIL: Actual: 49, Expected: 50") +static int sumSocketSpyCount(const QList<SocketSpy *> &sockets) +{ + return std::accumulate(sockets.cbegin(), sockets.cend(), 0, [](int c, SocketSpy *s) { + return c + s->disconnectSpy->count(); + }); +} + +void tst_QWebSocketServer::tst_handshakeTimeout() +{ + { // No Timeout + QWebSocketServer plainServer(QString(), QWebSocketServer::NonSecureMode); + plainServer.setHandshakeTimeout(-1); + QSignalSpy plainServerConnectionSpy(&plainServer, SIGNAL(newConnection())); + + QVERIFY(plainServer.listen()); + + QWebSocket socket; + socket.open(plainServer.serverUrl().toString()); + + QTRY_COMPARE(plainServerConnectionSpy.count(), 1); + QScopedPointer<QWebSocket> plainServerSocket(plainServer.nextPendingConnection()); + QVERIFY(!plainServerSocket.isNull()); + + plainServer.close(); + } + + { // Unencrypted + QWebSocketServer plainServer(QString(), QWebSocketServer::NonSecureMode); + plainServer.setHandshakeTimeout(500); + QSignalSpy plainServerConnectionSpy(&plainServer, SIGNAL(newConnection())); + + QVERIFY(plainServer.listen()); + + /* QTcpServer has a default of 30 pending connections. The test checks + * whether, when that list is full, the connections are dropped after + * a timeout and later pending connections are processed. */ + const int numConnections = 50; + QList<SocketSpy *> sockets; + auto cleaner = qScopeGuard([&sockets]() { qDeleteAll(sockets); }); + openManyConnections(&sockets, plainServer.serverPort(), numConnections); + + QCoreApplication::processEvents(); + + /* We have 50 plain TCP connections open, that are not proper websockets. */ + QCOMPARE(plainServerConnectionSpy.count(), 0); + + QWebSocket socket; + socket.open(plainServer.serverUrl().toString()); + + /* Check that a real websocket will be processed after some non-websocket + * TCP connections timeout. */ + QTRY_COMPARE(plainServerConnectionSpy.count(), 1); + QScopedPointer<QWebSocket> plainServerSocket(plainServer.nextPendingConnection()); + QVERIFY(!plainServerSocket.isNull()); + + /* Check that all non websocket connections eventually timeout. */ + QTRY_COMPARE(sumSocketSpyCount(sockets), numConnections); + + plainServer.close(); + } + +#if QT_CONFIG(ssl) + { // Encrypted + QWebSocketServer secureServer(QString(), QWebSocketServer::SecureMode); + setupSecureServer(&secureServer); + if (QTest::currentTestFailed()) + return; + secureServer.setHandshakeTimeout(500); + + QSignalSpy secureServerConnectionSpy(&secureServer, SIGNAL(newConnection())); + + QVERIFY(secureServer.listen()); + + const int numConnections = 50; + QList<SocketSpy *> sockets; + auto cleaner = qScopeGuard([&sockets]() { qDeleteAll(sockets); }); + openManyConnections(&sockets, secureServer.serverPort(), numConnections); + + QCoreApplication::processEvents(); + QCOMPARE(secureServerConnectionSpy.count(), 0); + + QWebSocket secureSocket; + QSslConfiguration config = secureSocket.sslConfiguration(); + config.setPeerVerifyMode(QSslSocket::VerifyNone); + secureSocket.setSslConfiguration(config); + + secureSocket.open(secureServer.serverUrl().toString()); + + QTRY_COMPARE(secureServerConnectionSpy.count(), 1); + QScopedPointer<QWebSocket> serverSocket(secureServer.nextPendingConnection()); + QVERIFY(!serverSocket.isNull()); + + QTRY_COMPARE(sumSocketSpyCount(sockets), numConnections); + + secureServer.close(); + } +#endif + + { // Ensure properly handshaked connections are not timed out + QWebSocketServer plainServer(QString(), QWebSocketServer::NonSecureMode); + plainServer.setHandshakeTimeout(250); + QSignalSpy plainServerConnectionSpy(&plainServer, SIGNAL(newConnection())); + + QVERIFY(plainServer.listen()); + + QWebSocket socket; + QSignalSpy socketConnectedSpy(&socket, &QWebSocket::connected); + QSignalSpy socketDisconnectedSpy(&socket, &QWebSocket::disconnected); + socket.open(plainServer.serverUrl().toString()); + + QTRY_COMPARE(plainServerConnectionSpy.count(), 1); + QTRY_COMPARE(socketConnectedSpy.count(), 1); + + QEventLoop loop; + QTimer::singleShot(500, &loop, &QEventLoop::quit); + loop.exec(); + + QCOMPARE(socketDisconnectedSpy.count(), 0); + } +} + +void tst_QWebSocketServer::multipleFrames() +{ + QWebSocketServer server(QString(), QWebSocketServer::NonSecureMode); + QSignalSpy serverConnectionSpy(&server, &QWebSocketServer::newConnection); + QVERIFY(server.listen()); + + QWebSocket socket; + QSignalSpy socketConnectedSpy(&socket, &QWebSocket::connected); + QSignalSpy messageReceivedSpy(&socket, &QWebSocket::binaryMessageReceived); + socket.open(server.serverUrl().toString()); + + QVERIFY(serverConnectionSpy.wait()); + QVERIFY(socketConnectedSpy.wait()); + + auto serverSocket = std::unique_ptr<QWebSocket>(server.nextPendingConnection()); + QVERIFY(serverSocket); + for (int i = 0; i < 10; i++) + serverSocket->sendBinaryMessage(QByteArray("abc")); + if (serverSocket->bytesToWrite()) + QVERIFY(serverSocket->flush()); + + QVERIFY(messageReceivedSpy.wait()); + // Since there's no guarantee the operating system will fit all 10 websocket frames into 1 tcp + // frame, let's just assume it will do at least 2. EXCEPT_FAIL any which doesn't merge any. + QVERIFY2(messageReceivedSpy.count() > 1, "Received only 1 message in the TCP frame!"); +} + QTEST_MAIN(tst_QWebSocketServer) #include "tst_qwebsocketserver.moc" diff --git a/tests/auto/websockets/websocketframe/tst_websocketframe.cpp b/tests/auto/websockets/websocketframe/tst_websocketframe.cpp index 5614df8..6b9aaaf 100644 --- a/tests/auto/websockets/websocketframe/tst_websocketframe.cpp +++ b/tests/auto/websockets/websocketframe/tst_websocketframe.cpp @@ -197,7 +197,8 @@ void tst_WebSocketFrame::tst_copyConstructorAndAssignment() QBuffer buffer(&payload); buffer.open(QIODevice::ReadOnly); - QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer); + QWebSocketFrame frame; + frame.readFrame(&buffer); buffer.close(); { @@ -330,7 +331,8 @@ void tst_WebSocketFrame::tst_goodFrames() QBuffer buffer; buffer.setData(wireRepresentation); buffer.open(QIODevice::ReadOnly); - QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer); + QWebSocketFrame frame; + frame.readFrame(&buffer); buffer.close(); QVERIFY(frame.isValid()); QCOMPARE(frame.rsv1(), rsv1); @@ -495,7 +497,8 @@ void tst_WebSocketFrame::tst_invalidFrames() QBuffer buffer; buffer.setData(wireRepresentation); buffer.open(QIODevice::ReadOnly); - QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer); + QWebSocketFrame frame; + frame.readFrame(&buffer); buffer.close(); QVERIFY(!frame.isValid()); @@ -606,7 +609,8 @@ void tst_WebSocketFrame::tst_malformedFrames() QBuffer buffer; buffer.setData(payload); buffer.open(QIODevice::ReadOnly); - QWebSocketFrame frame = QWebSocketFrame::readFrame(&buffer); + QWebSocketFrame frame; + frame.readFrame(&buffer); buffer.close(); QVERIFY(!frame.isValid()); |