diff options
author | Liang Qi <liang.qi@qt.io> | 2019-04-11 07:47:21 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2019-04-11 07:47:21 +0200 |
commit | c7af193d2e49e9f10b86262e63d8d13abf72b5cf (patch) | |
tree | 7ca5d4ba83888bb5ad4d9b0141e5c62f8a5138f2 /tests/auto | |
parent | 235ac95520a0fc2c822dedce7358e3c64a764255 (diff) | |
parent | 63e88f60a769f2535945db0e1cabb9815ff45a77 (diff) |
Merge remote-tracking branch 'origin/5.13' into dev
Conflicts:
src/widgets/styles/qstyle_p.h
Change-Id: I0e6e856bd6628da1135b3ba674dddffabbeb5c09
Diffstat (limited to 'tests/auto')
-rw-r--r-- | tests/auto/corelib/io/qurl/tst_qurl.cpp | 8 | ||||
-rw-r--r-- | tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp | 13 | ||||
-rw-r--r-- | tests/auto/network/access/http2/http2srv.cpp | 55 | ||||
-rw-r--r-- | tests/auto/network/access/http2/http2srv.h | 15 | ||||
-rw-r--r-- | tests/auto/network/access/http2/tst_http2.cpp | 93 |
5 files changed, 140 insertions, 44 deletions
diff --git a/tests/auto/corelib/io/qurl/tst_qurl.cpp b/tests/auto/corelib/io/qurl/tst_qurl.cpp index 3ee6a656b0..9c106c7f58 100644 --- a/tests/auto/corelib/io/qurl/tst_qurl.cpp +++ b/tests/auto/corelib/io/qurl/tst_qurl.cpp @@ -47,6 +47,7 @@ class tst_QUrl : public QObject private slots: void initTestCase(); + void cleanupTestCase(); void effectiveTLDs_data(); void effectiveTLDs(); void getSetCheck(); @@ -188,6 +189,7 @@ private slots: private: void testThreadingHelper(); + const QString m_currentPath = QDir::currentPath(); QTemporaryDir m_tempDir; }; @@ -196,6 +198,12 @@ void tst_QUrl::initTestCase() QVERIFY2(m_tempDir.isValid(), qPrintable(m_tempDir.errorString())); } +void tst_QUrl::cleanupTestCase() +{ + // Restore working directory changed in fromUserInputWithCwd() + QDir::setCurrent(m_currentPath); +} + // Testing get/set functions void tst_QUrl::getSetCheck() { diff --git a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp index 467d299526..350ed24c28 100644 --- a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp +++ b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp @@ -40,6 +40,13 @@ struct MyStruct int i; }; +class MyGadget +{ + Q_GADGET +public: + Q_INVOKABLE MyGadget() {} +}; + namespace MyNamespace { // Used in tst_QMetaObject::checkScope class MyClass : public QObject @@ -1208,6 +1215,12 @@ void tst_QMetaObject::invokeMetaConstructor() QCOMPARE(obj2->parent(), (QObject*)&obj); QVERIFY(qobject_cast<NamespaceWithConstructibleClass::ConstructibleClass*>(obj2) != 0); } + // gadget shouldn't return a valid pointer + { + QCOMPARE(MyGadget::staticMetaObject.constructorCount(), 1); + QTest::ignoreMessage(QtWarningMsg, "QMetaObject::newInstance: type MyGadget does not inherit QObject"); + QVERIFY(!MyGadget::staticMetaObject.newInstance()); + } } void tst_QMetaObject::invokeTypedefTypes() diff --git a/tests/auto/network/access/http2/http2srv.cpp b/tests/auto/network/access/http2/http2srv.cpp index 6e2220fa67..5a99d4e50c 100644 --- a/tests/auto/network/access/http2/http2srv.cpp +++ b/tests/auto/network/access/http2/http2srv.cpp @@ -76,11 +76,15 @@ void fill_push_header(const HttpHeader &originalRequest, HttpHeader &promisedReq } -Http2Server::Http2Server(bool h2c, const Http2::RawSettings &ss, const Http2::RawSettings &cs) - : serverSettings(ss), - expectedClientSettings(cs), - clearTextHTTP2(h2c) +Http2Server::Http2Server(H2Type type, const Http2::RawSettings &ss, const Http2::RawSettings &cs) + : connectionType(type), + serverSettings(ss), + expectedClientSettings(cs) { +#if !QT_CONFIG(ssl) + Q_ASSERT(type != H2Type::h2Alpn && type != H2Type::h2Direct); +#endif + responseBody = "<html>\n" "<head>\n" "<title>Sample \"Hello, World\" Application</title>\n" @@ -129,15 +133,15 @@ void Http2Server::redirectOpenStream(quint16 port) targetPort = port; } +bool Http2Server::isClearText() const +{ + return connectionType == H2Type::h2c || connectionType == H2Type::h2cDirect; +} + void Http2Server::startServer() { -#ifdef QT_NO_SSL - // Let the test fail with timeout. - if (!clearTextHTTP2) - return; -#endif if (listen()) { - if (clearTextHTTP2) + if (isClearText()) authority = QStringLiteral("127.0.0.1:%1").arg(serverPort()).toLatin1(); emit serverStarted(serverPort()); } @@ -146,7 +150,7 @@ void Http2Server::startServer() bool Http2Server::sendProtocolSwitchReply() { Q_ASSERT(socket); - Q_ASSERT(clearTextHTTP2 && upgradeProtocol); + Q_ASSERT(connectionType == H2Type::h2c); // The first and the last HTTP/1.1 response we send: const char response[] = "HTTP/1.1 101 Switching Protocols\r\n" "Connection: Upgrade\r\n" @@ -262,25 +266,28 @@ void Http2Server::sendWINDOW_UPDATE(quint32 streamID, quint32 delta) void Http2Server::incomingConnection(qintptr socketDescriptor) { - if (clearTextHTTP2) { + if (isClearText()) { socket.reset(new QTcpSocket); const bool set = socket->setSocketDescriptor(socketDescriptor); Q_ASSERT(set); // Stop listening: close(); - upgradeProtocol = true; + upgradeProtocol = connectionType == H2Type::h2c; QMetaObject::invokeMethod(this, "connectionEstablished", Qt::QueuedConnection); } else { -#ifndef QT_NO_SSL +#if QT_CONFIG(ssl) socket.reset(new QSslSocket); QSslSocket *sslSocket = static_cast<QSslSocket *>(socket.data()); - // Add HTTP2 as supported protocol: - auto conf = QSslConfiguration::defaultConfiguration(); - auto protos = conf.allowedNextProtocols(); - protos.prepend(QSslConfiguration::ALPNProtocolHTTP2); - conf.setAllowedNextProtocols(protos); - sslSocket->setSslConfiguration(conf); + + if (connectionType == H2Type::h2Alpn) { + // Add HTTP2 as supported protocol: + auto conf = QSslConfiguration::defaultConfiguration(); + auto protos = conf.allowedNextProtocols(); + protos.prepend(QSslConfiguration::ALPNProtocolHTTP2); + conf.setAllowedNextProtocols(protos); + sslSocket->setSslConfiguration(conf); + } // SSL-related setup ... sslSocket->setPeerVerifyMode(QSslSocket::VerifyNone); sslSocket->setProtocol(QSsl::TlsV1_2OrLater); @@ -299,7 +306,7 @@ void Http2Server::incomingConnection(qintptr socketDescriptor) connect(sslSocket, SIGNAL(encrypted()), this, SLOT(connectionEstablished())); sslSocket->startServerEncryption(); #else - Q_UNREACHABLE(); + Q_ASSERT(0); #endif } } @@ -377,7 +384,7 @@ void Http2Server::connectionEstablished() { using namespace Http2; - if (testingGOAWAY && !clearTextHTTP2) + if (testingGOAWAY && !isClearText()) return triggerGOAWAYEmulation(); // For clearTextHTTP2 we first have to respond with 'protocol switch' @@ -392,7 +399,7 @@ void Http2Server::connectionEstablished() waitingClientSettings = false; settingsSent = false; - if (clearTextHTTP2) { + if (connectionType == H2Type::h2c) { requestLine.clear(); // Now we have to handle HTTP/1.1 request. We use Get/Post in our test, // so set requestType to something unsupported: @@ -818,7 +825,7 @@ void Http2Server::sendResponse(quint32 streamID, bool emptyBody) Q_ASSERT(targetPort); header.push_back({":status", "308"}); const QString url("%1://localhost:%2/"); - header.push_back({"location", url.arg(clearTextHTTP2 ? QStringLiteral("http") : QStringLiteral("https"), + header.push_back({"location", url.arg(isClearText() ? QStringLiteral("http") : QStringLiteral("https"), QString::number(targetPort)).toLatin1()}); } else { diff --git a/tests/auto/network/access/http2/http2srv.h b/tests/auto/network/access/http2/http2srv.h index ae3f084fdc..4ef4b25101 100644 --- a/tests/auto/network/access/http2/http2srv.h +++ b/tests/auto/network/access/http2/http2srv.h @@ -62,21 +62,32 @@ public: Q_DECLARE_PRIVATE(Http11Reply) }; +enum class H2Type { + h2Alpn, // Secure connection, ALPN to negotiate h2. + h2c, // Clear text with protocol upgrade. + h2Direct, // Secure connection, ALPN not supported. + h2cDirect, // Clear text direct +}; + class Http2Server : public QTcpServer { Q_OBJECT public: - Http2Server(bool clearText, const Http2::RawSettings &serverSettings, + + Http2Server(H2Type type, const Http2::RawSettings &serverSettings, const Http2::RawSettings &clientSettings); ~Http2Server(); + // To be called before server started: void enablePushPromise(bool enabled, const QByteArray &path = QByteArray()); void setResponseBody(const QByteArray &body); void emulateGOAWAY(int timeout); void redirectOpenStream(quint16 targetPort); + bool isClearText() const; + // Invokables, since we can call them from the main thread, // but server (can) work on its own thread. Q_INVOKABLE void startServer(); @@ -129,6 +140,7 @@ private: QScopedPointer<QAbstractSocket> socket; + H2Type connectionType = H2Type::h2Alpn; // Connection preface: bool waitingClientPreface = false; bool waitingClientSettings = false; @@ -170,7 +182,6 @@ private: quint32 streamRecvWindowSize = Http2::defaultSessionWindowSize; QByteArray responseBody; - bool clearTextHTTP2 = false; bool pushPromiseEnabled = false; quint32 lastPromisedStream = 0; QByteArray pushPath; diff --git a/tests/auto/network/access/http2/tst_http2.cpp b/tests/auto/network/access/http2/tst_http2.cpp index 02c5e51cbe..53d0e7a694 100644 --- a/tests/auto/network/access/http2/tst_http2.cpp +++ b/tests/auto/network/access/http2/tst_http2.cpp @@ -60,6 +60,9 @@ const bool clearTextHTTP2 = false; const bool clearTextHTTP2 = true; #endif +Q_DECLARE_METATYPE(H2Type) +Q_DECLARE_METATYPE(QNetworkRequest::Attribute) + QT_BEGIN_NAMESPACE class tst_Http2 : public QObject @@ -70,6 +73,7 @@ public: ~tst_Http2(); private slots: // Tests: + void singleRequest_data(); void singleRequest(); void multipleRequests(); void flowControlClientSide(); @@ -101,13 +105,13 @@ private: // small payload. void runEventLoop(int ms = 5000); void stopEventLoop(); - Http2Server *newServer(const Http2::RawSettings &serverSettings, + Http2Server *newServer(const Http2::RawSettings &serverSettings, H2Type connectionType, const Http2::ProtocolParameters &clientSettings = {}); // Send a get or post request, depending on a payload (empty or not). void sendRequest(int streamNumber, QNetworkRequest::Priority priority = QNetworkRequest::NormalPriority, const QByteArray &payload = QByteArray()); - QUrl requestUrl() const; + QUrl requestUrl(H2Type connnectionType) const; quint16 serverPort = 0; QThread *workerThread = nullptr; @@ -144,6 +148,11 @@ struct ServerDeleter using ServerPtr = QScopedPointer<Http2Server, ServerDeleter>; +H2Type defaultConnectionType() +{ + return clearTextHTTP2 ? H2Type::h2c : H2Type::h2Alpn; +} + } // unnamed namespace tst_Http2::tst_Http2() @@ -165,25 +174,59 @@ tst_Http2::~tst_Http2() } } +void tst_Http2::singleRequest_data() +{ + QTest::addColumn<QNetworkRequest::Attribute>("h2Attribute"); + QTest::addColumn<H2Type>("connectionType"); + + // 'Clear text' that should always work, either via the protocol upgrade + // or as direct. + QTest::addRow("h2c-upgrade") << QNetworkRequest::HTTP2AllowedAttribute << H2Type::h2c; + QTest::addRow("h2c-direct") << QNetworkRequest::Http2DirectAttribute << H2Type::h2cDirect; + + if (!clearTextHTTP2) { + // Qt with TLS where TLS-backend supports ALPN. + QTest::addRow("h2-ALPN") << QNetworkRequest::HTTP2AllowedAttribute << H2Type::h2Alpn; + } + +#if QT_CONFIG(ssl) + QTest::addRow("h2-direct") << QNetworkRequest::Http2DirectAttribute << H2Type::h2Direct; +#endif +} + void tst_Http2::singleRequest() { clearHTTP2State(); +#if QT_CONFIG(securetransport) + // Normally on macOS we use plain text only for SecureTransport + // does not support ALPN on the server side. With 'direct encrytped' + // we have to use TLS sockets (== private key) and thus suppress a + // keychain UI asking for permission to use a private key. + // Our CI has this, but somebody testing locally - will have a problem. + qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", QByteArray("1")); + auto envRollback = qScopeGuard([](){ + qunsetenv("QT_SSL_USE_TEMPORARY_KEYCHAIN"); + }); +#endif + serverPort = 0; nRequests = 1; - ServerPtr srv(newServer(defaultServerSettings)); + QFETCH(const H2Type, connectionType); + ServerPtr srv(newServer(defaultServerSettings, connectionType)); QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection); runEventLoop(); QVERIFY(serverPort != 0); - auto url = requestUrl(); + auto url = requestUrl(connectionType); url.setPath("/index.html"); QNetworkRequest request(url); - request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, QVariant(true)); + QFETCH(const QNetworkRequest::Attribute, h2Attribute); + request.setAttribute(h2Attribute, QVariant(true)); auto reply = manager.get(request); connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished); @@ -208,7 +251,7 @@ void tst_Http2::multipleRequests() serverPort = 0; nRequests = 10; - ServerPtr srv(newServer(defaultServerSettings)); + ServerPtr srv(newServer(defaultServerSettings, defaultConnectionType())); QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection); @@ -259,7 +302,7 @@ void tst_Http2::flowControlClientSide() manager.setProperty(Http2::http2ParametersPropertyName, QVariant::fromValue(params)); const Http2::RawSettings serverSettings = {{Settings::MAX_CONCURRENT_STREAMS_ID, quint32(3)}}; - ServerPtr srv(newServer(serverSettings, params)); + ServerPtr srv(newServer(serverSettings, defaultConnectionType(), params)); const QByteArray respond(int(Http2::defaultSessionWindowSize * 10), 'x'); @@ -301,7 +344,7 @@ void tst_Http2::flowControlServerSide() const Http2::RawSettings serverSettings = {{Settings::MAX_CONCURRENT_STREAMS_ID, 7}}; - ServerPtr srv(newServer(serverSettings)); + ServerPtr srv(newServer(serverSettings, defaultConnectionType())); const QByteArray payload(int(Http2::defaultSessionWindowSize * 500), 'x'); @@ -336,7 +379,7 @@ void tst_Http2::pushPromise() params.settingsFrameData[Settings::ENABLE_PUSH_ID] = 1; manager.setProperty(Http2::http2ParametersPropertyName, QVariant::fromValue(params)); - ServerPtr srv(newServer(defaultServerSettings, params)); + ServerPtr srv(newServer(defaultServerSettings, defaultConnectionType(), params)); srv->enablePushPromise(true, QByteArray("/script.js")); QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection); @@ -344,7 +387,7 @@ void tst_Http2::pushPromise() QVERIFY(serverPort != 0); - auto url = requestUrl(); + auto url = requestUrl(defaultConnectionType()); url.setPath("/index.html"); QNetworkRequest request(url); @@ -410,14 +453,14 @@ void tst_Http2::goaway() serverPort = 0; nRequests = 3; - ServerPtr srv(newServer(defaultServerSettings)); + ServerPtr srv(newServer(defaultServerSettings, defaultConnectionType())); srv->emulateGOAWAY(responseTimeoutMS); QMetaObject::invokeMethod(srv.data(), "startServer", Qt::QueuedConnection); runEventLoop(); QVERIFY(serverPort != 0); - auto url = requestUrl(); + auto url = requestUrl(defaultConnectionType()); // We have to store these replies, so that we can check errors later. std::vector<QNetworkReply *> replies(nRequests); for (int i = 0; i < nRequests; ++i) { @@ -457,7 +500,7 @@ void tst_Http2::earlyResponse() serverPort = 0; nRequests = 1; - ServerPtr targetServer(newServer(defaultServerSettings)); + ServerPtr targetServer(newServer(defaultServerSettings, defaultConnectionType())); QMetaObject::invokeMethod(targetServer.data(), "startServer", Qt::QueuedConnection); runEventLoop(); @@ -467,7 +510,7 @@ void tst_Http2::earlyResponse() const quint16 targetPort = serverPort; serverPort = 0; - ServerPtr redirector(newServer(defaultServerSettings)); + ServerPtr redirector(newServer(defaultServerSettings, defaultConnectionType())); redirector->redirectOpenStream(targetPort); QMetaObject::invokeMethod(redirector.data(), "startServer", Qt::QueuedConnection); @@ -507,11 +550,11 @@ void tst_Http2::stopEventLoop() eventLoop.exitLoop(); } -Http2Server *tst_Http2::newServer(const Http2::RawSettings &serverSettings, +Http2Server *tst_Http2::newServer(const Http2::RawSettings &serverSettings, H2Type connectionType, const Http2::ProtocolParameters &clientSettings) { using namespace Http2; - auto srv = new Http2Server(clearTextHTTP2, serverSettings, + auto srv = new Http2Server(connectionType, serverSettings, clientSettings.settingsFrameData); using Srv = Http2Server; @@ -536,7 +579,7 @@ void tst_Http2::sendRequest(int streamNumber, QNetworkRequest::Priority priority, const QByteArray &payload) { - auto url = requestUrl(); + auto url = requestUrl(defaultConnectionType()); url.setPath(QString("/stream%1.html").arg(streamNumber)); QNetworkRequest request(url); @@ -555,10 +598,24 @@ void tst_Http2::sendRequest(int streamNumber, connect(reply, &QNetworkReply::finished, this, &tst_Http2::replyFinished); } -QUrl tst_Http2::requestUrl() const +QUrl tst_Http2::requestUrl(H2Type connectionType) const { +#if !QT_CONFIG(ssl) + Q_ASSERT(connectionType != H2Type::h2Alpn && connectionType != H2Type::h2Direct); +#endif static auto url = QUrl(QLatin1String(clearTextHTTP2 ? "http://127.0.0.1" : "https://127.0.0.1")); url.setPort(serverPort); + // Clear text may mean no-TLS-at-all or crappy-TLS-without-ALPN. + switch (connectionType) { + case H2Type::h2Alpn: + case H2Type::h2Direct: + url.setScheme(QStringLiteral("https")); + break; + case H2Type::h2c: + case H2Type::h2cDirect: + url.setScheme(QStringLiteral("http")); + break; + } return url; } |