summaryrefslogtreecommitdiffstats
path: root/tests/manual/network_stresstest/tst_network_stresstest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/manual/network_stresstest/tst_network_stresstest.cpp')
-rw-r--r--tests/manual/network_stresstest/tst_network_stresstest.cpp771
1 files changed, 771 insertions, 0 deletions
diff --git a/tests/manual/network_stresstest/tst_network_stresstest.cpp b/tests/manual/network_stresstest/tst_network_stresstest.cpp
new file mode 100644
index 0000000000..bce956cc75
--- /dev/null
+++ b/tests/manual/network_stresstest/tst_network_stresstest.cpp
@@ -0,0 +1,771 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QtCore/QThread>
+#include <QtCore/QSemaphore>
+#include <QtCore/QElapsedTimer>
+#include <QtCore/QSharedPointer>
+#include <QtCore/QVector>
+#include <QtNetwork/QTcpSocket>
+#include <QtNetwork/QNetworkReply>
+#include <QtNetwork/QNetworkAccessManager>
+
+#ifdef QT_BUILD_INTERNAL
+# include <private/qnetworkaccessmanager_p.h>
+#endif
+
+#include "minihttpserver.h"
+#include "../../auto/network-settings.h"
+
+#include <qplatformdefs.h>
+#ifdef Q_OS_UNIX
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <sys/select.h>
+# include <netinet/in.h>
+# include <errno.h>
+# include <netdb.h>
+# include <signal.h>
+# include <unistd.h>
+# include <fcntl.h>
+
+typedef int SOCKET;
+# define INVALID_SOCKET -1
+# define SOCKET_ERROR -1
+
+#elif defined(Q_OS_WIN)
+# include <winsock2.h>
+#endif
+
+class tst_NetworkStressTest : public QObject
+{
+ Q_OBJECT
+public:
+ enum { AttemptCount = 100 };
+ tst_NetworkStressTest();
+ MiniHttpServer server;
+
+ qint64 byteCounter;
+ QNetworkAccessManager manager;
+ bool intermediateDebug;
+
+private:
+ void clearManager();
+
+public slots:
+ void initTestCase_data();
+ void init();
+
+ void slotReadAll() { byteCounter += static_cast<QIODevice *>(sender())->readAll().size(); }
+
+private Q_SLOTS:
+ void nativeBlockingConnectDisconnect();
+ void nativeNonBlockingConnectDisconnect();
+ void blockingConnectDisconnect();
+ void blockingPipelined();
+ void blockingMultipleRequests();
+ void connectDisconnect();
+ void parallelConnectDisconnect_data();
+ void parallelConnectDisconnect();
+ void namGet_data();
+ void namGet();
+};
+
+tst_NetworkStressTest::tst_NetworkStressTest()
+ : intermediateDebug(qgetenv("STRESSDEBUG").toInt() > 0)
+{
+#ifdef Q_OS_WIN
+ WSAData wsadata;
+
+ // IPv6 requires Winsock v2.0 or better.
+ WSAStartup(MAKEWORD(2,0), &wsadata);
+#elif defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
+ ::signal(SIGALRM, SIG_IGN);
+#endif
+}
+
+void tst_NetworkStressTest::initTestCase_data()
+{
+ QTest::addColumn<bool>("isLocalhost");
+ QTest::addColumn<QString>("hostname");
+ QTest::addColumn<int>("port");
+
+ QTest::newRow("localhost") << true << "localhost" << server.port();
+ QTest::newRow("remote") << false << QtNetworkSettings::serverName() << 80;
+}
+
+void tst_NetworkStressTest::init()
+{
+ // clear the internal cache
+#ifndef QT_BUILD_INTERNAL
+ if (strncmp(QTest::currentTestFunction(), "nam") == 0)
+ QSKIP("QNetworkAccessManager tests disabled", SkipAll);
+#endif
+}
+
+void tst_NetworkStressTest::clearManager()
+{
+#ifdef QT_BUILD_INTERNAL
+ QNetworkAccessManagerPrivate::clearCache(&manager);
+ manager.setProxy(QNetworkProxy());
+ manager.setCache(0);
+#endif
+}
+
+bool nativeLookup(const char *hostname, int port, QByteArray &buf)
+{
+#if !defined(QT_NO_GETADDRINFO) && 0
+ addrinfo *res = 0;
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+
+ int result = getaddrinfo(QUrl::toAce(hostname).constData(), QByteArray::number(port).constData(), &hints, &res);
+ if (!result)
+ return false;
+ for (addrinfo *node = res; node; node = node->ai_next) {
+ if (node->ai_family == AF_INET) {
+ buf = QByteArray((char *)node->ai_addr, node->ai_addrlen);
+ break;
+ }
+ }
+ freeaddrinfo(res);
+#else
+ hostent *result = gethostbyname(hostname);
+ if (!result || result->h_addrtype != AF_INET)
+ return false;
+
+ struct sockaddr_in s;
+ s.sin_family = AF_INET;
+ s.sin_port = htons(port);
+ s.sin_addr = *(struct in_addr *) result->h_addr_list[0];
+
+ buf = QByteArray((char *)&s, sizeof s);
+#endif
+
+ return !buf.isEmpty();
+}
+
+bool nativeSelect(int fd, int timeout, bool selectForWrite)
+{
+ if (timeout < 0)
+ return false;
+
+ // wait for connected
+ fd_set fds, fde;
+ FD_ZERO(&fds);
+ FD_ZERO(&fde);
+ FD_SET(fd, &fds);
+ FD_SET(fd, &fde);
+
+ int ret;
+ do {
+ struct timeval tv;
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = timeout % 1000;
+ if (selectForWrite)
+ ret = ::select(fd + 1, 0, &fds, &fde, &tv);
+ else
+ ret = ::select(fd + 1, &fds, 0, &fde, &tv);
+ } while (ret == -1 && errno == EINTR);
+ return ret != 0;
+}
+
+void tst_NetworkStressTest::nativeBlockingConnectDisconnect()
+{
+ QFETCH_GLOBAL(QString, hostname);
+ QFETCH_GLOBAL(int, port);
+
+ qint64 totalBytes = 0;
+ QElapsedTimer outerTimer;
+ outerTimer.start();
+
+ for (int i = 0; i < AttemptCount; ++i) {
+ QElapsedTimer timeout;
+ byteCounter = 0;
+ timeout.start();
+
+#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
+ alarm(10);
+#endif
+
+ // look up the host
+ QByteArray addr;
+ if (!nativeLookup(QUrl::toAce(hostname).constData(), port, addr))
+ QFAIL("Lookup failed");
+
+ // connect
+ SOCKET fd = ::socket(AF_INET, SOCK_STREAM, 0);
+ QVERIFY(fd != INVALID_SOCKET);
+ QVERIFY(::connect(fd, (sockaddr *)addr.data(), addr.size()) != SOCKET_ERROR);
+
+ // send request
+ {
+ QByteArray request = "GET /qtest/bigfile HTTP/1.1\r\n"
+ "Connection: close\r\n"
+ "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
+ "Host: " + hostname.toLatin1() + "\r\n"
+ "\r\n";
+ qint64 bytesWritten = 0;
+ while (bytesWritten < request.size()) {
+ qint64 ret = ::send(fd, request.constData() + bytesWritten, request.size() - bytesWritten, 0);
+ if (ret == -1) {
+ ::close(fd);
+ QFAIL("Timeout");
+ }
+ bytesWritten += ret;
+ }
+ }
+
+ // receive reply
+ char buf[16384];
+ while (true) {
+ qint64 ret = ::recv(fd, buf, sizeof buf, 0);
+ if (ret == -1) {
+ ::close(fd);
+ QFAIL("Timeout");
+ } else if (ret == 0) {
+ break; // EOF
+ }
+ byteCounter += ret;
+ }
+ ::close(fd);
+
+ totalBytes += byteCounter;
+ if (intermediateDebug) {
+ double rate = (byteCounter * 1.0 / timeout.elapsed());
+ qDebug() << i << byteCounter << "bytes in" << timeout.elapsed() << "ms:"
+ << (rate / 1024.0 / 1024 * 1000) << "MB/s";
+ }
+ }
+ qDebug() << "Average transfer rate was" << (totalBytes / 1024.0 / 1024 * 1000 / outerTimer.elapsed()) << "MB/s";
+
+#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
+ alarm(0);
+#endif
+}
+
+void tst_NetworkStressTest::nativeNonBlockingConnectDisconnect()
+{
+ QFETCH_GLOBAL(QString, hostname);
+ QFETCH_GLOBAL(int, port);
+
+ qint64 totalBytes = 0;
+ QElapsedTimer outerTimer;
+ outerTimer.start();
+
+ for (int i = 0; i < AttemptCount; ++i) {
+ QElapsedTimer timeout;
+ byteCounter = 0;
+ timeout.start();
+
+ // look up the host
+ QByteArray addr;
+ if (!nativeLookup(QUrl::toAce(hostname).constData(), port, addr))
+ QFAIL("Lookup failed");
+
+ SOCKET fd;
+
+ {
+#if defined(Q_OS_UNIX)
+ fd = ::socket(AF_INET, SOCK_STREAM, 0);
+ QVERIFY(fd != INVALID_SOCKET);
+
+ // set the socket to non-blocking and start connecting
+# if !defined(Q_OS_VXWORKS)
+ int flags = ::fcntl(fd, F_GETFL, 0);
+ QVERIFY(flags != -1);
+ QVERIFY(::fcntl(fd, F_SETFL, flags | O_NONBLOCK) != -1);
+# else // Q_OS_VXWORKS
+ int onoff = 1;
+ QVERIFY(::ioctl(socketDescriptor, FIONBIO, &onoff) >= 0);
+# endif // Q_OS_VXWORKS
+ while (true) {
+ if (::connect(fd, (sockaddr *)addr.data(), addr.size()) == -1) {
+ QVERIFY2(errno == EINPROGRESS, QByteArray("Error connecting: ").append(strerror(errno)).constData());
+ QVERIFY2(nativeSelect(fd, 10000 - timeout.elapsed(), true), "Timeout");
+ } else {
+ break; // connected
+ }
+ }
+#elif defined(Q_OS_WIN)
+ fd = ::WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
+ QVERIFY(fd != INVALID_SOCKET);
+
+ // set the socket to non-blocking and start connecting
+ unsigned long buf = v;
+ unsigned long outBuf;
+ DWORD sizeWritten = 0;
+ QVERIFY(::WSAIoctl(fd, FIONBIO, &buf, sizeof(unsigned long), &outBuf, sizeof(unsigned long), &sizeWritten, 0,0) != SOCKET_ERROR);
+
+ while (true) {
+ int connectResult = ::WSAConnect(fd, sockAddrPtr, sockAddrSize, 0,0,0,0);
+ if (connectResult == 0 || WSAGetLastError() == WSAEISCONN) {
+ break; // connected
+ } else {
+ QVERIFY2(WSAGetLastError() == WSAEINPROGRESS, "Unexpected error");
+ QVERIFY2(nativeSelect(fd, 10000 - timeout.elapsed(), true), "Timeout");
+ }
+ }
+#endif
+ }
+
+ // send request
+ {
+ QByteArray request = "GET /qtest/bigfile HTTP/1.1\r\n"
+ "Connection: close\r\n"
+ "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
+ "Host: " + hostname.toLatin1() + "\r\n"
+ "\r\n";
+ qint64 bytesWritten = 0;
+ while (bytesWritten < request.size()) {
+ qint64 ret = ::send(fd, request.constData() + bytesWritten, request.size() - bytesWritten, 0);
+ if (ret == -1 && errno != EWOULDBLOCK) {
+ ::close(fd);
+ QFAIL(QByteArray("Error writing: ").append(strerror(errno)).constData());
+ } else if (ret == -1) {
+ // wait for writing
+ QVERIFY2(nativeSelect(fd, 10000 - timeout.elapsed(), true), "Timeout");
+ continue;
+ }
+ bytesWritten += ret;
+ }
+ }
+
+ // receive reply
+ char buf[16384];
+ while (true) {
+ qint64 ret = ::recv(fd, buf, sizeof buf, 0);
+ if (ret == -1 && errno != EWOULDBLOCK) {
+ ::close(fd);
+ QFAIL("Timeout");
+ } else if (ret == -1) {
+ // wait for reading
+ QVERIFY2(nativeSelect(fd, 10000 - timeout.elapsed(), false), "Timeout");
+ } else if (ret == 0) {
+ break; // EOF
+ }
+ byteCounter += ret;
+ }
+ ::close(fd);
+
+ totalBytes += byteCounter;
+ if (intermediateDebug) {
+ double rate = (byteCounter * 1.0 / timeout.elapsed());
+ qDebug() << i << byteCounter << "bytes in" << timeout.elapsed() << "ms:"
+ << (rate / 1024.0 / 1024 * 1000) << "MB/s";
+ }
+ }
+ qDebug() << "Average transfer rate was" << (totalBytes / 1024.0 / 1024 * 1000 / outerTimer.elapsed()) << "MB/s";
+}
+
+void tst_NetworkStressTest::blockingConnectDisconnect()
+{
+ QFETCH_GLOBAL(QString, hostname);
+ QFETCH_GLOBAL(int, port);
+
+ qint64 totalBytes = 0;
+ QElapsedTimer outerTimer;
+ outerTimer.start();
+
+ for (int i = 0; i < AttemptCount; ++i) {
+ QElapsedTimer timeout;
+ byteCounter = 0;
+ timeout.start();
+
+ QTcpSocket socket;
+ socket.connectToHost(hostname, port);
+ QVERIFY2(socket.waitForConnected(), "Timeout");
+
+ socket.write("GET /qtest/bigfile HTTP/1.1\r\n"
+ "Connection: close\r\n"
+ "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
+ "Host: " + hostname.toLatin1() + "\r\n"
+ "\r\n");
+ while (socket.bytesToWrite())
+ QVERIFY2(socket.waitForBytesWritten(), "Timeout");
+
+ while (socket.state() == QAbstractSocket::ConnectedState && !timeout.hasExpired(10000)) {
+ socket.waitForReadyRead();
+ byteCounter += socket.readAll().size(); // discard
+ }
+
+ totalBytes += byteCounter;
+ if (intermediateDebug) {
+ double rate = (byteCounter * 1.0 / timeout.elapsed());
+ qDebug() << i << byteCounter << "bytes in" << timeout.elapsed() << "ms:"
+ << (rate / 1024.0 / 1024 * 1000) << "MB/s";
+ }
+ }
+ qDebug() << "Average transfer rate was" << (totalBytes / 1024.0 / 1024 * 1000 / outerTimer.elapsed()) << "MB/s";
+}
+
+void tst_NetworkStressTest::blockingPipelined()
+{
+ QFETCH_GLOBAL(QString, hostname);
+ QFETCH_GLOBAL(int, port);
+
+ qint64 totalBytes = 0;
+ QElapsedTimer outerTimer;
+ outerTimer.start();
+
+ for (int i = 0; i < AttemptCount / 2; ++i) {
+ QElapsedTimer timeout;
+ byteCounter = 0;
+ timeout.start();
+
+ QTcpSocket socket;
+ socket.connectToHost(hostname, port);
+ QVERIFY2(socket.waitForConnected(), "Timeout");
+
+ for (int j = 0 ; j < 3; ++j) {
+ if (intermediateDebug)
+ qDebug("Attempt %d%c", i, 'a' + j);
+ socket.write("GET /qtest/bigfile HTTP/1.1\r\n"
+ "Connection: " + QByteArray(j == 2 ? "close" : "keep-alive") + "\r\n"
+ "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
+ "Host: " + hostname.toLatin1() + "\r\n"
+ "\r\n");
+ while (socket.bytesToWrite())
+ QVERIFY2(socket.waitForBytesWritten(), "Timeout");
+ }
+
+ while (socket.state() == QAbstractSocket::ConnectedState && !timeout.hasExpired(10000)) {
+ socket.waitForReadyRead();
+ byteCounter += socket.readAll().size(); // discard
+ }
+
+ totalBytes += byteCounter;
+ if (intermediateDebug) {
+ double rate = (byteCounter * 1.0 / timeout.elapsed());
+ qDebug() << i << byteCounter << "bytes in" << timeout.elapsed() << "ms:"
+ << (rate / 1024.0 / 1024 * 1000) << "MB/s";
+ }
+ }
+ qDebug() << "Average transfer rate was" << (totalBytes / 1024.0 / 1024 * 1000 / outerTimer.elapsed()) << "MB/s";
+}
+
+void tst_NetworkStressTest::blockingMultipleRequests()
+{
+ QFETCH_GLOBAL(QString, hostname);
+ QFETCH_GLOBAL(int, port);
+
+ qint64 totalBytes = 0;
+ QElapsedTimer outerTimer;
+ outerTimer.start();
+
+ for (int i = 0; i < AttemptCount / 5; ++i) {
+ QTcpSocket socket;
+ socket.connectToHost(hostname, port);
+ QVERIFY2(socket.waitForConnected(), "Timeout");
+
+ for (int j = 0 ; j < 5; ++j) {
+ QElapsedTimer timeout;
+ byteCounter = 0;
+ timeout.start();
+
+ socket.write("GET /qtest/bigfile HTTP/1.1\r\n"
+ "Connection: keep-alive\r\n"
+ "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
+ "Host: " + hostname.toLatin1() + "\r\n"
+ "\r\n");
+ while (socket.bytesToWrite())
+ QVERIFY2(socket.waitForBytesWritten(), "Timeout");
+
+ qint64 bytesRead = 0;
+ qint64 bytesExpected = -1;
+ QByteArray buffer;
+ while (socket.state() == QAbstractSocket::ConnectedState && !timeout.hasExpired(10000)) {
+ socket.waitForReadyRead();
+ buffer += socket.readAll();
+ byteCounter += buffer.size();
+ int pos = buffer.indexOf("\r\n\r\n");
+ if (pos == -1)
+ continue;
+
+ bytesRead = buffer.length() - pos - 4;
+
+ buffer.truncate(pos + 2);
+ buffer = buffer.toLower();
+ pos = buffer.indexOf("\r\ncontent-length: ");
+ if (pos == -1) {
+ qWarning() << "no content-length:" << QString(buffer);
+ break;
+ }
+ pos += strlen("\r\ncontent-length: ");
+
+ int eol = buffer.indexOf("\r\n", pos + 2);
+ if (eol == -1) {
+ qWarning() << "invalid header";
+ break;
+ }
+
+ bytesExpected = buffer.mid(pos, eol - pos).toLongLong();
+ break;
+ }
+ QVERIFY(bytesExpected > 0);
+ QVERIFY2(!timeout.hasExpired(10000), "Timeout");
+
+ while (socket.state() == QAbstractSocket::ConnectedState && !timeout.hasExpired(10000) && bytesExpected > bytesRead) {
+ socket.waitForReadyRead();
+ int blocklen = socket.read(bytesExpected - bytesRead).length(); // discard
+ bytesRead += blocklen;
+ byteCounter += blocklen;
+ }
+ QVERIFY2(!timeout.hasExpired(10000), "Timeout");
+ QCOMPARE(bytesRead, bytesExpected);
+
+ totalBytes += byteCounter;
+ if (intermediateDebug) {
+ double rate = (byteCounter * 1.0 / timeout.elapsed());
+ qDebug() << i << byteCounter << "bytes in" << timeout.elapsed() << "ms:"
+ << (rate / 1024.0 / 1024 * 1000) << "MB/s";
+ }
+ }
+
+ socket.disconnectFromHost();
+ QVERIFY(socket.state() == QAbstractSocket::UnconnectedState);
+ }
+ qDebug() << "Average transfer rate was" << (totalBytes / 1024.0 / 1024 * 1000 / outerTimer.elapsed()) << "MB/s";
+}
+
+void tst_NetworkStressTest::connectDisconnect()
+{
+ QFETCH_GLOBAL(QString, hostname);
+ QFETCH_GLOBAL(int, port);
+
+ qint64 totalBytes = 0;
+ QElapsedTimer outerTimer;
+ outerTimer.start();
+
+ for (int i = 0; i < AttemptCount; ++i) {
+ QElapsedTimer timeout;
+ byteCounter = 0;
+ timeout.start();
+
+ QTcpSocket socket;
+ socket.connectToHost(hostname, port);
+
+ socket.write("GET /qtest/bigfile HTTP/1.1\r\n"
+ "Connection: close\r\n"
+ "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
+ "Host: " + hostname.toLatin1() + "\r\n"
+ "\r\n");
+ connect(&socket, SIGNAL(readyRead()), SLOT(slotReadAll()));
+
+ QTestEventLoop::instance().connect(&socket, SIGNAL(disconnected()), SLOT(exitLoop()));
+ QTestEventLoop::instance().enterLoop(30);
+ QVERIFY2(!QTestEventLoop::instance().timeout(), "Timeout");
+
+ totalBytes += byteCounter;
+ if (intermediateDebug) {
+ double rate = (byteCounter * 1.0 / timeout.elapsed());
+ qDebug() << i << byteCounter << "bytes in" << timeout.elapsed() << "ms:"
+ << (rate / 1024.0 / 1024 * 1000) << "MB/s";
+ }
+ }
+ qDebug() << "Average transfer rate was" << (totalBytes / 1024.0 / 1024 * 1000 / outerTimer.elapsed()) << "MB/s";
+}
+
+void tst_NetworkStressTest::parallelConnectDisconnect_data()
+{
+ QTest::addColumn<int>("parallelAttempts");
+ QTest::newRow("1") << 1;
+ QTest::newRow("2") << 2;
+ QTest::newRow("4") << 4;
+ QTest::newRow("5") << 5;
+ QTest::newRow("6") << 6;
+ QTest::newRow("8") << 8;
+ QTest::newRow("10") << 10;
+ QTest::newRow("25") << 25;
+ QTest::newRow("100") << 100;
+ QTest::newRow("500") << 500;
+}
+
+void tst_NetworkStressTest::parallelConnectDisconnect()
+{
+ QFETCH_GLOBAL(QString, hostname);
+ QFETCH_GLOBAL(int, port);
+ QFETCH(int, parallelAttempts);
+
+ if (parallelAttempts > 100) {
+ QFETCH_GLOBAL(bool, isLocalhost);
+ if (!isLocalhost)
+ QSKIP("Localhost-only test", SkipSingle);
+ }
+
+ qint64 totalBytes = 0;
+ QElapsedTimer outerTimer;
+ outerTimer.start();
+
+ for (int i = 0; i < qMax(2, AttemptCount/qMax(2, parallelAttempts/4)); ++i) {
+ QElapsedTimer timeout;
+ byteCounter = 0;
+ timeout.start();
+
+ QTcpSocket *socket = new QTcpSocket[parallelAttempts];
+ for (int j = 0; j < parallelAttempts; ++j) {
+ socket[j].connectToHost(hostname, port);
+
+ socket[j].write("GET /qtest/bigfile HTTP/1.1\r\n"
+ "Connection: close\r\n"
+ "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
+ "Host: " + hostname.toLatin1() + "\r\n"
+ "\r\n");
+ connect(&socket[j], SIGNAL(readyRead()), SLOT(slotReadAll()));
+
+ QTestEventLoop::instance().connect(&socket[j], SIGNAL(disconnected()), SLOT(exitLoop()));
+ }
+
+ while (!timeout.hasExpired(30000)) {
+ QTestEventLoop::instance().enterLoop(10);
+ int done = 0;
+ for (int j = 0; j < parallelAttempts; ++j)
+ done += socket[j].state() == QAbstractSocket::UnconnectedState ? 1 : 0;
+ if (done == parallelAttempts)
+ break;
+ }
+ delete[] socket;
+ QVERIFY2(!timeout.hasExpired(30000), "Timeout");
+
+ totalBytes += byteCounter;
+ if (intermediateDebug) {
+ double rate = (byteCounter * 1.0 / timeout.elapsed());
+ qDebug() << i << byteCounter << "bytes in" << timeout.elapsed() << "ms:"
+ << (rate / 1024.0 / 1024 * 1000) << "MB/s";
+ }
+ }
+ qDebug() << "Average transfer rate was" << (totalBytes / 1024.0 / 1024 * 1000 / outerTimer.elapsed()) << "MB/s";
+}
+
+void tst_NetworkStressTest::namGet_data()
+{
+ QTest::addColumn<int>("parallelAttempts");
+ QTest::addColumn<bool>("pipelineAllowed");
+
+ QTest::newRow("1") << 1 << false;
+ QTest::newRow("1p") << 1 << true;
+ QTest::newRow("2") << 2 << false;
+ QTest::newRow("2p") << 2 << true;
+ QTest::newRow("4") << 4 << false;
+ QTest::newRow("4p") << 4 << true;
+ QTest::newRow("5") << 5 << false;
+ QTest::newRow("5p") << 5 << true;
+ QTest::newRow("6") << 6 << false;
+ QTest::newRow("6p") << 6 << true;
+ QTest::newRow("8") << 8 << false;
+ QTest::newRow("8p") << 8 << true;
+ QTest::newRow("10") << 10 << false;
+ QTest::newRow("10p") << 10 << true;
+ QTest::newRow("25") << 25 << false;
+ QTest::newRow("25p") << 25 << true;
+ QTest::newRow("100") << 100 << false;
+ QTest::newRow("100p") << 100 << true;
+ QTest::newRow("500") << 500 << false;
+ QTest::newRow("500p") << 500 << true;
+}
+
+void tst_NetworkStressTest::namGet()
+{
+ QFETCH_GLOBAL(QString, hostname);
+ QFETCH_GLOBAL(int, port);
+ QFETCH(int, parallelAttempts);
+ QFETCH(bool, pipelineAllowed);
+
+ if (parallelAttempts > 100) {
+ QFETCH_GLOBAL(bool, isLocalhost);
+ if (!isLocalhost)
+ QSKIP("Localhost-only test", SkipSingle);
+ }
+
+ qint64 totalBytes = 0;
+ QElapsedTimer outerTimer;
+ outerTimer.start();
+
+ for (int i = 0; i < qMax(2, AttemptCount/qMax(2, parallelAttempts/4)); ++i) {
+ QElapsedTimer timeout;
+ byteCounter = 0;
+ timeout.start();
+
+ QUrl url;
+ url.setScheme("http");
+ url.setHost(hostname);
+ url.setPort(port);
+ url.setEncodedPath("/qtest/bigfile");
+ QNetworkRequest req(url);
+ req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, pipelineAllowed);
+
+ QVector<QSharedPointer<QNetworkReply> > replies;
+ replies.resize(parallelAttempts);
+ for (int j = 0; j < parallelAttempts; ++j) {
+ QNetworkReply *r = manager.get(req);
+
+ connect(r, SIGNAL(readyRead()), SLOT(slotReadAll()));
+ QTestEventLoop::instance().connect(r, SIGNAL(finished()), SLOT(exitLoop()));
+
+ replies[j] = QSharedPointer<QNetworkReply>(r);
+ }
+
+ while (!timeout.hasExpired(30000)) {
+ QTestEventLoop::instance().enterLoop(10);
+ int done = 0;
+ for (int j = 0; j < parallelAttempts; ++j)
+ done += replies[j]->isFinished() ? 1 : 0;
+ if (done == parallelAttempts)
+ break;
+ }
+ replies.clear();
+
+ QVERIFY2(!timeout.hasExpired(30000), "Timeout");
+ totalBytes += byteCounter;
+ if (intermediateDebug) {
+ double rate = (byteCounter * 1.0 / timeout.elapsed());
+ qDebug() << i << byteCounter << "bytes in" << timeout.elapsed() << "ms:"
+ << (rate / 1024.0 / 1024 * 1000) << "MB/s";
+ }
+ }
+ qDebug() << "Average transfer rate was" << (totalBytes / 1024.0 / 1024 * 1000 / outerTimer.elapsed()) << "MB/s";
+}
+
+QTEST_MAIN(tst_NetworkStressTest);
+
+#include "tst_network_stresstest.moc"