diff options
Diffstat (limited to 'tests/auto/qnetworkreply')
-rw-r--r-- | tests/auto/qnetworkreply/.gitattributes | 5 | ||||
-rw-r--r-- | tests/auto/qnetworkreply/echo/echo.pro | 2 | ||||
-rw-r--r-- | tests/auto/qnetworkreply/qnetworkreply.pro | 2 | ||||
-rw-r--r-- | tests/auto/qnetworkreply/test/test.pro | 14 | ||||
-rw-r--r-- | tests/auto/qnetworkreply/tst_qnetworkreply.cpp | 1043 |
5 files changed, 930 insertions, 136 deletions
diff --git a/tests/auto/qnetworkreply/.gitattributes b/tests/auto/qnetworkreply/.gitattributes index f0cae99..80252cf 100644 --- a/tests/auto/qnetworkreply/.gitattributes +++ b/tests/auto/qnetworkreply/.gitattributes @@ -1,2 +1,3 @@ -rfc3252.txt -crlf -bigfile -crlf +rfc3252.txt -crlf +bigfile -crlf +resource -crlf diff --git a/tests/auto/qnetworkreply/echo/echo.pro b/tests/auto/qnetworkreply/echo/echo.pro index bf791ff..74b0bfc 100644 --- a/tests/auto/qnetworkreply/echo/echo.pro +++ b/tests/auto/qnetworkreply/echo/echo.pro @@ -3,4 +3,4 @@ QT = core CONFIG -= app_bundle debug_and_release_target CONFIG += console - +symbian:TARGET.CAPABILITY="ALL -TCB" diff --git a/tests/auto/qnetworkreply/qnetworkreply.pro b/tests/auto/qnetworkreply/qnetworkreply.pro index 0bcf067..fd8454c 100644 --- a/tests/auto/qnetworkreply/qnetworkreply.pro +++ b/tests/auto/qnetworkreply/qnetworkreply.pro @@ -1,4 +1,6 @@ TEMPLATE = subdirs SUBDIRS = test +requires(contains(QT_CONFIG,private_tests)) + !wince*:SUBDIRS += echo diff --git a/tests/auto/qnetworkreply/test/test.pro b/tests/auto/qnetworkreply/test/test.pro index 71f76a2..e0df503 100644 --- a/tests/auto/qnetworkreply/test/test.pro +++ b/tests/auto/qnetworkreply/test/test.pro @@ -10,7 +10,7 @@ win32 { } } -DEFINES += SRCDIR=\\\"$$PWD/..\\\" +!symbian:DEFINES += SRCDIR=\\\"$$PWD/..\\\" QT = core network RESOURCES += ../qnetworkreply.qrc @@ -20,3 +20,15 @@ wince*: { addFiles.path = . DEPLOYMENT += addFiles } + +symbian:{ + addFiles.sources = ../empty ../rfc3252.txt ../resource ../bigfile + addFiles.path = . + DEPLOYMENT += addFiles + + # Symbian toolchain does not support correct include semantics + INCPATH+=..\..\..\..\include\QtNetwork\private + # bigfile test case requires more heap + TARGET.EPOCHEAPSIZE="0x100 0x1000000" + TARGET.CAPABILITY="ALL -TCB" +} diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp index 48a48f4..a223d1c 100644 --- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp @@ -52,6 +52,7 @@ #include <QtNetwork/QTcpSocket> #include <QtNetwork/QLocalSocket> #include <QtNetwork/QLocalServer> +#include <QtNetwork/QHostInfo> #include <QtNetwork/QFtp> #include <QtNetwork/qauthenticator.h> #include <QtNetwork/qnetworkaccessmanager.h> @@ -67,8 +68,16 @@ #include "private/qnetworkaccessmanager_p.h" +#ifdef Q_OS_SYMBIAN +// In Symbian OS test data is located in applications private dir +// Current path (C:\private\<UID>) contains only ascii chars +//#define SRCDIR QDir::currentPath() +#define SRCDIR "." +#endif + #include "../network-settings.h" + Q_DECLARE_METATYPE(QNetworkReply*) Q_DECLARE_METATYPE(QAuthenticator*) Q_DECLARE_METATYPE(QNetworkProxy) @@ -91,6 +100,15 @@ class tst_QNetworkReply: public QObject { Q_OBJECT + struct ProxyData { + ProxyData(const QNetworkProxy &p, const QByteArray &t, bool auth) + : tag(t), proxy(p), requiresAuthentication(auth) + { } + QByteArray tag; + QNetworkProxy proxy; + bool requiresAuthentication; + }; + QEventLoop *loop; enum RunSimpleRequestReturn { Timeout = 0, Success, Failure }; int returnCode; @@ -99,14 +117,17 @@ class tst_QNetworkReply: public QObject QString wronlyFileName; #endif QString uniqueExtension; + QList<ProxyData> proxies; QNetworkAccessManager manager; MyCookieJar *cookieJar; #ifndef QT_NO_OPENSSL QSslConfiguration storedSslConfiguration; + QList<QSslError> storedExpectedSslErrors; #endif public: tst_QNetworkReply(); + ~tst_QNetworkReply(); QString runSimpleRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &request, QNetworkReplyPtr &reply, const QByteArray &data = QByteArray()); @@ -115,9 +136,11 @@ public Q_SLOTS: void gotError(); void authenticationRequired(QNetworkReply*,QAuthenticator*); void proxyAuthenticationRequired(const QNetworkProxy &,QAuthenticator*); + #ifndef QT_NO_OPENSSL void sslErrors(QNetworkReply*,const QList<QSslError> &); void storeSslConfiguration(); + void ignoreSslErrorListSlot(QNetworkReply *reply, const QList<QSslError> &); #endif protected Q_SLOTS: @@ -150,6 +173,10 @@ private Q_SLOTS: void putToHttp(); void postToHttp_data(); void postToHttp(); + void deleteFromHttp_data(); + void deleteFromHttp(); + void putGetDeleteGetFromHttp_data(); + void putGetDeleteGetFromHttp(); void ioGetFromData_data(); void ioGetFromData(); @@ -192,12 +219,23 @@ private Q_SLOTS: void ioPutToHttpFromFile(); void ioPostToHttpFromFile_data(); void ioPostToHttpFromFile(); + void ioPostToHttpFromSocket_data(); + void ioPostToHttpFromSocket(); + void ioPostToHttpFromMiddleOfFileToEnd(); + void ioPostToHttpFromMiddleOfFileFiveBytes(); + void ioPostToHttpFromMiddleOfQBufferFiveBytes(); + void ioPostToHttpNoBufferFlag(); + void ioPostToHttpUploadProgress(); + void ioPostToHttpEmtpyUploadProgress(); void rateControl_data(); void rateControl(); void downloadPerformance(); void uploadPerformance(); void performanceControlRate(); + void httpUploadPerformance(); + void httpDownloadPerformance_data(); + void httpDownloadPerformance(); void downloadProgress_data(); void downloadProgress(); @@ -220,8 +258,14 @@ private Q_SLOTS: void authorizationError_data(); void authorizationError(); - void httpDownloadPerformance_data(); - void httpDownloadPerformance(); + void httpConnectionCount(); + +#ifndef QT_NO_OPENSSL + void ignoreSslErrorsList_data(); + void ignoreSslErrorsList(); + void ignoreSslErrorsListWithSlot_data(); + void ignoreSslErrorsListWithSlot(); +#endif }; QT_BEGIN_NAMESPACE @@ -371,6 +415,63 @@ public slots: } }; +class FixedSizeDataGenerator : public QIODevice +{ + Q_OBJECT + enum { Idle, Started, Stopped } state; +public: + FixedSizeDataGenerator(qint64 size) : state(Idle) + { open(ReadOnly | Unbuffered); + toBeGeneratedTotalCount = toBeGeneratedCount = size; + } + + virtual qint64 bytesAvailable() const + { + return state == Started ? toBeGeneratedCount + QIODevice::bytesAvailable() : 0; + } + + virtual bool isSequential() const{ + return false; + } + + virtual bool reset() const{ + return false; + } + + qint64 size() const { + return toBeGeneratedTotalCount; + } + +public slots: + void start() { state = Started; emit readyRead(); } + +protected: + virtual qint64 readData(char *data, qint64 maxlen) + { + memset(data, '@', maxlen); + + if (toBeGeneratedCount <= 0) { + return -1; + } + + qint64 n = qMin(maxlen, toBeGeneratedCount); + toBeGeneratedCount -= n; + + if (toBeGeneratedCount <= 0) { + // make sure this is a queued connection! + emit readChannelFinished(); + } + + return n; + } + virtual qint64 writeData(const char *, qint64) + { return -1; } + + qint64 toBeGeneratedCount; + qint64 toBeGeneratedTotalCount; +}; + + class DataGenerator: public QIODevice { Q_OBJECT @@ -391,6 +492,7 @@ protected: { if (state == Stopped) return -1; // EOF + // return as many bytes as are wanted memset(data, '@', maxlen); return maxlen; @@ -399,6 +501,8 @@ protected: { return -1; } }; + + class SocketPair: public QObject { Q_OBJECT @@ -418,11 +522,22 @@ public: QTcpSocket *active = new QTcpSocket(this); active->connectToHost("127.0.0.1", server.serverPort()); - if (!active->waitForConnected(10)) +#ifndef Q_OS_SYMBIAN + // need more time as working with embedded + // device and testing from emualtor + // things tend to get slower + if (!active->waitForConnected(1000)) + return false; + + if (!server.waitForNewConnection(1000)) + return false; +#else + if (!active->waitForConnected(100)) return false; - if (!server.waitForNewConnection(10)) + if (!server.waitForNewConnection(100)) return false; +#endif QTcpSocket *passive = server.nextPendingConnection(); passive->setParent(this); @@ -636,7 +751,7 @@ protected: return; transferRate = totalBytes * 1000 / timer.elapsed(); - qDebug() << "receive rate:" << (transferRate / 1024) << "kB/s in" + qDebug() << "TimedSender::run" << "receive rate:" << (transferRate / 1024) << "kB/s in" << timer.elapsed() << "ms"; } @@ -650,12 +765,13 @@ protected: class ThreadedDataReader: public QThread { Q_OBJECT + // used to make the constructor only return after the tcp server started listening QSemaphore ready; QTcpSocket *client; int timeout; int port; public: - int transferRate; + qint64 transferRate; ThreadedDataReader() : port(-1), transferRate(-1) { @@ -683,14 +799,155 @@ protected: QTime timer; timer.start(); eventLoop.exec(); + qint64 elapsed = timer.elapsed(); + + transferRate = reader.totalBytes * 1000 / elapsed; + qDebug() << "ThreadedDataReader::run" << "send rate:" << (transferRate / 1024) << "kB/s in" << elapsed << "msec"; + } +}; + +class ThreadedDataReaderHttpServer: public QThread +{ + Q_OBJECT + // used to make the constructor only return after the tcp server started listening + QSemaphore ready; + QTcpSocket *client; + int timeout; + int port; +public: + qint64 transferRate; + ThreadedDataReaderHttpServer() + : port(-1), transferRate(-1) + { + start(); + ready.acquire(); + } + + inline int serverPort() const { return port; } + +protected: + void run() + { + QTcpServer server; + server.listen(); + port = server.serverPort(); + ready.release(); + + server.waitForNewConnection(-1); + client = server.nextPendingConnection(); + client->write("HTTP/1.0 200 OK\r\n"); + client->write("Content-length: 0\r\n"); + client->write("\r\n"); + client->flush(); + + QCoreApplication::processEvents(); + + QEventLoop eventLoop; + DataReader reader(client, false); + QObject::connect(client, SIGNAL(disconnected()), &eventLoop, SLOT(quit())); + + QTime timer; + timer.start(); + eventLoop.exec(); + qint64 elapsed = timer.elapsed(); - transferRate = reader.totalBytes * 1000 / timer.elapsed(); - qDebug() << "send rate:" << (transferRate / 1024) << "kB/s"; + transferRate = reader.totalBytes * 1000 / elapsed; + qDebug() << "ThreadedDataReaderHttpServer::run" << "send rate:" << (transferRate / 1024) << "kB/s in" << elapsed << "msec"; } }; +class HttpDownloadPerformanceClient : QObject { + Q_OBJECT; + QIODevice *device; + public: + HttpDownloadPerformanceClient (QIODevice *dev) : device(dev){ + connect(dev, SIGNAL(readyRead()), this, SLOT(readyReadSlot())); + } + + public slots: + void readyReadSlot() { + device->readAll(); + } + +}; + +class HttpDownloadPerformanceServer : QObject { + Q_OBJECT; + qint64 dataSize; + qint64 dataSent; + QTcpServer server; + QTcpSocket *client; + bool serverSendsContentLength; + bool chunkedEncoding; + +public: + HttpDownloadPerformanceServer (qint64 ds, bool sscl, bool ce) : dataSize(ds), dataSent(0), + client(0), serverSendsContentLength(sscl), chunkedEncoding(ce) { + server.listen(); + connect(&server, SIGNAL(newConnection()), this, SLOT(newConnectionSlot())); + } + + int serverPort() { + return server.serverPort(); + } + +public slots: + + void newConnectionSlot() { + client = server.nextPendingConnection(); + client->setParent(this); + connect(client, SIGNAL(readyRead()), this, SLOT(readyReadSlot())); + connect(client, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWrittenSlot(qint64))); + } + + void readyReadSlot() { + client->readAll(); + client->write("HTTP/1.0 200 OK\n"); + if (serverSendsContentLength) + client->write(QString("Content-Length: " + QString::number(dataSize) + "\n").toAscii()); + if (chunkedEncoding) + client->write(QString("Transfer-Encoding: chunked\n").toAscii()); + client->write("Connection: close\n\n"); + } + + void bytesWrittenSlot(qint64 amount) { + Q_UNUSED(amount); + if (dataSent == dataSize && client) { + // close eventually + + // chunked encoding: we have to send a last "empty" chunk + if (chunkedEncoding) + client->write(QString("0\r\n\r\n").toAscii()); + + client->disconnectFromHost(); + server.close(); + client = 0; + return; + } + + // send data + if (client && client->bytesToWrite() < 100*1024 && dataSent < dataSize) { + qint64 amount = qMin(qint64(16*1024), dataSize - dataSent); + QByteArray data(amount, '@'); + + if (chunkedEncoding) { + client->write(QString(QString("%1").arg(amount,0,16).toUpper() + "\r\n").toAscii()); + client->write(data.constData(), amount); + client->write(QString("\r\n").toAscii()); + } else { + client->write(data.constData(), amount); + } + + dataSent += amount; + } + } +}; + + tst_QNetworkReply::tst_QNetworkReply() { + Q_SET_DEFAULT_IAP + testFileName = QDir::currentPath() + "/testfile"; #ifndef Q_OS_WINCE uniqueExtension = QString("%1%2%3").arg((qulonglong)this).arg(rand()).arg((qulonglong)time(0)); @@ -699,8 +956,31 @@ tst_QNetworkReply::tst_QNetworkReply() #endif cookieJar = new MyCookieJar; manager.setCookieJar(cookieJar); + + QHostInfo hostInfo = QHostInfo::fromName(QtNetworkSettings::serverName()); + + proxies << ProxyData(QNetworkProxy::NoProxy, "", false); + + if (hostInfo.error() == QHostInfo::NoError && !hostInfo.addresses().isEmpty()) { + QString proxyserver = hostInfo.addresses().first().toString(); + proxies << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3128), "+proxy", false) + << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3129), "+proxyauth", true) + // currently unsupported + // << ProxyData(QNetworkProxy(QNetworkProxy::HttpProxy, proxyserver, 3130), "+proxyauth-ntlm", true); + << ProxyData(QNetworkProxy(QNetworkProxy::Socks5Proxy, proxyserver, 1080), "+socks", false) + << ProxyData(QNetworkProxy(QNetworkProxy::Socks5Proxy, proxyserver, 1081), "+socksauth", true); + } else { + printf("==================================================================\n"); + printf("Proxy could not be looked up. No proxy will be used while testing!\n"); + printf("==================================================================\n"); + } } +tst_QNetworkReply::~tst_QNetworkReply() +{ +} + + void tst_QNetworkReply::authenticationRequired(QNetworkReply*, QAuthenticator* auth) { auth->setUser("httptest"); @@ -752,6 +1032,10 @@ QString tst_QNetworkReply::runSimpleRequest(QNetworkAccessManager::Operation op, reply = manager.post(request, data); break; + case QNetworkAccessManager::DeleteOperation: + reply = manager.deleteResource(request); + break; + default: Q_ASSERT_X(false, "tst_QNetworkReply", "Invalid/unknown operation requested"); } @@ -840,6 +1124,7 @@ void tst_QNetworkReply::stateChecking() QCOMPARE(reply->request(), req); QCOMPARE(int(reply->operation()), int(QNetworkAccessManager::GetOperation)); QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->isFinished(), false); QCOMPARE(reply->url(), url); reply->abort(); @@ -861,7 +1146,7 @@ void tst_QNetworkReply::invalidProtocol() void tst_QNetworkReply::getFromData_data() { - QTest::addColumn<QString>("request"); + QTest::addColumn<QString>("request"); QTest::addColumn<QByteArray>("expected"); QTest::addColumn<QString>("mimeType"); @@ -957,7 +1242,7 @@ void tst_QNetworkReply::getFromData() void tst_QNetworkReply::getFromFile() { - // create the file: + // create the file: QTemporaryFile file(QDir::currentPath() + "/temp-XXXXXX"); file.setAutoRemove(true); QVERIFY(file.open()); @@ -1009,7 +1294,7 @@ void tst_QNetworkReply::getFromFileSpecial_data() void tst_QNetworkReply::getFromFileSpecial() { - QFETCH(QString, fileName); + QFETCH(QString, fileName); QFETCH(QString, url); // open the resource so we can find out its size @@ -1039,7 +1324,7 @@ void tst_QNetworkReply::getFromFtp_data() void tst_QNetworkReply::getFromFtp() { - QFETCH(QString, referenceName); + QFETCH(QString, referenceName); QFETCH(QString, url); QFile reference(referenceName); @@ -1068,7 +1353,7 @@ void tst_QNetworkReply::getFromHttp_data() void tst_QNetworkReply::getFromHttp() { - QFETCH(QString, referenceName); + QFETCH(QString, referenceName); QFETCH(QString, url); QFile reference(referenceName); @@ -1108,7 +1393,7 @@ void tst_QNetworkReply::getErrors_data() << int(QNetworkReply::ContentOperationNotPermittedError) << 0 << true; QTest::newRow("file-exist") << QUrl::fromLocalFile(QDir::currentPath() + "/this-file-doesnt-exist.txt").toString() << int(QNetworkReply::ContentNotFoundError) << 0 << true; -#if !defined Q_OS_WIN +#if !defined Q_OS_WIN && !defined(Q_OS_SYMBIAN) QTest::newRow("file-is-wronly") << QUrl::fromLocalFile(wronlyFileName).toString() << int(QNetworkReply::ContentAccessDenied) << 0 << true; #endif @@ -1163,6 +1448,9 @@ void tst_QNetworkReply::getErrors() QTEST(reply->readAll().isEmpty(), "dataIsEmpty"); + QVERIFY(reply->isFinished()); + QVERIFY(!reply->isRunning()); + QFETCH(int, httpStatusCode); if (httpStatusCode != 0) { QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), httpStatusCode); @@ -1329,6 +1617,97 @@ void tst_QNetworkReply::postToHttp() QCOMPARE(uploadedData, md5sum.toHex()); } +void tst_QNetworkReply::deleteFromHttp_data() +{ + QTest::addColumn<QUrl>("url"); + QTest::addColumn<int>("resultCode"); + QTest::addColumn<QNetworkReply::NetworkError>("error"); + + // for status codes to expect, see http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html + + QTest::newRow("405-method-not-allowed") << QUrl("http://" + QtNetworkSettings::serverName() + "/index.html") << 405 << QNetworkReply::ContentOperationNotPermittedError; + QTest::newRow("200-ok") << QUrl("http://" + QtNetworkSettings::serverName() + "/cgi-bin/http-delete.cgi?200-ok") << 200 << QNetworkReply::NoError; + QTest::newRow("202-accepted") << QUrl("http://" + QtNetworkSettings::serverName() + "/cgi-bin/http-delete.cgi?202-accepted") << 202 << QNetworkReply::NoError; + QTest::newRow("204-no-content") << QUrl("http://" + QtNetworkSettings::serverName() + "/cgi-bin/http-delete.cgi?204-no-content") << 204 << QNetworkReply::NoError; + QTest::newRow("404-not-found") << QUrl("http://" + QtNetworkSettings::serverName() + "/cgi-bin/http-delete.cgi?404-not-found") << 404 << QNetworkReply::ContentNotFoundError; +} + +void tst_QNetworkReply::deleteFromHttp() +{ + QFETCH(QUrl, url); + QFETCH(int, resultCode); + QFETCH(QNetworkReply::NetworkError, error); + QNetworkRequest request(url); + QNetworkReplyPtr reply; + runSimpleRequest(QNetworkAccessManager::DeleteOperation, request, reply, 0); + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), error); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), resultCode); +} + +void tst_QNetworkReply::putGetDeleteGetFromHttp_data() +{ + QTest::addColumn<QUrl>("putUrl"); + QTest::addColumn<int>("putResultCode"); + QTest::addColumn<QNetworkReply::NetworkError>("putError"); + QTest::addColumn<QUrl>("deleteUrl"); + QTest::addColumn<int>("deleteResultCode"); + QTest::addColumn<QNetworkReply::NetworkError>("deleteError"); + QTest::addColumn<QUrl>("get2Url"); + QTest::addColumn<int>("get2ResultCode"); + QTest::addColumn<QNetworkReply::NetworkError>("get2Error"); + + QUrl url("http://" + QtNetworkSettings::serverName()); + url.setPath(QString("/dav/qnetworkaccess-putToHttp-%1-%2") + .arg(QTest::currentDataTag()) + .arg(uniqueExtension)); + + // first use case: put, get (to check it is there), delete, get (to check it is not there anymore) + QTest::newRow("success") << url << 201 << QNetworkReply::NoError << url << 204 << QNetworkReply::NoError << url << 404 << QNetworkReply::ContentNotFoundError; + + QUrl wrongUrl("http://" + QtNetworkSettings::serverName()); + wrongUrl.setPath(QString("/dav/qnetworkaccess-thisURLisNotAvailable")); + + // second use case: put, get (to check it is there), delete wrong URL, get (to check it is still there) + QTest::newRow("delete-error") << url << 201 << QNetworkReply::NoError << wrongUrl << 404 << QNetworkReply::ContentNotFoundError << url << 200 << QNetworkReply::NoError; + +} + +void tst_QNetworkReply::putGetDeleteGetFromHttp() +{ + QFETCH(QUrl, putUrl); + QFETCH(int, putResultCode); + QFETCH(QNetworkReply::NetworkError, putError); + QFETCH(QUrl, deleteUrl); + QFETCH(int, deleteResultCode); + QFETCH(QNetworkReply::NetworkError, deleteError); + QFETCH(QUrl, get2Url); + QFETCH(int, get2ResultCode); + QFETCH(QNetworkReply::NetworkError, get2Error); + + QNetworkRequest putRequest(putUrl); + QNetworkRequest deleteRequest(deleteUrl); + QNetworkRequest get2Request(get2Url); + QNetworkReplyPtr reply; + + RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, putRequest, reply, 0)); + QCOMPARE(reply->error(), putError); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), putResultCode); + + runSimpleRequest(QNetworkAccessManager::GetOperation, putRequest, reply, 0); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + + runSimpleRequest(QNetworkAccessManager::DeleteOperation, deleteRequest, reply, 0); + QCOMPARE(reply->error(), deleteError); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), deleteResultCode); + + runSimpleRequest(QNetworkAccessManager::GetOperation, get2Request, reply, 0); + QCOMPARE(reply->error(), get2Error); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), get2ResultCode); + +} + void tst_QNetworkReply::ioGetFromData_data() { QTest::addColumn<QString>("urlStr"); @@ -1902,8 +2281,11 @@ void tst_QNetworkReply::ioGetFromHttpBrokenServer_data() QTest::addColumn<bool>("doDisconnect"); QTest::newRow("no-newline") << QByteArray("Hello World") << false; - QTest::newRow("just-newline") << QByteArray("\r\n") << false; - QTest::newRow("just-2newline") << QByteArray("\r\n\r\n") << false; + + // these are OK now, we just eat the lonely newlines + //QTest::newRow("just-newline") << QByteArray("\r\n") << false; + //QTest::newRow("just-2newline") << QByteArray("\r\n\r\n") << false; + QTest::newRow("with-newlines") << QByteArray("Long first line\r\nLong second line") << false; QTest::newRow("with-newlines2") << QByteArray("\r\nSecond line") << false; QTest::newRow("with-newlines3") << QByteArray("ICY\r\nSecond line") << false; @@ -2171,7 +2553,6 @@ void tst_QNetworkReply::ioGetWithManyProxies() connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), SLOT(sslErrors(QNetworkReply*,QList<QSslError>))); #endif - QTestEventLoop::instance().enterLoop(10); QVERIFY(!QTestEventLoop::instance().timeout()); @@ -2338,18 +2719,19 @@ void tst_QNetworkReply::ioPutToFileFromProcess_data() void tst_QNetworkReply::ioPutToFileFromProcess() { -#if defined(Q_OS_WINCE) - QSKIP("Currently no stdin/out supported for Windows CE", SkipAll); +#if defined(Q_OS_WINCE) || defined (Q_OS_SYMBIAN) + QSKIP("Currently no stdin/out supported for Windows CE / Symbian OS", SkipAll); #endif + #ifdef Q_OS_WIN if (qstrcmp(QTest::currentDataTag(), "small") == 0) QSKIP("When passing a CR-LF-LF sequence through Windows stdio, it gets converted, " "so this test fails. Disabled on Windows", SkipSingle); #endif + #if defined(QT_NO_PROCESS) QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll); #else - QFile file(testFileName); QUrl url = QUrl::fromLocalFile(file.fileName()); @@ -2508,6 +2890,324 @@ void tst_QNetworkReply::ioPostToHttpFromFile() QCOMPARE(reply->readAll().trimmed(), md5sum(sourceFile.readAll()).toHex()); } +void tst_QNetworkReply::ioPostToHttpFromSocket_data() +{ + QTest::addColumn<QByteArray>("data"); + QTest::addColumn<QByteArray>("md5sum"); + QTest::addColumn<QUrl>("url"); + QTest::addColumn<QNetworkProxy>("proxy"); + QTest::addColumn<int>("authenticationRequiredCount"); + QTest::addColumn<int>("proxyAuthenticationRequiredCount"); + + for (int i = 0; i < proxies.count(); ++i) + for (int auth = 0; auth < 2; ++auth) { + QUrl url; + if (auth) + url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"; + else + url = "http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi"; + + QNetworkProxy proxy = proxies.at(i).proxy; + QByteArray testsuffix = QByteArray(auth ? "+auth" : "") + proxies.at(i).tag; + int proxyauthcount = proxies.at(i).requiresAuthentication; + + QByteArray data; + data = ""; + QTest::newRow("empty" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount; + + data = "This is a normal message."; + QTest::newRow("generic" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount; + + data = "This is a message to show that Qt rocks!\r\n\n"; + QTest::newRow("small" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount; + + data = QByteArray("abcd\0\1\2\abcd",12); + QTest::newRow("with-nul" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount; + + data = QByteArray(4097, '\4'); + QTest::newRow("4k+1" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount; + + data = QByteArray(128*1024+1, '\177'); + QTest::newRow("128k+1" + testsuffix) << data << md5sum(data) << url << proxy << auth << proxyauthcount; + } +} + +void tst_QNetworkReply::ioPostToHttpFromSocket() +{ + qRegisterMetaType<QNetworkProxy>(); // for QSignalSpy + qRegisterMetaType<QAuthenticator *>(); + qRegisterMetaType<QNetworkReply *>(); + + QFETCH(QByteArray, data); + QFETCH(QUrl, url); + QFETCH(QNetworkProxy, proxy); + SocketPair socketpair; + socketpair.create(); + QVERIFY(socketpair.endPoints[0] && socketpair.endPoints[1]); + + socketpair.endPoints[0]->write(data); + + QNetworkRequest request(url); + manager.setProxy(proxy); + QNetworkReplyPtr reply = manager.post(QNetworkRequest(url), socketpair.endPoints[1]); + socketpair.endPoints[0]->close(); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + connect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + + QSignalSpy authenticationRequiredSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*))); + QSignalSpy proxyAuthenticationRequiredSpy(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + +#ifdef Q_OS_SYMBIAN + QTestEventLoop::instance().enterLoop(6); +#else + QTestEventLoop::instance().enterLoop(3); +#endif + + disconnect(&manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), + this, SLOT(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*))); + disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), QNetworkReply::NoError); + // verify that the HTTP status code is 200 Ok + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + + QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex()); + + QTEST(authenticationRequiredSpy.count(), "authenticationRequiredCount"); + QTEST(proxyAuthenticationRequiredSpy.count(), "proxyAuthenticationRequiredCount"); + } + +// this tests checks if rewinding the POST-data to some place in the middle +// worked. +void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileToEnd() +{ + QFile sourceFile(SRCDIR "/rfc3252.txt"); + QVERIFY(sourceFile.open(QIODevice::ReadOnly)); + // seeking to the middle + sourceFile.seek(sourceFile.size() / 2); + + QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"; + QNetworkRequest request(url); + QNetworkReplyPtr reply = manager.post(QNetworkRequest(url), &sourceFile); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + + QTestEventLoop::instance().enterLoop(2); + disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + QVERIFY(!QTestEventLoop::instance().timeout()); + + // compare half data + sourceFile.seek(sourceFile.size() / 2); + QByteArray data = sourceFile.readAll(); + QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex()); +} + +void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileFiveBytes() +{ + QFile sourceFile(SRCDIR "/rfc3252.txt"); + QVERIFY(sourceFile.open(QIODevice::ReadOnly)); + // seeking to the middle + sourceFile.seek(sourceFile.size() / 2); + + QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"; + QNetworkRequest request(url); + // only send 5 bytes + request.setHeader(QNetworkRequest::ContentLengthHeader, 5); + QVERIFY(request.header(QNetworkRequest::ContentLengthHeader).isValid()); + QNetworkReplyPtr reply = manager.post(request, &sourceFile); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + + QTestEventLoop::instance().enterLoop(2); + disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + QVERIFY(!QTestEventLoop::instance().timeout()); + + // compare half data + sourceFile.seek(sourceFile.size() / 2); + QByteArray data = sourceFile.read(5); + QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex()); +} + +void tst_QNetworkReply::ioPostToHttpFromMiddleOfQBufferFiveBytes() +{ + // test needed since a QBuffer goes with a different codepath than the QFile + // tested in ioPostToHttpFromMiddleOfFileFiveBytes + QBuffer uploadBuffer; + uploadBuffer.open(QIODevice::ReadWrite); + uploadBuffer.write("1234567890"); + uploadBuffer.seek(5); + + QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"; + QNetworkRequest request(url); + QNetworkReplyPtr reply = manager.post(request, &uploadBuffer); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + + QTestEventLoop::instance().enterLoop(2); + disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + QVERIFY(!QTestEventLoop::instance().timeout()); + + // compare half data + uploadBuffer.seek(5); + QByteArray data = uploadBuffer.read(5); + QCOMPARE(reply->readAll().trimmed(), md5sum(data).toHex()); +} + + +void tst_QNetworkReply::ioPostToHttpNoBufferFlag() +{ + QByteArray data = QByteArray("daaaaaaataaaaaaa"); + // create a sequential QIODevice by feeding the data into a local TCP server + SocketPair socketpair; + socketpair.create(); + QVERIFY(socketpair.endPoints[0] && socketpair.endPoints[1]); + socketpair.endPoints[0]->write(data); + + QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"; + QNetworkRequest request(url); + // disallow buffering + request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, true); + request.setHeader(QNetworkRequest::ContentLengthHeader, data.size()); + QNetworkReplyPtr reply = manager.post(request, socketpair.endPoints[1]); + socketpair.endPoints[0]->close(); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + + QTestEventLoop::instance().enterLoop(2); + disconnect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), + this, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*))); + + // verify: error code is QNetworkReply::ContentReSendError + QCOMPARE(reply->error(), QNetworkReply::ContentReSendError); +} + + +void tst_QNetworkReply::ioPostToHttpUploadProgress() +{ + QFile sourceFile(SRCDIR "/bigfile"); + QVERIFY(sourceFile.open(QIODevice::ReadOnly)); + + // emulate a minimal http server + QTcpServer server; + server.listen(QHostAddress(QHostAddress::LocalHost), 0); + + // create the request + QUrl url = QUrl(QString("http://127.0.0.1:%1/").arg(server.serverPort())); + QNetworkRequest request(url); + QNetworkReplyPtr reply = manager.post(request, &sourceFile); + QSignalSpy spy(reply, SIGNAL(uploadProgress(qint64,qint64))); + connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop())); + + // get the request started and the incoming socket connected + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + QTcpSocket *incomingSocket = server.nextPendingConnection(); + QVERIFY(incomingSocket); + disconnect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop())); + + incomingSocket->setReadBufferSize(1*1024); + QTestEventLoop::instance().enterLoop(2); + // some progress should have been made + QList<QVariant> args = spy.last(); + QVERIFY(!args.isEmpty()); + QVERIFY(args.at(0).toLongLong() > 0); + + incomingSocket->setReadBufferSize(32*1024); + incomingSocket->read(16*1024); + QTestEventLoop::instance().enterLoop(2); + // some more progress than before + QList<QVariant> args2 = spy.last(); + QVERIFY(!args2.isEmpty()); + QVERIFY(args2.at(0).toLongLong() > args.at(0).toLongLong()); + + // set the read buffer to unlimited + incomingSocket->setReadBufferSize(0); + QTestEventLoop::instance().enterLoop(10); + // progress should be finished + QList<QVariant> args3 = spy.last(); + QVERIFY(!args3.isEmpty()); + QVERIFY(args3.at(0).toLongLong() > args2.at(0).toLongLong()); + QCOMPARE(args3.at(0).toLongLong(), args3.at(1).toLongLong()); + QCOMPARE(args3.at(0).toLongLong(), sourceFile.size()); + + // after sending this, the QNAM should emit finished() + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + incomingSocket->write("HTTP/1.0 200 OK\r\n"); + incomingSocket->write("Content-Length: 0\r\n"); + incomingSocket->write("\r\n"); + QTestEventLoop::instance().enterLoop(10); + // not timeouted -> finished() was emitted + QVERIFY(!QTestEventLoop::instance().timeout()); + + incomingSocket->close(); + server.close(); +} + +void tst_QNetworkReply::ioPostToHttpEmtpyUploadProgress() +{ + QByteArray ba; + ba.resize(0); + QBuffer buffer(&ba,0); + QVERIFY(buffer.open(QIODevice::ReadOnly)); + + // emulate a minimal http server + QTcpServer server; + server.listen(QHostAddress(QHostAddress::LocalHost), 0); + + // create the request + QUrl url = QUrl(QString("http://127.0.0.1:%1/").arg(server.serverPort())); + QNetworkRequest request(url); + QNetworkReplyPtr reply = manager.post(request, &buffer); + QSignalSpy spy(reply, SIGNAL(uploadProgress(qint64,qint64))); + connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop())); + + + // get the request started and the incoming socket connected + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + QTcpSocket *incomingSocket = server.nextPendingConnection(); + QVERIFY(incomingSocket); + + // after sending this, the QNAM should emit finished() + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + incomingSocket->write("HTTP/1.0 200 OK\r\n"); + incomingSocket->write("Content-Length: 0\r\n"); + incomingSocket->write("\r\n"); + incomingSocket->flush(); + QTestEventLoop::instance().enterLoop(10); + // not timeouted -> finished() was emitted + QVERIFY(!QTestEventLoop::instance().timeout()); + + // final check: only 1 uploadProgress has been emitted + QVERIFY(spy.length() == 1); + QList<QVariant> args = spy.last(); + QVERIFY(!args.isEmpty()); + QCOMPARE(args.at(0).toLongLong(), buffer.size()); + QCOMPARE(args.at(0).toLongLong(), buffer.size()); + + incomingSocket->close(); + server.close(); +} + + void tst_QNetworkReply::rateControl_data() { QTest::addColumn<int>("rate"); @@ -2544,8 +3244,8 @@ void tst_QNetworkReply::rateControl() QTestEventLoop::instance().enterLoop(40); int elapsedTime = loopTime.elapsed(); - qDebug() << "send rate:" << sender.transferRate; - qDebug() << "receive rate:" << reader.totalBytesRead * 1000 / elapsedTime + qDebug() << "tst_QNetworkReply::rateControl" << "send rate:" << sender.transferRate; + qDebug() << "tst_QNetworkReply::rateControl" << "receive rate:" << reader.totalBytesRead * 1000 / elapsedTime << "(it received" << reader.totalBytesRead << "bytes in" << elapsedTime << "ms)"; sender.wait(); @@ -2565,7 +3265,6 @@ void tst_QNetworkReply::downloadPerformance() { // unlike the above function, this one tries to send as fast as possible // and measures how fast it was. - TimedSender sender(5000); QNetworkRequest request("debugpipe://127.0.0.1:" + QString::number(sender.serverPort()) + "/?bare=1"); QNetworkReplyPtr reply = manager.get(request); @@ -2579,23 +3278,59 @@ void tst_QNetworkReply::downloadPerformance() sender.wait(); qint64 receivedBytes = reader.totalBytes; - qDebug() << "receive rate:" << (receivedBytes * 1000 / elapsedTime / 1024) << "kB/s and" + qDebug() << "tst_QNetworkReply::downloadPerformance" << "receive rate:" << (receivedBytes * 1000 / elapsedTime / 1024) << "kB/s and" << elapsedTime << "ms"; } void tst_QNetworkReply::uploadPerformance() { - ThreadedDataReader reader; - DataGenerator generator; - QNetworkRequest request("debugpipe://127.0.0.1:" + QString::number(reader.serverPort()) + "/?bare=1"); - QNetworkReplyPtr reply = manager.put(request, &generator); + ThreadedDataReader reader; + DataGenerator generator; - connect(&reader, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); - QTimer::singleShot(5000, &generator, SLOT(stop())); - generator.start(); - QTestEventLoop::instance().enterLoop(40); + + QNetworkRequest request("debugpipe://127.0.0.1:" + QString::number(reader.serverPort()) + "/?bare=1"); + QNetworkReplyPtr reply = manager.put(request, &generator); + generator.start(); + connect(&reader, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTimer::singleShot(5000, &generator, SLOT(stop())); + + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); } +void tst_QNetworkReply::httpUploadPerformance() +{ +#ifdef Q_OS_SYMBIAN + // SHow some mercy for non-desktop platform/s + enum {UploadSize = 4*1024*1024}; // 4 MB +#else + enum {UploadSize = 128*1024*1024}; // 128 MB +#endif + ThreadedDataReaderHttpServer reader; + FixedSizeDataGenerator generator(UploadSize); + + QNetworkRequest request(QUrl("http://127.0.0.1:" + QString::number(reader.serverPort()) + "/?bare=1")); + request.setHeader(QNetworkRequest::ContentLengthHeader,UploadSize); + + QNetworkReplyPtr reply = manager.put(request, &generator); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + + QTime time; + generator.start(); + time.start(); + QTestEventLoop::instance().enterLoop(40); + QVERIFY(!QTestEventLoop::instance().timeout()); + + qint64 elapsed = time.elapsed(); + qDebug() << "tst_QNetworkReply::httpUploadPerformance" << elapsed << "msec, " + << ((UploadSize/1024.0)/(elapsed/1000.0)) << " kB/sec"; + + reader.exit(); + reader.wait(); +} + + void tst_QNetworkReply::performanceControlRate() { // this is a control comparison for the other two above @@ -2616,17 +3351,63 @@ void tst_QNetworkReply::performanceControlRate() sender.wait(); qint64 receivedBytes = reader.totalBytes; - qDebug() << "receive rate:" << (receivedBytes * 1000 / elapsedTime / 1024) << "kB/s and" + qDebug() << "tst_QNetworkReply::performanceControlRate" << "receive rate:" << (receivedBytes * 1000 / elapsedTime / 1024) << "kB/s and" << elapsedTime << "ms"; } +void tst_QNetworkReply::httpDownloadPerformance_data() +{ + QTest::addColumn<bool>("serverSendsContentLength"); + QTest::addColumn<bool>("chunkedEncoding"); + + QTest::newRow("Server sends no Content-Length") << false << false; + QTest::newRow("Server sends Content-Length") << true << false; + QTest::newRow("Server uses chunked encoding") << false << true; + +} + +void tst_QNetworkReply::httpDownloadPerformance() +{ + QFETCH(bool, serverSendsContentLength); + QFETCH(bool, chunkedEncoding); +#ifdef Q_OS_SYMBIAN + // Show some mercy to non-desktop platform/s + enum {UploadSize = 4*1024*1024}; // 4 MB +#else + enum {UploadSize = 128*1024*1024}; // 128 MB +#endif + HttpDownloadPerformanceServer server(UploadSize, serverSendsContentLength, chunkedEncoding); + + QNetworkRequest request(QUrl("http://127.0.0.1:" + QString::number(server.serverPort()) + "/?bare=1")); + QNetworkReplyPtr reply = manager.get(request); + + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection); + HttpDownloadPerformanceClient client(reply); + + QTime time; + time.start(); + QTestEventLoop::instance().enterLoop(40); + QVERIFY(!QTestEventLoop::instance().timeout()); + + qint64 elapsed = time.elapsed(); + qDebug() << "tst_QNetworkReply::httpDownloadPerformance" << elapsed << "msec, " + << ((UploadSize/1024.0)/(elapsed/1000.0)) << " kB/sec"; +} + void tst_QNetworkReply::downloadProgress_data() { QTest::addColumn<int>("loopCount"); QTest::newRow("empty") << 0; QTest::newRow("small") << 4; +#ifndef Q_OS_SYMBIAN QTest::newRow("big") << 4096; +#else + // it can run even with 4096 + // but it takes lot time + //especially on emulator + QTest::newRow("big") << 1024; +#endif } void tst_QNetworkReply::downloadProgress() @@ -2640,6 +3421,8 @@ void tst_QNetworkReply::downloadProgress() connect(reply, SIGNAL(downloadProgress(qint64,qint64)), &QTestEventLoop::instance(), SLOT(exitLoop())); QVERIFY(spy.isValid()); + QVERIFY(!reply->isFinished()); + QVERIFY(reply->isRunning()); QCoreApplication::instance()->processEvents(); if (!server.hasPendingConnections()) @@ -2649,6 +3432,7 @@ void tst_QNetworkReply::downloadProgress() QByteArray data(128, 'a'); QTcpSocket *sender = server.nextPendingConnection(); + QVERIFY(sender); QFETCH(int, loopCount); for (int i = 1; i <= loopCount; ++i) { @@ -2659,6 +3443,8 @@ void tst_QNetworkReply::downloadProgress() QTestEventLoop::instance().enterLoop(2); QVERIFY(!QTestEventLoop::instance().timeout()); QVERIFY(spy.count() > 0); + QVERIFY(!reply->isFinished()); + QVERIFY(reply->isRunning()); QList<QVariant> args = spy.last(); QCOMPARE(args.at(0).toInt(), i*data.size()); @@ -2672,6 +3458,8 @@ void tst_QNetworkReply::downloadProgress() QTestEventLoop::instance().enterLoop(2); QVERIFY(!QTestEventLoop::instance().timeout()); QVERIFY(spy.count() > 0); + QVERIFY(!reply->isRunning()); + QVERIFY(reply->isFinished()); QList<QVariant> args = spy.last(); QCOMPARE(args.at(0).toInt(), loopCount * data.size()); @@ -2802,7 +3590,7 @@ void tst_QNetworkReply::receiveCookiesFromHttp_data() void tst_QNetworkReply::receiveCookiesFromHttp() { - QFETCH(QString, cookieString); + QFETCH(QString, cookieString); QByteArray data = cookieString.toLatin1() + '\n'; QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/set-cookie.cgi"); @@ -2932,7 +3720,7 @@ void tst_QNetworkReply::httpProxyCommands_data() << QUrl("http://0.0.0.0:4443/http-request") << QByteArray("HTTP/1.0 200 OK\r\nProxy-Connection: close\r\nContent-Length: 1\r\n\r\n1") << "GET http://0.0.0.0:4443/http-request HTTP/1."; -#ifndef QT_NO_SSL +#ifndef QT_NO_OPENSSL QTest::newRow("https") << QUrl("https://0.0.0.0:4443/https-request") << QByteArray("HTTP/1.0 200 Connection Established\r\n\r\n") @@ -2955,7 +3743,9 @@ void tst_QNetworkReply::httpProxyCommands() // wait for the finished signal connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(1); + QVERIFY(!QTestEventLoop::instance().timeout()); //qDebug() << reply->error() << reply->errorString(); @@ -2985,7 +3775,15 @@ void tst_QNetworkReply::proxyChange() QNetworkReplyPtr reply2 = manager.get(req); connect(reply2, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); +#ifdef Q_OS_SYMBIAN + // we need more time as: + // 1. running from the emulator + // 2. not perfect POSIX implementation + // 3. embedded device + QTestEventLoop::instance().enterLoop(20); +#else QTestEventLoop::instance().enterLoop(10); +#endif QVERIFY(!QTestEventLoop::instance().timeout()); if (finishedspy.count() == 0) { @@ -3071,129 +3869,110 @@ void tst_QNetworkReply::authorizationError() QCOMPARE(QString(reply->readAll()), httpBody); } -class HttpDownloadPerformanceClient : QObject { - Q_OBJECT; - QIODevice *device; - public: - HttpDownloadPerformanceClient (QIODevice *dev) : device(dev){ - connect(dev, SIGNAL(readyRead()), this, SLOT(readyReadSlot())); - } - - public slots: - void readyReadSlot() { - device->readAll(); - } - -}; - -class HttpDownloadPerformanceServer : QObject { - Q_OBJECT; - qint64 dataSize; - qint64 dataSent; +void tst_QNetworkReply::httpConnectionCount() +{ QTcpServer server; - QTcpSocket *client; - bool serverSendsContentLength; - bool chunkedEncoding; - -public: - HttpDownloadPerformanceServer (qint64 ds, bool sscl, bool ce) : dataSize(ds), dataSent(0), - client(0), serverSendsContentLength(sscl), chunkedEncoding(ce) { - server.listen(); - connect(&server, SIGNAL(newConnection()), this, SLOT(newConnectionSlot())); - } + QVERIFY(server.listen()); + QCoreApplication::instance()->processEvents(); - int serverPort() { - return server.serverPort(); + for (int i = 0; i < 10; i++) { + QNetworkRequest request (QUrl("http://127.0.0.1:" + QString::number(server.serverPort()) + "/" + QString::number(i))); + QNetworkReply* reply = manager.get(request); + reply->setParent(this); } -public slots: + int pendingConnectionCount = 0; + QTime time; + time.start(); - void newConnectionSlot() { - client = server.nextPendingConnection(); - client->setParent(this); - connect(client, SIGNAL(readyRead()), this, SLOT(readyReadSlot())); - connect(client, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWrittenSlot(qint64))); - } + while(pendingConnectionCount != 6) { + QCoreApplication::instance()->processEvents(); + while (server.nextPendingConnection()) + pendingConnectionCount++; - void readyReadSlot() { - client->readAll(); - client->write("HTTP/1.0 200 OK\n"); - if (serverSendsContentLength) - client->write(QString("Content-Length: " + QString::number(dataSize) + "\n").toAscii()); - if (chunkedEncoding) - client->write(QString("Transfer-Encoding: chunked\n").toAscii()); - client->write("Connection: close\n\n"); + // at max. wait 10 sec + if (time.elapsed() > 10000) + break; } - void bytesWrittenSlot(qint64 amount) { - Q_UNUSED(amount); - if (dataSent == dataSize && client) { - // close eventually + QCOMPARE(pendingConnectionCount, 6); +} - // chunked encoding: we have to send a last "empty" chunk - if (chunkedEncoding) - client->write(QString("0\r\n\r\n").toAscii()); +#ifndef QT_NO_OPENSSL +void tst_QNetworkReply::ignoreSslErrorsList_data() +{ + QTest::addColumn<QString>("url"); + QTest::addColumn<QList<QSslError> >("expectedSslErrors"); + QTest::addColumn<QNetworkReply::NetworkError>("expectedNetworkError"); - client->disconnectFromHost(); - server.close(); - client = 0; - return; - } + QList<QSslError> expectedSslErrors; + // apparently, because of some weird behaviour of SRCDIR, the file name below needs to start with a slash + QList<QSslCertificate> certs = QSslCertificate::fromPath(QLatin1String(SRCDIR "/../qsslsocket/certs/qt-test-server-cacert.pem")); + QSslError rightError(QSslError::SelfSignedCertificate, certs.at(0)); + QSslError wrongError(QSslError::SelfSignedCertificate); - // send data - if (client && client->bytesToWrite() < 100*1024 && dataSent < dataSize) { - qint64 amount = qMin(qint64(16*1024), dataSize - dataSent); - QByteArray data(amount, '@'); + QTest::newRow("SSL-failure-empty-list") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::SslHandshakeFailedError; + expectedSslErrors.append(wrongError); + QTest::newRow("SSL-failure-wrong-error") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::SslHandshakeFailedError; + expectedSslErrors.append(rightError); + QTest::newRow("allErrorsInExpectedList1") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::NoError; + expectedSslErrors.removeAll(wrongError); + QTest::newRow("allErrorsInExpectedList2") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::NoError; + expectedSslErrors.removeAll(rightError); + QTest::newRow("SSL-failure-empty-list-again") << "https://" + QtNetworkSettings::serverName() + "/index.html" << expectedSslErrors << QNetworkReply::SslHandshakeFailedError; +} - if (chunkedEncoding) { - client->write(QString(QString("%1").arg(amount,0,16).toUpper() + "\r\n").toAscii()); - client->write(data.constData(), amount); - client->write(QString("\r\n").toAscii()); - } else { - client->write(data.constData(), amount); - } +void tst_QNetworkReply::ignoreSslErrorsList() +{ + QFETCH(QString, url); + QNetworkRequest request(url); + QNetworkReplyPtr reply = manager.get(request); - dataSent += amount; - } - } -}; + QFETCH(QList<QSslError>, expectedSslErrors); + reply->ignoreSslErrors(expectedSslErrors); -void tst_QNetworkReply::httpDownloadPerformance_data() -{ - QTest::addColumn<bool>("serverSendsContentLength"); - QTest::addColumn<bool>("chunkedEncoding"); + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); - QTest::newRow("Server sends no Content-Length") << false << false; - QTest::newRow("Server sends Content-Length") << true << false; - QTest::newRow("Server uses chunked encoding") << false << true; + QFETCH(QNetworkReply::NetworkError, expectedNetworkError); + QCOMPARE(reply->error(), expectedNetworkError); +} +void tst_QNetworkReply::ignoreSslErrorsListWithSlot_data() +{ + ignoreSslErrorsList_data(); } -void tst_QNetworkReply::httpDownloadPerformance() +// this is not a test, just a slot called in the test below +void tst_QNetworkReply::ignoreSslErrorListSlot(QNetworkReply *reply, const QList<QSslError> &) { - QFETCH(bool, serverSendsContentLength); - QFETCH(bool, chunkedEncoding); + reply->ignoreSslErrors(storedExpectedSslErrors); +} - enum {UploadSize = 1000*1024*1024}; // 1000 MB - HttpDownloadPerformanceServer server(UploadSize, serverSendsContentLength, chunkedEncoding); +// do the same as in ignoreSslErrorsList, but ignore the errors in the slot +void tst_QNetworkReply::ignoreSslErrorsListWithSlot() +{ + QFETCH(QString, url); + QNetworkRequest request(url); + QNetworkReplyPtr reply = manager.get(request); - QNetworkRequest request(QUrl("http://127.0.0.1:" + QString::number(server.serverPort()) + "/?bare=1")); - QNetworkReply* reply = manager.get(request); + QFETCH(QList<QSslError>, expectedSslErrors); + // store the errors to ignore them later in the slot connected below + storedExpectedSslErrors = expectedSslErrors; + connect(&manager, SIGNAL(sslErrors(QNetworkReply *, const QList<QSslError> &)), + this, SLOT(ignoreSslErrorListSlot(QNetworkReply *, const QList<QSslError> &))); - connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection); - HttpDownloadPerformanceClient client(reply); - QTime time; - time.start(); - QTestEventLoop::instance().enterLoop(40); + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + QTestEventLoop::instance().enterLoop(10); QVERIFY(!QTestEventLoop::instance().timeout()); - qint64 elapsed = time.elapsed(); - qDebug() << "tst_QNetworkReply::httpDownloadPerformance" << elapsed << "msec, " - << ((UploadSize/1024.0)/(elapsed/1000.0)) << " kB/sec"; - - delete reply; + QFETCH(QNetworkReply::NetworkError, expectedNetworkError); + QCOMPARE(reply->error(), expectedNetworkError); } +#endif // QT_NO_OPENSSL + QTEST_MAIN(tst_QNetworkReply) #include "tst_qnetworkreply.moc" |