mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-05 16:55:25 +08:00
qt 6.5.1 original
This commit is contained in:
22
tests/benchmarks/network/CMakeLists.txt
Normal file
22
tests/benchmarks/network/CMakeLists.txt
Normal file
@ -0,0 +1,22 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
# SSL library include path is not propagated with private tests which results in
|
||||
# test not being able to find the ssl header when they are not in the standard
|
||||
# include paths
|
||||
if (QT_FEATURE_private_tests)
|
||||
if (QT_FEATURE_openssl AND QT_FEATURE_openssl_linked AND QT_FEATURE_ssl)
|
||||
include_directories($<TARGET_PROPERTY:OpenSSL::SSL,INTERFACE_INCLUDE_DIRECTORIES>)
|
||||
endif()
|
||||
|
||||
if (QT_FEATURE_openssl AND QT_FEATURE_ssl AND NOT QT_FEATURE_openssl_linked)
|
||||
include_directories($<TARGET_PROPERTY:WrapOpenSSLHeaders::WrapOpenSSLHeaders,INTERFACE_INCLUDE_DIRECTORIES>)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_subdirectory(access)
|
||||
add_subdirectory(kernel)
|
||||
add_subdirectory(socket)
|
||||
if(QT_FEATURE_openssl)
|
||||
add_subdirectory(ssl)
|
||||
endif()
|
10
tests/benchmarks/network/access/CMakeLists.txt
Normal file
10
tests/benchmarks/network/access/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
add_subdirectory(qfile_vs_qnetworkaccessmanager)
|
||||
add_subdirectory(qnetworkreply)
|
||||
add_subdirectory(qnetworkreply_from_cache)
|
||||
add_subdirectory(qnetworkdiskcache)
|
||||
if(QT_FEATURE_private_tests)
|
||||
add_subdirectory(qdecompresshelper)
|
||||
endif()
|
BIN
tests/benchmarks/network/access/qdecompresshelper/50mb.txt.br
Normal file
BIN
tests/benchmarks/network/access/qdecompresshelper/50mb.txt.br
Normal file
Binary file not shown.
BIN
tests/benchmarks/network/access/qdecompresshelper/50mb.txt.gz
Normal file
BIN
tests/benchmarks/network/access/qdecompresshelper/50mb.txt.gz
Normal file
Binary file not shown.
BIN
tests/benchmarks/network/access/qdecompresshelper/50mb.txt.zst
Normal file
BIN
tests/benchmarks/network/access/qdecompresshelper/50mb.txt.zst
Normal file
Binary file not shown.
@ -0,0 +1,16 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## qdecompresshelper Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(qdecompresshelper
|
||||
SOURCES
|
||||
main.cpp
|
||||
DEFINES
|
||||
SRC_DIR=${CMAKE_CURRENT_SOURCE_DIR}
|
||||
LIBRARIES
|
||||
Qt::NetworkPrivate
|
||||
Qt::Test
|
||||
)
|
71
tests/benchmarks/network/access/qdecompresshelper/main.cpp
Normal file
71
tests/benchmarks/network/access/qdecompresshelper/main.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
// Copyright (C) 2020 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QtNetwork/private/qdecompresshelper_p.h>
|
||||
|
||||
#include <QtTest/QTest>
|
||||
|
||||
class tst_QDecompressHelper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void decompress_data();
|
||||
void decompress();
|
||||
};
|
||||
|
||||
void tst_QDecompressHelper::decompress_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("encoding");
|
||||
QTest::addColumn<QString>("fileName");
|
||||
|
||||
QString srcDir = QStringLiteral(QT_STRINGIFY(SRC_DIR));
|
||||
srcDir = QDir::fromNativeSeparators(srcDir);
|
||||
if (!srcDir.endsWith("/"))
|
||||
srcDir += "/";
|
||||
|
||||
bool dataAdded = false;
|
||||
#ifndef QT_NO_COMPRESS
|
||||
QTest::addRow("gzip") << QByteArray("gzip") << srcDir + QString("50mb.txt.gz");
|
||||
dataAdded = true;
|
||||
#endif
|
||||
#if QT_CONFIG(brotli)
|
||||
QTest::addRow("brotli") << QByteArray("br") << srcDir + QString("50mb.txt.br");
|
||||
dataAdded = true;
|
||||
#endif
|
||||
#if QT_CONFIG(zstd)
|
||||
QTest::addRow("zstandard") << QByteArray("zstd") << srcDir + QString("50mb.txt.zst");
|
||||
dataAdded = true;
|
||||
#endif
|
||||
if (!dataAdded)
|
||||
QSKIP("There's no decompression support");
|
||||
}
|
||||
|
||||
void tst_QDecompressHelper::decompress()
|
||||
{
|
||||
QFETCH(QByteArray, encoding);
|
||||
QFETCH(QString, fileName);
|
||||
|
||||
QFile file { fileName };
|
||||
QVERIFY(file.open(QIODevice::ReadOnly));
|
||||
QBENCHMARK {
|
||||
file.seek(0);
|
||||
QDecompressHelper helper;
|
||||
helper.setEncoding(encoding);
|
||||
QVERIFY(helper.isValid());
|
||||
|
||||
helper.feed(file.readAll());
|
||||
|
||||
qsizetype bytes = 0;
|
||||
while (helper.hasData()) {
|
||||
QByteArray out(64 * 1024, Qt::Uninitialized);
|
||||
qsizetype bytesRead = helper.read(out.data(), out.size());
|
||||
bytes += bytesRead;
|
||||
}
|
||||
|
||||
QCOMPARE(bytes, 50 * 1024 * 1024);
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QDecompressHelper)
|
||||
|
||||
#include "main.moc"
|
@ -0,0 +1,14 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qfile_vs_qnetworkaccessmanager Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qfile_vs_qnetworkaccessmanager
|
||||
SOURCES
|
||||
main.cpp
|
||||
LIBRARIES
|
||||
Qt::Network
|
||||
Qt::Test
|
||||
)
|
@ -0,0 +1,154 @@
|
||||
// Copyright (C) 2020 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
#include <QDebug>
|
||||
#include <qtest.h>
|
||||
#include <QTest>
|
||||
#include <QTestEventLoop>
|
||||
#include <QtNetwork/qnetworkreply.h>
|
||||
#include <QtNetwork/qnetworkrequest.h>
|
||||
#include <QtNetwork/qnetworkaccessmanager.h>
|
||||
#include <QtCore/QTemporaryFile>
|
||||
#include <QtCore/QElapsedTimer>
|
||||
#include <QtCore/QFile>
|
||||
|
||||
class qfile_vs_qnetworkaccessmanager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
protected:
|
||||
void qnamFileRead_iteration(QNetworkAccessManager &manager, QNetworkRequest &request);
|
||||
void qnamImmediateFileRead_iteration(QNetworkAccessManager &manager, QNetworkRequest &request);
|
||||
void qfileFileRead_iteration();
|
||||
static const int iterations = 10;
|
||||
|
||||
private slots:
|
||||
void qnamFileRead();
|
||||
void qnamImmediateFileRead();
|
||||
void qfileFileRead();
|
||||
|
||||
void initTestCase();
|
||||
void cleanupTestCase();
|
||||
|
||||
public:
|
||||
qint64 size;
|
||||
QTemporaryFile testFile;
|
||||
|
||||
qfile_vs_qnetworkaccessmanager() : QObject(), size(0) {};
|
||||
};
|
||||
|
||||
void qfile_vs_qnetworkaccessmanager::initTestCase()
|
||||
{
|
||||
testFile.open();
|
||||
QByteArray qba(1*1024*1024, 'x'); // 1 MB
|
||||
for (int i = 0; i < 100; i++) {
|
||||
testFile.write(qba);
|
||||
testFile.flush();
|
||||
size += qba.size();
|
||||
} // 100 MB or 10 MB
|
||||
testFile.reset();
|
||||
}
|
||||
|
||||
void qfile_vs_qnetworkaccessmanager::cleanupTestCase()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void qfile_vs_qnetworkaccessmanager::qnamFileRead_iteration(QNetworkAccessManager &manager, QNetworkRequest &request)
|
||||
{
|
||||
QNetworkReply* reply = manager.get(request);
|
||||
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
|
||||
QTestEventLoop::instance().enterLoop(10);
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
QByteArray qba = reply->readAll();
|
||||
delete reply;
|
||||
}
|
||||
|
||||
void qfile_vs_qnetworkaccessmanager::qnamFileRead()
|
||||
{
|
||||
QNetworkAccessManager manager;
|
||||
QElapsedTimer t;
|
||||
QNetworkRequest request(QUrl::fromLocalFile(testFile.fileName()));
|
||||
|
||||
// do 3 dry runs for cache warmup
|
||||
qnamFileRead_iteration(manager, request);
|
||||
qnamFileRead_iteration(manager, request);
|
||||
qnamFileRead_iteration(manager, request);
|
||||
|
||||
t.start();
|
||||
// 10 real runs
|
||||
QBENCHMARK_ONCE {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
qnamFileRead_iteration(manager, request);
|
||||
}
|
||||
}
|
||||
|
||||
qint64 elapsed = t.elapsed();
|
||||
qDebug() << Qt::endl << "Finished!";
|
||||
qDebug() << "Bytes:" << size;
|
||||
qDebug() << "Speed:" << (qreal(size*iterations) / 1024.0) / (qreal(elapsed) / 1000.0) << "KB/sec";
|
||||
}
|
||||
|
||||
void qfile_vs_qnetworkaccessmanager::qnamImmediateFileRead_iteration(QNetworkAccessManager &manager, QNetworkRequest &request)
|
||||
{
|
||||
QNetworkReply* reply = manager.get(request);
|
||||
QVERIFY(reply->isFinished()); // should be like that!
|
||||
QByteArray qba = reply->readAll();
|
||||
delete reply;
|
||||
}
|
||||
|
||||
void qfile_vs_qnetworkaccessmanager::qnamImmediateFileRead()
|
||||
{
|
||||
QNetworkAccessManager manager;
|
||||
QElapsedTimer t;
|
||||
QNetworkRequest request(QUrl::fromLocalFile(testFile.fileName()));
|
||||
|
||||
// do 3 dry runs for cache warmup
|
||||
qnamImmediateFileRead_iteration(manager, request);
|
||||
qnamImmediateFileRead_iteration(manager, request);
|
||||
qnamImmediateFileRead_iteration(manager, request);
|
||||
|
||||
t.start();
|
||||
// 10 real runs
|
||||
QBENCHMARK_ONCE {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
qnamImmediateFileRead_iteration(manager, request);
|
||||
}
|
||||
}
|
||||
|
||||
qint64 elapsed = t.elapsed();
|
||||
qDebug() << Qt::endl << "Finished!";
|
||||
qDebug() << "Bytes:" << size;
|
||||
qDebug() << "Speed:" << (qreal(size*iterations) / 1024.0) / (qreal(elapsed) / 1000.0) << "KB/sec";
|
||||
}
|
||||
|
||||
void qfile_vs_qnetworkaccessmanager::qfileFileRead_iteration()
|
||||
{
|
||||
testFile.reset();
|
||||
QByteArray qba = testFile.readAll();
|
||||
}
|
||||
|
||||
void qfile_vs_qnetworkaccessmanager::qfileFileRead()
|
||||
{
|
||||
QElapsedTimer t;
|
||||
|
||||
// do 3 dry runs for cache warmup
|
||||
qfileFileRead_iteration();
|
||||
qfileFileRead_iteration();
|
||||
qfileFileRead_iteration();
|
||||
|
||||
t.start();
|
||||
// 10 real runs
|
||||
QBENCHMARK_ONCE {
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
qfileFileRead_iteration();
|
||||
}
|
||||
}
|
||||
|
||||
qint64 elapsed = t.elapsed();
|
||||
qDebug() << Qt::endl << "Finished!";
|
||||
qDebug() << "Bytes:" << size;
|
||||
qDebug() << "Speed:" << (qreal(size*iterations) / 1024.0) / (qreal(elapsed) / 1000.0) << "KB/sec";
|
||||
}
|
||||
|
||||
QTEST_MAIN(qfile_vs_qnetworkaccessmanager)
|
||||
|
||||
#include "main.moc"
|
@ -0,0 +1,14 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qnetworkdiskcache Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qnetworkdiskcache
|
||||
SOURCES
|
||||
tst_qnetworkdiskcache.cpp
|
||||
LIBRARIES
|
||||
Qt::Network
|
||||
Qt::Test
|
||||
)
|
@ -0,0 +1,379 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QNetworkDiskCache>
|
||||
#include <QNetworkCacheMetaData>
|
||||
#include <QDir>
|
||||
#include <QBuffer>
|
||||
#include <QTextStream>
|
||||
#include <QDebug>
|
||||
#include <QTest>
|
||||
#include <QIODevice>
|
||||
#include <QStandardPaths>
|
||||
#include <QDirIterator>
|
||||
|
||||
|
||||
|
||||
enum Numbers { NumFakeCacheObjects = 200, //entries in pre-populated cache
|
||||
NumInsertions = 100, //insertions to be timed
|
||||
NumRemovals = 100, //removals to be timed
|
||||
NumReadContent = 100, //meta requests to be timed
|
||||
HugeCacheLimit = 50*1024*1024, // max size for a big cache
|
||||
TinyCacheLimit = 1*512*1024}; // max size for a tiny cache
|
||||
|
||||
const QString fakeURLbase = "http://127.0.0.1/fake/";
|
||||
//fake HTTP body aka payload
|
||||
const QByteArray payload("Qt rocks!");
|
||||
|
||||
class tst_qnetworkdiskcache : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
void injectFakeData();
|
||||
void insertOneItem();
|
||||
bool isUrlCached(quint32 id);
|
||||
void cleanRecursive(QString &path);
|
||||
void cleanupCacheObject();
|
||||
void initCacheObject();
|
||||
QString cacheDir;
|
||||
QNetworkDiskCache *cache;
|
||||
|
||||
public slots:
|
||||
void initTestCase();
|
||||
void cleanupTestCase();
|
||||
|
||||
private slots:
|
||||
|
||||
void timeInsertion_data();
|
||||
void timeInsertion();
|
||||
void timeRead_data();
|
||||
void timeRead();
|
||||
void timeRemoval_data();
|
||||
void timeRemoval();
|
||||
|
||||
void timeExpiration_data();
|
||||
void timeExpiration();
|
||||
};
|
||||
|
||||
|
||||
void tst_qnetworkdiskcache::initTestCase()
|
||||
{
|
||||
cache = 0;
|
||||
}
|
||||
|
||||
|
||||
void tst_qnetworkdiskcache::cleanupTestCase()
|
||||
{
|
||||
cleanupCacheObject();
|
||||
cleanRecursive(cacheDir);
|
||||
}
|
||||
|
||||
void tst_qnetworkdiskcache::timeInsertion_data()
|
||||
{
|
||||
QTest::addColumn<QString>("cacheRootDirectory");
|
||||
|
||||
QString cacheLoc = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
|
||||
QTest::newRow("QStandardPaths Cache Location") << cacheLoc;
|
||||
}
|
||||
|
||||
//This functions times an insert() operation.
|
||||
//You can run it after populating the cache with
|
||||
//fake data so that more realistic performance
|
||||
//estimates are obtained.
|
||||
void tst_qnetworkdiskcache::timeInsertion()
|
||||
{
|
||||
|
||||
QFETCH(QString, cacheRootDirectory);
|
||||
|
||||
cacheDir = QString( cacheRootDirectory + QDir::separator() + "man_qndc");
|
||||
QDir d;
|
||||
qDebug() << "Setting cache directory to = " << d.absoluteFilePath(cacheDir);
|
||||
|
||||
//Housekeeping
|
||||
cleanRecursive(cacheDir); // slow op.
|
||||
initCacheObject();
|
||||
|
||||
cache->setCacheDirectory(cacheDir);
|
||||
cache->setMaximumCacheSize(qint64(HugeCacheLimit));
|
||||
cache->clear();
|
||||
|
||||
//populate some fake data to simulate partially full cache
|
||||
injectFakeData(); // SLOW
|
||||
|
||||
//Sanity-check that the first URL that we insert below isn't already in there.
|
||||
QVERIFY(isUrlCached(NumFakeCacheObjects) == false);
|
||||
|
||||
// IMPORTANT: max cache size should be HugeCacheLimit, to avoid evictions below
|
||||
//time insertion of previously-uncached URLs.
|
||||
QBENCHMARK_ONCE {
|
||||
for (quint32 i = NumFakeCacheObjects; i < (NumFakeCacheObjects + NumInsertions); i++) {
|
||||
//prepare metata for url
|
||||
QNetworkCacheMetaData meta;
|
||||
QString fakeURL;
|
||||
QTextStream stream(&fakeURL);
|
||||
stream << fakeURLbase << i;
|
||||
QUrl url(fakeURL);
|
||||
meta.setUrl(url);
|
||||
meta.setSaveToDisk(true);
|
||||
|
||||
//commit payload and metadata to disk
|
||||
QIODevice *device = cache->prepare(meta);
|
||||
device->write(payload);
|
||||
cache->insert(device);
|
||||
}
|
||||
}
|
||||
|
||||
//SLOW cleanup
|
||||
cleanupCacheObject();
|
||||
cleanRecursive(cacheDir);
|
||||
|
||||
}
|
||||
|
||||
void tst_qnetworkdiskcache::timeRead_data()
|
||||
{
|
||||
QTest::addColumn<QString>("cacheRootDirectory");
|
||||
|
||||
QString cacheLoc = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
|
||||
QTest::newRow("QStandardPaths Cache Location") << cacheLoc;
|
||||
}
|
||||
|
||||
//Times metadata as well payload lookup
|
||||
// i.e metaData(), rawHeaders() and data()
|
||||
void tst_qnetworkdiskcache::timeRead()
|
||||
{
|
||||
|
||||
QFETCH(QString, cacheRootDirectory);
|
||||
|
||||
cacheDir = QString( cacheRootDirectory + QDir::separator() + "man_qndc");
|
||||
QDir d;
|
||||
qDebug() << "Setting cache directory to = " << d.absoluteFilePath(cacheDir);
|
||||
|
||||
//Housekeeping
|
||||
cleanRecursive(cacheDir); // slow op.
|
||||
initCacheObject();
|
||||
cache->setCacheDirectory(cacheDir);
|
||||
cache->setMaximumCacheSize(qint64(HugeCacheLimit));
|
||||
cache->clear();
|
||||
|
||||
//populate some fake data to simulate partially full cache
|
||||
injectFakeData();
|
||||
|
||||
//Entries in the cache should be > what we try to remove
|
||||
QVERIFY(NumFakeCacheObjects > NumReadContent);
|
||||
|
||||
//time metadata lookup of previously inserted URL.
|
||||
QBENCHMARK_ONCE {
|
||||
for (quint32 i = 0; i < NumReadContent; i++) {
|
||||
QString fakeURL;
|
||||
QTextStream stream(&fakeURL);
|
||||
stream << fakeURLbase << i;
|
||||
QUrl url(fakeURL);
|
||||
|
||||
QNetworkCacheMetaData qndc = cache->metaData(url);
|
||||
QVERIFY(qndc.isValid()); // we must have read the metadata
|
||||
|
||||
QNetworkCacheMetaData::RawHeaderList raw(qndc.rawHeaders());
|
||||
QVERIFY(raw.size()); // we must have parsed the headers from the meta
|
||||
|
||||
QIODevice *iodevice(cache->data(url));
|
||||
QVERIFY(iodevice); //must not be NULL
|
||||
iodevice->close();
|
||||
delete iodevice;
|
||||
}
|
||||
}
|
||||
|
||||
//Cleanup (slow)
|
||||
cleanupCacheObject();
|
||||
cleanRecursive(cacheDir);
|
||||
|
||||
}
|
||||
|
||||
void tst_qnetworkdiskcache::timeRemoval_data()
|
||||
{
|
||||
QTest::addColumn<QString>("cacheRootDirectory");
|
||||
|
||||
QString cacheLoc = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
|
||||
QTest::newRow("QStandardPaths Cache Location") << cacheLoc;
|
||||
}
|
||||
|
||||
void tst_qnetworkdiskcache::timeRemoval()
|
||||
{
|
||||
|
||||
QFETCH(QString, cacheRootDirectory);
|
||||
|
||||
cacheDir = QString( cacheRootDirectory + QDir::separator() + "man_qndc");
|
||||
QDir d;
|
||||
qDebug() << "Setting cache directory to = " << d.absoluteFilePath(cacheDir);
|
||||
|
||||
//Housekeeping
|
||||
initCacheObject();
|
||||
cleanRecursive(cacheDir); // slow op.
|
||||
cache->setCacheDirectory(cacheDir);
|
||||
// Make max cache size HUGE, so that evictions don't happen below
|
||||
cache->setMaximumCacheSize(qint64(HugeCacheLimit));
|
||||
cache->clear();
|
||||
|
||||
//populate some fake data to simulate partially full cache
|
||||
injectFakeData();
|
||||
|
||||
//Sanity-check that the URL is already in there somewhere
|
||||
QVERIFY(isUrlCached(NumRemovals-1) == true);
|
||||
//Entries in the cache should be > what we try to remove
|
||||
QVERIFY(NumFakeCacheObjects > NumRemovals);
|
||||
|
||||
//time removal of previously-inserted URL.
|
||||
QBENCHMARK_ONCE {
|
||||
for (quint32 i = 0; i < NumRemovals; i++) {
|
||||
QString fakeURL;
|
||||
QTextStream stream(&fakeURL);
|
||||
stream << fakeURLbase << i;
|
||||
QUrl url(fakeURL);
|
||||
cache->remove(url);
|
||||
}
|
||||
}
|
||||
|
||||
//Cleanup (slow)
|
||||
cleanupCacheObject();
|
||||
cleanRecursive(cacheDir);
|
||||
|
||||
}
|
||||
|
||||
void tst_qnetworkdiskcache::timeExpiration_data()
|
||||
{
|
||||
QTest::addColumn<QString>("cacheRootDirectory");
|
||||
|
||||
QString cacheLoc = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
|
||||
QTest::newRow("QStandardPaths Cache Location") << cacheLoc;
|
||||
}
|
||||
|
||||
void tst_qnetworkdiskcache::timeExpiration()
|
||||
{
|
||||
|
||||
QFETCH(QString, cacheRootDirectory);
|
||||
|
||||
cacheDir = QString( cacheRootDirectory + QDir::separator() + "man_qndc");
|
||||
QDir d;
|
||||
qDebug() << "Setting cache directory to = " << d.absoluteFilePath(cacheDir);
|
||||
|
||||
//Housekeeping
|
||||
initCacheObject();
|
||||
cleanRecursive(cacheDir); // slow op.
|
||||
cache->setCacheDirectory(cacheDir);
|
||||
// Make max cache size HUGE, so that evictions don't happen below
|
||||
cache->setMaximumCacheSize(qint64(HugeCacheLimit));
|
||||
cache->clear();
|
||||
|
||||
//populate some fake data to simulate partially full cache
|
||||
injectFakeData();
|
||||
|
||||
//Sanity-check that the URL is already in there somewhere
|
||||
QVERIFY(isUrlCached(NumRemovals-1) == true);
|
||||
//Entries in the cache should be > what we try to remove
|
||||
QVERIFY(NumFakeCacheObjects > NumRemovals);
|
||||
|
||||
|
||||
//Set cache limit lower, so this force 1 round of eviction
|
||||
cache->setMaximumCacheSize(qint64(TinyCacheLimit));
|
||||
|
||||
//time insertions of additional content, which is likely to internally cause evictions
|
||||
QBENCHMARK_ONCE {
|
||||
for (quint32 i = NumFakeCacheObjects; i < (NumFakeCacheObjects + NumInsertions); i++) {
|
||||
//prepare metata for url
|
||||
QNetworkCacheMetaData meta;
|
||||
QString fakeURL;
|
||||
QTextStream stream(&fakeURL);
|
||||
stream << fakeURLbase << i;//codescanner::leave
|
||||
QUrl url(fakeURL);
|
||||
meta.setUrl(url);
|
||||
meta.setSaveToDisk(true);
|
||||
|
||||
//commit payload and metadata to disk
|
||||
QIODevice *device = cache->prepare(meta);
|
||||
device->write(payload);
|
||||
cache->insert(device); // this should trigger evictions, if TinyCacheLimit is small enough
|
||||
}
|
||||
}
|
||||
|
||||
//Cleanup (slow)
|
||||
cleanupCacheObject();
|
||||
cleanRecursive(cacheDir);
|
||||
|
||||
}
|
||||
// This function simulates a partially or fully occupied disk cache
|
||||
// like a normal user of a cache might encounter is real-life browsing.
|
||||
// The point of this is to trigger degradation in file-system and media performance
|
||||
// that occur due to the quantity and layout of data.
|
||||
void tst_qnetworkdiskcache::injectFakeData()
|
||||
{
|
||||
|
||||
QNetworkCacheMetaData::RawHeaderList headers;
|
||||
headers.append(qMakePair(QByteArray("X-TestHeader"),QByteArray("HeaderValue")));
|
||||
|
||||
|
||||
//Prep cache dir with fake data using QNetworkDiskCache APIs
|
||||
for (quint32 i = 0; i < NumFakeCacheObjects; i++) {
|
||||
|
||||
//prepare metata for url
|
||||
QNetworkCacheMetaData meta;
|
||||
QString fakeURL;
|
||||
QTextStream stream(&fakeURL);
|
||||
stream << fakeURLbase << i;
|
||||
QUrl url(fakeURL);
|
||||
meta.setUrl(url);
|
||||
meta.setRawHeaders(headers);
|
||||
meta.setSaveToDisk(true);
|
||||
|
||||
//commit payload and metadata to disk
|
||||
QIODevice *device = cache->prepare(meta);
|
||||
device->write(payload);
|
||||
cache->insert(device);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Checks if the fake URL #id is already cached or not.
|
||||
bool tst_qnetworkdiskcache::isUrlCached(quint32 id)
|
||||
{
|
||||
QString str;
|
||||
QTextStream stream(&str);
|
||||
stream << fakeURLbase << id;
|
||||
QUrl url(str);
|
||||
QIODevice *iod = cache->data(url);
|
||||
return ((iod == 0) ? false : true) ;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Utility function for recursive directory cleanup.
|
||||
void tst_qnetworkdiskcache::cleanRecursive(QString &path)
|
||||
{
|
||||
QDirIterator it(path, QDir::Files | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
|
||||
while (it.hasNext()) {
|
||||
QFile f(it.next());
|
||||
bool err = f.remove();
|
||||
Q_UNUSED(err);
|
||||
}
|
||||
|
||||
QDirIterator it2(path, QDir::AllDirs | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
|
||||
while (it2.hasNext()) {
|
||||
QString s(it2.next());
|
||||
QDir dir(s);
|
||||
dir.rmdir(s);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_qnetworkdiskcache::cleanupCacheObject()
|
||||
{
|
||||
delete cache;
|
||||
cache = 0;
|
||||
}
|
||||
|
||||
void tst_qnetworkdiskcache::initCacheObject()
|
||||
{
|
||||
|
||||
cache = new QNetworkDiskCache();
|
||||
|
||||
}
|
||||
QTEST_MAIN(tst_qnetworkdiskcache)
|
||||
#include "tst_qnetworkdiskcache.moc"
|
16
tests/benchmarks/network/access/qnetworkreply/CMakeLists.txt
Normal file
16
tests/benchmarks/network/access/qnetworkreply/CMakeLists.txt
Normal file
@ -0,0 +1,16 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qnetworkreply Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qnetworkreply
|
||||
SOURCES
|
||||
tst_qnetworkreply.cpp
|
||||
LIBRARIES
|
||||
Qt::CorePrivate
|
||||
Qt::Network
|
||||
Qt::NetworkPrivate
|
||||
Qt::Test
|
||||
)
|
@ -0,0 +1,935 @@
|
||||
// Copyright (C) 2020 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
// This file contains benchmarks for QNetworkReply functions.
|
||||
|
||||
#include <QDebug>
|
||||
#include <qtest.h>
|
||||
#include <QTest>
|
||||
#include <QTestEventLoop>
|
||||
#include <QSemaphore>
|
||||
#include <QTimer>
|
||||
#include <QtCore/qrandom.h>
|
||||
#include <QtCore/QElapsedTimer>
|
||||
#include <QtNetwork/qnetworkreply.h>
|
||||
#include <QtNetwork/qnetworkrequest.h>
|
||||
#include <QtNetwork/qnetworkaccessmanager.h>
|
||||
#include <QtNetwork/qtcpsocket.h>
|
||||
#include <QtNetwork/qtcpserver.h>
|
||||
#include "../../../../auto/network-settings.h"
|
||||
|
||||
#ifdef QT_BUILD_INTERNAL
|
||||
#include <QtNetwork/private/qhostinfo_p.h>
|
||||
#endif
|
||||
|
||||
Q_DECLARE_METATYPE(QSharedPointer<char>)
|
||||
|
||||
class TimedSender: public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
qint64 totalBytes;
|
||||
QSemaphore ready;
|
||||
QByteArray dataToSend;
|
||||
QTcpSocket *client;
|
||||
int timeout;
|
||||
int port;
|
||||
public:
|
||||
int transferRate;
|
||||
TimedSender(int ms)
|
||||
: totalBytes(0), timeout(ms), port(-1), transferRate(-1)
|
||||
{
|
||||
dataToSend = QByteArray(16*1024, '@');
|
||||
start();
|
||||
ready.acquire();
|
||||
}
|
||||
|
||||
inline int serverPort() const { return port; }
|
||||
|
||||
private slots:
|
||||
void writeMore()
|
||||
{
|
||||
while (client->bytesToWrite() < 128 * 1024) {
|
||||
writePacket(dataToSend);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
void run() override
|
||||
{
|
||||
QTcpServer server;
|
||||
server.listen();
|
||||
port = server.serverPort();
|
||||
ready.release();
|
||||
|
||||
server.waitForNewConnection(-1);
|
||||
client = server.nextPendingConnection();
|
||||
|
||||
writeMore();
|
||||
connect(client, SIGNAL(bytesWritten(qint64)), SLOT(writeMore()), Qt::DirectConnection);
|
||||
|
||||
QEventLoop eventLoop;
|
||||
QTimer::singleShot(timeout, &eventLoop, SLOT(quit()));
|
||||
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
eventLoop.exec();
|
||||
disconnect(client, SIGNAL(bytesWritten(qint64)), this, 0);
|
||||
|
||||
// wait for the connection to shut down
|
||||
client->disconnectFromHost();
|
||||
if (!client->waitForDisconnected(10000))
|
||||
return;
|
||||
|
||||
transferRate = totalBytes * 1000 / timer.elapsed();
|
||||
qDebug() << "TimedSender::run" << "receive rate:" << (transferRate / 1024) << "kB/s in"
|
||||
<< timer.elapsed() << "ms";
|
||||
}
|
||||
|
||||
void writePacket(const QByteArray &array)
|
||||
{
|
||||
client->write(array);
|
||||
totalBytes += array.size();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
typedef QSharedPointer<QNetworkReply> QNetworkReplyPtr;
|
||||
|
||||
class DataReader: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
qint64 totalBytes;
|
||||
QByteArray data;
|
||||
QIODevice *device;
|
||||
bool accumulate;
|
||||
DataReader(const QNetworkReplyPtr &dev, bool acc = true) : totalBytes(0), device(dev.data()), accumulate(acc)
|
||||
{
|
||||
connect(device, SIGNAL(readyRead()), SLOT(doRead()));
|
||||
}
|
||||
DataReader(QIODevice *dev, bool acc = true) : totalBytes(0), device(dev), accumulate(acc)
|
||||
{
|
||||
connect(device, SIGNAL(readyRead()), SLOT(doRead()));
|
||||
}
|
||||
|
||||
public slots:
|
||||
void doRead()
|
||||
{
|
||||
QByteArray buffer;
|
||||
buffer.resize(device->bytesAvailable());
|
||||
qint64 bytesRead = device->read(buffer.data(), device->bytesAvailable());
|
||||
if (bytesRead == -1) {
|
||||
QTestEventLoop::instance().exitLoop();
|
||||
return;
|
||||
}
|
||||
buffer.truncate(bytesRead);
|
||||
totalBytes += bytesRead;
|
||||
|
||||
if (accumulate)
|
||||
data += buffer;
|
||||
}
|
||||
};
|
||||
|
||||
class ThreadedDataReader: public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
// used to make the constructor only return after the tcp server started listening
|
||||
QSemaphore ready;
|
||||
QTcpSocket *client;
|
||||
int port;
|
||||
public:
|
||||
qint64 transferRate;
|
||||
ThreadedDataReader()
|
||||
: port(-1), transferRate(-1)
|
||||
{
|
||||
start();
|
||||
ready.acquire();
|
||||
}
|
||||
|
||||
inline int serverPort() const { return port; }
|
||||
|
||||
protected:
|
||||
void run() override
|
||||
{
|
||||
QTcpServer server;
|
||||
server.listen();
|
||||
port = server.serverPort();
|
||||
ready.release();
|
||||
|
||||
server.waitForNewConnection(-1);
|
||||
client = server.nextPendingConnection();
|
||||
|
||||
QEventLoop eventLoop;
|
||||
DataReader reader(client, false);
|
||||
QObject::connect(client, SIGNAL(disconnected()), &eventLoop, SLOT(quit()));
|
||||
|
||||
QElapsedTimer 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 DataGenerator: public QIODevice
|
||||
{
|
||||
Q_OBJECT
|
||||
enum { Idle, Started, Stopped } state;
|
||||
public:
|
||||
DataGenerator() : state(Idle)
|
||||
{ open(ReadOnly); }
|
||||
|
||||
bool isSequential() const override { return true; }
|
||||
qint64 bytesAvailable() const override { return state == Started ? 1024*1024 : 0; }
|
||||
|
||||
public slots:
|
||||
void start() { state = Started; emit readyRead(); }
|
||||
void stop() { state = Stopped; emit readyRead(); }
|
||||
|
||||
protected:
|
||||
qint64 readData(char *data, qint64 maxlen) override
|
||||
{
|
||||
if (state == Stopped)
|
||||
return -1; // EOF
|
||||
|
||||
// return as many bytes as are wanted
|
||||
memset(data, '@', maxlen);
|
||||
return maxlen;
|
||||
}
|
||||
qint64 writeData(const char *, qint64) override { return -1; }
|
||||
};
|
||||
|
||||
class ThreadedDataReaderHttpServer: public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
// used to make the constructor only return after the tcp server started listening
|
||||
QSemaphore ready;
|
||||
QTcpSocket *client;
|
||||
int port;
|
||||
public:
|
||||
qint64 transferRate;
|
||||
ThreadedDataReaderHttpServer()
|
||||
: port(-1), transferRate(-1)
|
||||
{
|
||||
start();
|
||||
ready.acquire();
|
||||
}
|
||||
|
||||
inline int serverPort() const { return port; }
|
||||
|
||||
protected:
|
||||
void run() override
|
||||
{
|
||||
QTcpServer server;
|
||||
server.listen();
|
||||
port = server.serverPort();
|
||||
ready.release();
|
||||
|
||||
QVERIFY(server.waitForNewConnection(10*1000));
|
||||
client = server.nextPendingConnection();
|
||||
|
||||
// read lines until we read the empty line seperating HTTP request from HTTP request body
|
||||
do {
|
||||
if (client->canReadLine()) {
|
||||
QString line = client->readLine();
|
||||
if (line == "\n" || line == "\r\n")
|
||||
break; // empty line
|
||||
}
|
||||
if (!client->waitForReadyRead(10*1000)) {
|
||||
client->close();
|
||||
return;
|
||||
}
|
||||
} while (client->state() == QAbstractSocket::ConnectedState);
|
||||
|
||||
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()));
|
||||
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
eventLoop.exec();
|
||||
qint64 elapsed = timer.elapsed();
|
||||
|
||||
transferRate = reader.totalBytes * 1000 / elapsed;
|
||||
qDebug() << "ThreadedDataReaderHttpServer::run" << "send rate:" << (transferRate / 1024) << "kB/s in" << elapsed << "msec";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class FixedSizeDataGenerator : public QIODevice
|
||||
{
|
||||
Q_OBJECT
|
||||
enum { Idle, Started, Stopped } state;
|
||||
public:
|
||||
FixedSizeDataGenerator(qint64 size) : state(Idle)
|
||||
{ open(ReadOnly | Unbuffered);
|
||||
toBeGeneratedTotalCount = toBeGeneratedCount = size;
|
||||
}
|
||||
|
||||
qint64 bytesAvailable() const override
|
||||
{
|
||||
return state == Started ? toBeGeneratedCount + QIODevice::bytesAvailable() : 0;
|
||||
}
|
||||
|
||||
bool isSequential() const override { return false; }
|
||||
|
||||
bool reset() override { return false; }
|
||||
|
||||
qint64 size() const override { return toBeGeneratedTotalCount; }
|
||||
|
||||
public slots:
|
||||
void start() { state = Started; emit readyRead(); }
|
||||
|
||||
protected:
|
||||
qint64 readData(char *data, qint64 maxlen) override
|
||||
{
|
||||
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;
|
||||
}
|
||||
qint64 writeData(const char *, qint64) override { return -1; }
|
||||
|
||||
qint64 toBeGeneratedCount;
|
||||
qint64 toBeGeneratedTotalCount;
|
||||
};
|
||||
|
||||
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").toLatin1());
|
||||
if (chunkedEncoding)
|
||||
client->write(QString("Transfer-Encoding: chunked\n").toLatin1());
|
||||
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").toLatin1());
|
||||
|
||||
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").toLatin1());
|
||||
client->write(data.constData(), amount);
|
||||
client->write(QString("\r\n").toLatin1());
|
||||
} else {
|
||||
client->write(data.constData(), amount);
|
||||
}
|
||||
|
||||
dataSent += amount;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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 tst_qnetworkreply : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
QNetworkAccessManager manager;
|
||||
|
||||
public:
|
||||
using QObject::connect;
|
||||
bool connect(const QNetworkReplyPtr &sender, const char *signal, const QObject *receiver, const char *slot, Qt::ConnectionType ct = Qt::AutoConnection)
|
||||
{ return connect(sender.data(), signal, receiver, slot, ct); }
|
||||
private slots:
|
||||
void initTestCase();
|
||||
void httpLatency();
|
||||
|
||||
#ifndef QT_NO_SSL
|
||||
void echoPerformance_data();
|
||||
void echoPerformance();
|
||||
void preConnectEncrypted();
|
||||
#endif // !QT_NO_SSL
|
||||
void preConnectEncrypted_data();
|
||||
|
||||
void downloadPerformance();
|
||||
void uploadPerformance();
|
||||
void performanceControlRate();
|
||||
void httpUploadPerformance();
|
||||
void httpDownloadPerformance_data();
|
||||
void httpDownloadPerformance();
|
||||
void httpDownloadPerformanceDownloadBuffer_data();
|
||||
void httpDownloadPerformanceDownloadBuffer();
|
||||
void httpsRequestChain();
|
||||
void httpsUpload();
|
||||
void preConnect_data();
|
||||
void preConnect();
|
||||
|
||||
private:
|
||||
void runHttpsUploadRequest(const QByteArray &data, const QNetworkRequest &request);
|
||||
QPair<QNetworkReply *, qint64> runGetRequest(QNetworkAccessManager *manager,
|
||||
const QNetworkRequest &request);
|
||||
};
|
||||
|
||||
void tst_qnetworkreply::initTestCase()
|
||||
{
|
||||
if (!QtNetworkSettings::verifyTestNetworkSettings())
|
||||
QSKIP("No network test server available");
|
||||
}
|
||||
|
||||
void tst_qnetworkreply::httpLatency()
|
||||
{
|
||||
QNetworkAccessManager manager;
|
||||
QBENCHMARK{
|
||||
QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/"));
|
||||
QNetworkReply* reply = manager.get(request);
|
||||
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
|
||||
QTestEventLoop::instance().enterLoop(5);
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
delete reply;
|
||||
}
|
||||
}
|
||||
|
||||
QPair<QNetworkReply *, qint64> tst_qnetworkreply::runGetRequest(
|
||||
QNetworkAccessManager *manager, const QNetworkRequest &request)
|
||||
{
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
QNetworkReply *reply = manager->get(request);
|
||||
connect(reply, SIGNAL(sslErrors(QList<QSslError>)), reply, SLOT(ignoreSslErrors()));
|
||||
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
|
||||
QTestEventLoop::instance().enterLoop(20);
|
||||
qint64 elapsed = timer.elapsed();
|
||||
return qMakePair(reply, elapsed);
|
||||
}
|
||||
|
||||
#ifndef QT_NO_SSL
|
||||
void tst_qnetworkreply::echoPerformance_data()
|
||||
{
|
||||
QTest::addColumn<bool>("ssl");
|
||||
QTest::newRow("no_ssl") << false;
|
||||
QTest::newRow("ssl") << true;
|
||||
}
|
||||
|
||||
void tst_qnetworkreply::echoPerformance()
|
||||
{
|
||||
QFETCH(bool, ssl);
|
||||
QNetworkAccessManager manager;
|
||||
QNetworkRequest request(QUrl((ssl ? "https://" : "http://") + QtNetworkSettings::serverName() + "/qtest/cgi-bin/echo.cgi"));
|
||||
|
||||
QByteArray data;
|
||||
data.resize(1024*1024*10); // 10 MB
|
||||
// init with garbage. needed so ssl cannot compress it in an efficient way.
|
||||
for (size_t i = 0; i < data.size() / sizeof(int); i++) {
|
||||
char r = char(QRandomGenerator::global()->generate());
|
||||
data.data()[i*sizeof(int)] = r;
|
||||
}
|
||||
|
||||
QBENCHMARK{
|
||||
QNetworkReply* reply = manager.post(request, data);
|
||||
connect(reply, SIGNAL(sslErrors(QList<QSslError>)), reply, SLOT(ignoreSslErrors()));
|
||||
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
|
||||
QTestEventLoop::instance().enterLoop(5);
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
QVERIFY(reply->error() == QNetworkReply::NoError);
|
||||
delete reply;
|
||||
}
|
||||
}
|
||||
|
||||
void tst_qnetworkreply::preConnectEncrypted()
|
||||
{
|
||||
QFETCH(int, sleepTime);
|
||||
QString hostName = QLatin1String("www.google.com");
|
||||
|
||||
QNetworkAccessManager manager;
|
||||
QNetworkRequest request(QUrl("https://" + hostName));
|
||||
|
||||
// make sure we have a full request including
|
||||
// DNS lookup, TCP and SSL handshakes
|
||||
#ifdef QT_BUILD_INTERNAL
|
||||
qt_qhostinfo_clear_cache();
|
||||
#else
|
||||
qWarning("no internal build, could not clear DNS cache. Results may not be representative.");
|
||||
#endif
|
||||
|
||||
// first, benchmark a normal request
|
||||
QPair<QNetworkReply *, qint64> normalResult = runGetRequest(&manager, request);
|
||||
QNetworkReply *normalReply = normalResult.first;
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
QVERIFY(normalReply->error() == QNetworkReply::NoError);
|
||||
qint64 normalElapsed = normalResult.second;
|
||||
|
||||
// clear all caches again
|
||||
#ifdef QT_BUILD_INTERNAL
|
||||
qt_qhostinfo_clear_cache();
|
||||
#else
|
||||
qWarning("no internal build, could not clear DNS cache. Results may not be representative.");
|
||||
#endif
|
||||
manager.clearAccessCache();
|
||||
|
||||
// now try to make the connection beforehand
|
||||
manager.connectToHostEncrypted(hostName);
|
||||
QTestEventLoop::instance().enterLoopMSecs(sleepTime);
|
||||
|
||||
// now make another request and hopefully use the existing connection
|
||||
QPair<QNetworkReply *, qint64> preConnectResult = runGetRequest(&manager, request);
|
||||
QNetworkReply *preConnectReply = normalResult.first;
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
QVERIFY(preConnectReply->error() == QNetworkReply::NoError);
|
||||
qint64 preConnectElapsed = preConnectResult.second;
|
||||
qDebug() << request.url().toString() << "full request:" << normalElapsed
|
||||
<< "ms, pre-connect request:" << preConnectElapsed << "ms, difference:"
|
||||
<< (normalElapsed - preConnectElapsed) << "ms";
|
||||
}
|
||||
|
||||
#endif // !QT_NO_SSL
|
||||
|
||||
void tst_qnetworkreply::preConnectEncrypted_data()
|
||||
{
|
||||
#ifndef QT_NO_OPENSSL
|
||||
QTest::addColumn<int>("sleepTime");
|
||||
// start a new normal request after preconnecting is done
|
||||
QTest::newRow("HTTPS-2secs") << 2000;
|
||||
|
||||
// start a new normal request while preconnecting is in-flight
|
||||
QTest::newRow("HTTPS-100ms") << 100;
|
||||
#endif // QT_NO_OPENSSL
|
||||
}
|
||||
|
||||
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(QUrl(QStringLiteral("debugpipe://127.0.0.1:") + QString::number(sender.serverPort()) + QStringLiteral("/?bare=1")));
|
||||
QNetworkReplyPtr reply(manager.get(request));
|
||||
DataReader reader(reply, false);
|
||||
|
||||
QElapsedTimer loopTime;
|
||||
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
|
||||
loopTime.start();
|
||||
QTestEventLoop::instance().enterLoop(40);
|
||||
int elapsedTime = loopTime.elapsed();
|
||||
sender.wait();
|
||||
|
||||
qint64 receivedBytes = reader.totalBytes;
|
||||
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(QUrl(QStringLiteral("debugpipe://127.0.0.1:") + QString::number(reader.serverPort()) + QStringLiteral("/?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(30);
|
||||
QCOMPARE(reply->error(), QNetworkReply::NoError);
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
}
|
||||
|
||||
constexpr qint64 MiB = 1024 * 1024;
|
||||
|
||||
void tst_qnetworkreply::httpUploadPerformance()
|
||||
{
|
||||
constexpr qint64 UploadSize = 128 * MiB;
|
||||
|
||||
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()));
|
||||
|
||||
QElapsedTimer time;
|
||||
generator.start();
|
||||
time.start();
|
||||
QTestEventLoop::instance().enterLoop(40);
|
||||
qint64 elapsed = time.elapsed();
|
||||
reader.exit();
|
||||
reader.wait();
|
||||
QVERIFY(reply->isFinished());
|
||||
QCOMPARE(reply->error(), QNetworkReply::NoError);
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
|
||||
qDebug() << "tst_QNetworkReply::httpUploadPerformance" << elapsed << "msec, "
|
||||
<< ((UploadSize/1024.0)/(elapsed/1000.0)) << " kB/sec";
|
||||
}
|
||||
|
||||
|
||||
void tst_qnetworkreply::performanceControlRate()
|
||||
{
|
||||
// this is a control comparison for the other two above
|
||||
// it does the same thing, but instead bypasses the QNetworkAccess system
|
||||
qDebug() << "The following are the maximum transfer rates that we can get in this system"
|
||||
" (bypassing QNetworkAccess)";
|
||||
|
||||
TimedSender sender(5000);
|
||||
QTcpSocket sink;
|
||||
sink.connectToHost("127.0.0.1", sender.serverPort());
|
||||
DataReader reader(&sink, false);
|
||||
|
||||
QElapsedTimer loopTime;
|
||||
connect(&sink, SIGNAL(disconnected()), &QTestEventLoop::instance(), SLOT(exitLoop()));
|
||||
loopTime.start();
|
||||
QTestEventLoop::instance().enterLoop(40);
|
||||
int elapsedTime = loopTime.elapsed();
|
||||
sender.wait();
|
||||
|
||||
qint64 receivedBytes = reader.totalBytes;
|
||||
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);
|
||||
|
||||
constexpr qint64 UploadSize = 128 * MiB;
|
||||
|
||||
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.data());
|
||||
|
||||
QElapsedTimer time;
|
||||
time.start();
|
||||
QTestEventLoop::instance().enterLoop(40);
|
||||
QCOMPARE(reply->error(), QNetworkReply::NoError);
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
|
||||
qint64 elapsed = time.elapsed();
|
||||
qDebug() << "tst_QNetworkReply::httpDownloadPerformance" << elapsed << "msec, "
|
||||
<< ((UploadSize/1024.0)/(elapsed/1000.0)) << " kB/sec";
|
||||
};
|
||||
|
||||
enum HttpDownloadPerformanceDownloadBufferTestType {
|
||||
JustDownloadBuffer,
|
||||
DownloadBufferButUseRead,
|
||||
NoDownloadBuffer
|
||||
};
|
||||
Q_DECLARE_METATYPE(HttpDownloadPerformanceDownloadBufferTestType)
|
||||
|
||||
class HttpDownloadPerformanceClientDownloadBuffer : QObject {
|
||||
Q_OBJECT
|
||||
private:
|
||||
HttpDownloadPerformanceDownloadBufferTestType testType;
|
||||
QNetworkReply *reply;
|
||||
qint64 uploadSize;
|
||||
QList<qint64> bytesAvailableList;
|
||||
public:
|
||||
HttpDownloadPerformanceClientDownloadBuffer (QNetworkReply *reply, HttpDownloadPerformanceDownloadBufferTestType testType, qint64 uploadSize)
|
||||
: testType(testType), reply(reply), uploadSize(uploadSize)
|
||||
{
|
||||
connect(reply, SIGNAL(finished()), this, SLOT(finishedSlot()));
|
||||
}
|
||||
|
||||
public slots:
|
||||
void finishedSlot() {
|
||||
if (testType == JustDownloadBuffer) {
|
||||
// We have a download buffer and use it. This should be the fastest benchmark result.
|
||||
QVariant downloadBufferAttribute = reply->attribute(QNetworkRequest::DownloadBufferAttribute);
|
||||
QSharedPointer<char> data = downloadBufferAttribute.value<QSharedPointer<char> >();
|
||||
} else if (testType == DownloadBufferButUseRead) {
|
||||
// We had a download buffer but we benchmark here the "legacy" read() way to access it
|
||||
char* replyData = (char*) malloc(uploadSize);
|
||||
QVERIFY(reply->read(replyData, uploadSize) == uploadSize);
|
||||
free(replyData);
|
||||
} else if (testType == NoDownloadBuffer) {
|
||||
// We did not have a download buffer but we still need to benchmark having the data, e.g. reading it all.
|
||||
// This should be the slowest benchmark result.
|
||||
char* replyData = (char*) malloc(uploadSize);
|
||||
QVERIFY(reply->read(replyData, uploadSize) == uploadSize);
|
||||
free(replyData);
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(&QTestEventLoop::instance(), "exitLoop", Qt::QueuedConnection);
|
||||
}
|
||||
};
|
||||
|
||||
void tst_qnetworkreply::httpDownloadPerformanceDownloadBuffer_data()
|
||||
{
|
||||
QTest::addColumn<HttpDownloadPerformanceDownloadBufferTestType>("testType");
|
||||
|
||||
QTest::newRow("use-download-buffer") << JustDownloadBuffer;
|
||||
QTest::newRow("use-download-buffer-but-use-read") << DownloadBufferButUseRead;
|
||||
QTest::newRow("do-not-use-download-buffer") << NoDownloadBuffer;
|
||||
}
|
||||
|
||||
// Please note that the whole "zero copy" download buffer API is private right now. Do not use it.
|
||||
void tst_qnetworkreply::httpDownloadPerformanceDownloadBuffer()
|
||||
{
|
||||
QFETCH(HttpDownloadPerformanceDownloadBufferTestType, testType);
|
||||
|
||||
// On my Linux Desktop the results are already visible with 128 kB, however we use this to have good results.
|
||||
enum {UploadSize = 32*1024*1024}; // 32 MB
|
||||
|
||||
HttpDownloadPerformanceServer server(UploadSize, true, false);
|
||||
|
||||
QNetworkRequest request(QUrl("http://127.0.0.1:" + QString::number(server.serverPort()) + "/?bare=1"));
|
||||
if (testType == JustDownloadBuffer || testType == DownloadBufferButUseRead)
|
||||
request.setAttribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute, 1024*1024*128); // 128 MB is max allowed
|
||||
|
||||
QNetworkAccessManager manager;
|
||||
QNetworkReplyPtr reply(manager.get(request));
|
||||
|
||||
HttpDownloadPerformanceClientDownloadBuffer client(reply.data(), testType, UploadSize);
|
||||
|
||||
QBENCHMARK_ONCE {
|
||||
QTestEventLoop::instance().enterLoop(40);
|
||||
QCOMPARE(reply->error(), QNetworkReply::NoError);
|
||||
QVERIFY(reply->isFinished());
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class HttpsRequestChainHelper : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
QList<QNetworkRequest> requestList;
|
||||
|
||||
QElapsedTimer timeOneRequest;
|
||||
QList<qint64> timeList;
|
||||
|
||||
QElapsedTimer globalTime;
|
||||
|
||||
QNetworkAccessManager manager;
|
||||
|
||||
HttpsRequestChainHelper() {
|
||||
}
|
||||
public slots:
|
||||
void doNextRequest() {
|
||||
// all requests done
|
||||
if (requestList.isEmpty()) {
|
||||
QTestEventLoop::instance().exitLoop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (qobject_cast<QNetworkReply*>(sender()) == 0) {
|
||||
// first start after DNS lookup, start timer
|
||||
globalTime.start();
|
||||
}
|
||||
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
|
||||
if (reply) {
|
||||
QVERIFY(reply->error() == QNetworkReply::NoError);
|
||||
qDebug() << "time =" << timeOneRequest.elapsed() << "ms";
|
||||
timeList.append(timeOneRequest.elapsed());
|
||||
}
|
||||
|
||||
QNetworkRequest request = requestList.takeFirst();
|
||||
timeOneRequest.restart();
|
||||
reply = manager.get(request);
|
||||
QObject::connect(reply, SIGNAL(sslErrors(QList<QSslError>)), reply, SLOT(ignoreSslErrors()));
|
||||
QObject::connect(reply, SIGNAL(finished()), this, SLOT(doNextRequest()));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void tst_qnetworkreply::httpsRequestChain()
|
||||
{
|
||||
int count = 10;
|
||||
|
||||
QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + "/fluke.gif"));
|
||||
// Disable keep-alive so we have the full re-connecting of TCP.
|
||||
request.setRawHeader("Connection", "close");
|
||||
|
||||
HttpsRequestChainHelper helper;
|
||||
for (int i = 0; i < count; i++)
|
||||
helper.requestList.append(request);
|
||||
|
||||
// Warm up DNS cache and then immediately start HTTP
|
||||
QHostInfo::lookupHost(QtNetworkSettings::serverName(), &helper, SLOT(doNextRequest()));
|
||||
|
||||
// we can use QBENCHMARK_ONCE when we find out how to make it really run once.
|
||||
// there is still a warmup-run :(
|
||||
|
||||
//QBENCHMARK_ONCE {
|
||||
QTestEventLoop::instance().enterLoop(40);
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
//}
|
||||
|
||||
qint64 elapsed = helper.globalTime.elapsed();
|
||||
|
||||
qint64 average = (elapsed / count);
|
||||
|
||||
std::sort(helper.timeList.begin(), helper.timeList.end());
|
||||
qint64 median = helper.timeList.at(5);
|
||||
|
||||
qDebug() << "Total:" << elapsed << " Average:" << average << " Median:" << median;
|
||||
|
||||
}
|
||||
|
||||
void tst_qnetworkreply::runHttpsUploadRequest(const QByteArray &data, const QNetworkRequest &request)
|
||||
{
|
||||
QNetworkReply* reply = manager.post(request, data);
|
||||
reply->ignoreSslErrors();
|
||||
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
|
||||
QTestEventLoop::instance().enterLoop(15);
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
QCOMPARE(reply->error(), QNetworkReply::NoError);
|
||||
reply->deleteLater();
|
||||
}
|
||||
|
||||
void tst_qnetworkreply::httpsUpload()
|
||||
{
|
||||
QByteArray data = QByteArray(2*1024*1024+1, '\177');
|
||||
QNetworkRequest request(QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi"));
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/octet-stream");
|
||||
// for (int a = 0; a < 10; ++a)
|
||||
// runHttpsUploadRequest(data, request); // to warmup all TCP connections
|
||||
QBENCHMARK {
|
||||
runHttpsUploadRequest(data, request);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_qnetworkreply::preConnect_data()
|
||||
{
|
||||
preConnectEncrypted_data();
|
||||
}
|
||||
|
||||
void tst_qnetworkreply::preConnect()
|
||||
{
|
||||
QString hostName = QLatin1String("www.google.com");
|
||||
|
||||
QNetworkAccessManager manager;
|
||||
QNetworkRequest request(QUrl("http://" + hostName));
|
||||
|
||||
// make sure we have a full request including
|
||||
// DNS lookup and TCP handshake
|
||||
#ifdef QT_BUILD_INTERNAL
|
||||
qt_qhostinfo_clear_cache();
|
||||
#else
|
||||
qWarning("no internal build, could not clear DNS cache. Results may not be representative.");
|
||||
#endif
|
||||
|
||||
// first, benchmark a normal request
|
||||
QPair<QNetworkReply *, qint64> normalResult = runGetRequest(&manager, request);
|
||||
QNetworkReply *normalReply = normalResult.first;
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
QVERIFY(normalReply->error() == QNetworkReply::NoError);
|
||||
qint64 normalElapsed = normalResult.second;
|
||||
|
||||
// clear all caches again
|
||||
#ifdef QT_BUILD_INTERNAL
|
||||
qt_qhostinfo_clear_cache();
|
||||
#else
|
||||
qWarning("no internal build, could not clear DNS cache. Results may not be representative.");
|
||||
#endif
|
||||
manager.clearAccessCache();
|
||||
|
||||
// now try to make the connection beforehand
|
||||
QFETCH(int, sleepTime);
|
||||
manager.connectToHost(hostName);
|
||||
QTestEventLoop::instance().enterLoopMSecs(sleepTime);
|
||||
|
||||
// now make another request and hopefully use the existing connection
|
||||
QPair<QNetworkReply *, qint64> preConnectResult = runGetRequest(&manager, request);
|
||||
QNetworkReply *preConnectReply = normalResult.first;
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
QVERIFY(preConnectReply->error() == QNetworkReply::NoError);
|
||||
qint64 preConnectElapsed = preConnectResult.second;
|
||||
qDebug() << request.url().toString() << "full request:" << normalElapsed
|
||||
<< "ms, pre-connect request:" << preConnectElapsed << "ms, difference:"
|
||||
<< (normalElapsed - preConnectElapsed) << "ms";
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_qnetworkreply)
|
||||
|
||||
#include "tst_qnetworkreply.moc"
|
@ -0,0 +1,14 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qnetworkreply_from_cache Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qnetworkreply_from_cache
|
||||
SOURCES
|
||||
tst_qnetworkreply_from_cache.cpp
|
||||
LIBRARIES
|
||||
Qt::Network
|
||||
Qt::Test
|
||||
)
|
@ -0,0 +1,194 @@
|
||||
// Copyright (C) 2012 Hewlett-Packard Development Company, L.P.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QTest>
|
||||
#include <QBuffer>
|
||||
#include <QTestEventLoop>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
#include <QtNetwork/QNetworkDiskCache>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QtNetwork/QTcpServer>
|
||||
#include <QtNetwork/QTcpSocket>
|
||||
|
||||
#define TEST_CASE_TIMEOUT 30
|
||||
|
||||
class NetworkDiskCache : public QNetworkDiskCache
|
||||
{
|
||||
public:
|
||||
NetworkDiskCache(QObject *parent = nullptr)
|
||||
: QNetworkDiskCache(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QByteArray cachedData;
|
||||
|
||||
QNetworkCacheMetaData metaData(const QUrl &url) override
|
||||
{
|
||||
QNetworkCacheMetaData metaData;
|
||||
if (!cachedData.isEmpty()) {
|
||||
metaData.setUrl(url);
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
metaData.setLastModified(now.addDays(-1));
|
||||
metaData.setExpirationDate(now.addDays(1));
|
||||
metaData.setSaveToDisk(true);
|
||||
}
|
||||
return metaData;
|
||||
}
|
||||
|
||||
QIODevice *data(const QUrl &/*url*/) override
|
||||
{
|
||||
if (cachedData.isEmpty())
|
||||
return 0;
|
||||
|
||||
QBuffer *buffer = new QBuffer;
|
||||
buffer->setData(cachedData);
|
||||
buffer->open(QIODevice::ReadOnly);
|
||||
return buffer;
|
||||
}
|
||||
};
|
||||
|
||||
class HttpServer : public QTcpServer
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
HttpServer(const QByteArray &reply)
|
||||
: m_reply(reply), m_writePos(), m_client()
|
||||
{
|
||||
listen(QHostAddress::AnyIPv4);
|
||||
connect(this, SIGNAL(newConnection()), this, SLOT(accept()));
|
||||
}
|
||||
|
||||
private Q_SLOTS:
|
||||
void accept()
|
||||
{
|
||||
m_client = nextPendingConnection();
|
||||
m_client->setParent(this);
|
||||
connect(m_client, SIGNAL(readyRead()), this, SLOT(reply()));
|
||||
}
|
||||
|
||||
void reply()
|
||||
{
|
||||
disconnect(m_client, SIGNAL(readyRead()));
|
||||
m_client->readAll();
|
||||
connect(m_client, SIGNAL(bytesWritten(qint64)), this, SLOT(write()));
|
||||
write();
|
||||
}
|
||||
|
||||
void write()
|
||||
{
|
||||
qint64 pos = m_client->write(m_reply.mid(m_writePos));
|
||||
if (pos > 0)
|
||||
m_writePos += pos;
|
||||
if (m_writePos >= m_reply.size())
|
||||
m_client->disconnect();
|
||||
}
|
||||
|
||||
private:
|
||||
QByteArray m_reply;
|
||||
qint64 m_writePos;
|
||||
QTcpSocket *m_client;
|
||||
};
|
||||
|
||||
class tst_qnetworkreply_from_cache : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
tst_qnetworkreply_from_cache();
|
||||
|
||||
void timeReadAll(const QString &headers, const QByteArray &data = QByteArray());
|
||||
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
void cleanup();
|
||||
|
||||
void readAll_data();
|
||||
void readAll();
|
||||
void readAllFromCache_data();
|
||||
void readAllFromCache();
|
||||
|
||||
protected Q_SLOTS:
|
||||
void replyReadAll() { m_replyData += m_reply->readAll(); }
|
||||
|
||||
private:
|
||||
QTemporaryDir m_tempDir;
|
||||
QNetworkAccessManager *m_networkAccessManager;
|
||||
NetworkDiskCache *m_networkDiskCache;
|
||||
QNetworkReply *m_reply;
|
||||
QByteArray m_replyData;
|
||||
};
|
||||
|
||||
tst_qnetworkreply_from_cache::tst_qnetworkreply_from_cache()
|
||||
: m_tempDir(QDir::tempPath() + "/tst_qnetworkreply_from_cache.XXXXXX")
|
||||
{
|
||||
}
|
||||
|
||||
void tst_qnetworkreply_from_cache::timeReadAll(const QString &headers, const QByteArray &data)
|
||||
{
|
||||
QByteArray reply;
|
||||
reply.append(headers.toUtf8());
|
||||
reply.append(data);
|
||||
|
||||
m_replyData.reserve(data.size());
|
||||
|
||||
HttpServer server(reply);
|
||||
|
||||
QBENCHMARK_ONCE {
|
||||
QNetworkRequest request(QUrl(QString("http://127.0.0.1:%1").arg(server.serverPort())));
|
||||
m_reply = m_networkAccessManager->get(request);
|
||||
connect(m_reply, SIGNAL(readyRead()), this, SLOT(replyReadAll()), Qt::QueuedConnection);
|
||||
connect(m_reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
|
||||
QTestEventLoop::instance().enterLoop(TEST_CASE_TIMEOUT);
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
delete m_reply;
|
||||
}
|
||||
|
||||
QCOMPARE(data.size(), m_replyData.size());
|
||||
QCOMPARE(data, m_replyData);
|
||||
}
|
||||
|
||||
void tst_qnetworkreply_from_cache::initTestCase()
|
||||
{
|
||||
m_networkAccessManager = new QNetworkAccessManager(this);
|
||||
m_networkDiskCache = new NetworkDiskCache(m_networkAccessManager);
|
||||
m_networkDiskCache->setCacheDirectory(m_tempDir.path());
|
||||
m_networkAccessManager->setCache(m_networkDiskCache);
|
||||
}
|
||||
|
||||
void tst_qnetworkreply_from_cache::cleanup()
|
||||
{
|
||||
m_replyData.clear();
|
||||
}
|
||||
|
||||
void tst_qnetworkreply_from_cache::readAll_data()
|
||||
{
|
||||
QTest::addColumn<int>("dataSize");
|
||||
QTest::newRow("1MB") << (int)1e6;
|
||||
QTest::newRow("5MB") << (int)5e6;
|
||||
QTest::newRow("10MB") << (int)10e6;
|
||||
}
|
||||
|
||||
void tst_qnetworkreply_from_cache::readAll()
|
||||
{
|
||||
QFETCH(int, dataSize);
|
||||
QString headers = QString("HTTP/1.0 200 OK\r\nContent-Length: %1\r\n\r\n").arg(dataSize);
|
||||
QByteArray data(QByteArray(dataSize, (char)42));
|
||||
m_networkDiskCache->cachedData.clear();
|
||||
timeReadAll(headers, data);
|
||||
}
|
||||
|
||||
void tst_qnetworkreply_from_cache::readAllFromCache_data()
|
||||
{
|
||||
readAll_data();
|
||||
}
|
||||
|
||||
void tst_qnetworkreply_from_cache::readAllFromCache()
|
||||
{
|
||||
QFETCH(int, dataSize);
|
||||
QByteArray headers("HTTP/1.0 304 Use Cache\r\n\r\n");
|
||||
QByteArray data(QByteArray(dataSize, (char)42));
|
||||
m_networkDiskCache->cachedData = data;
|
||||
timeReadAll(headers, data);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_qnetworkreply_from_cache)
|
||||
#include "tst_qnetworkreply_from_cache.moc"
|
6
tests/benchmarks/network/kernel/CMakeLists.txt
Normal file
6
tests/benchmarks/network/kernel/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
if(QT_FEATURE_private_tests)
|
||||
add_subdirectory(qhostinfo)
|
||||
endif()
|
16
tests/benchmarks/network/kernel/qhostinfo/CMakeLists.txt
Normal file
16
tests/benchmarks/network/kernel/qhostinfo/CMakeLists.txt
Normal file
@ -0,0 +1,16 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qhostinfo Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qhostinfo
|
||||
SOURCES
|
||||
main.cpp
|
||||
LIBRARIES
|
||||
Qt::CorePrivate
|
||||
Qt::Network
|
||||
Qt::NetworkPrivate
|
||||
Qt::Test
|
||||
)
|
82
tests/benchmarks/network/kernel/qhostinfo/main.cpp
Normal file
82
tests/benchmarks/network/kernel/qhostinfo/main.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
|
||||
#include <QDebug>
|
||||
#include <QHostInfo>
|
||||
#include <QStringList>
|
||||
#include <QString>
|
||||
|
||||
#include <qtest.h>
|
||||
#include <qtesteventloop.h>
|
||||
|
||||
#include "private/qhostinfo_p.h"
|
||||
|
||||
class tst_qhostinfo : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public slots:
|
||||
void init();
|
||||
private slots:
|
||||
void lookupSpeed_data();
|
||||
void lookupSpeed();
|
||||
};
|
||||
|
||||
class SignalReceiver : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SignalReceiver(int nrc) : receiveCount(0), neededReceiveCount(nrc) {};
|
||||
int receiveCount;
|
||||
int neededReceiveCount;
|
||||
public slots:
|
||||
void resultsReady(const QHostInfo) {
|
||||
receiveCount++;
|
||||
if (receiveCount == neededReceiveCount)
|
||||
QTestEventLoop::instance().exitLoop();
|
||||
}
|
||||
};
|
||||
|
||||
void tst_qhostinfo::init()
|
||||
{
|
||||
// delete the cache so inidividual testcase results are independent from each other
|
||||
qt_qhostinfo_clear_cache();
|
||||
}
|
||||
|
||||
void tst_qhostinfo::lookupSpeed_data()
|
||||
{
|
||||
QTest::addColumn<bool>("cache");
|
||||
QTest::newRow("WithCache") << true;
|
||||
QTest::newRow("WithoutCache") << false;
|
||||
}
|
||||
|
||||
void tst_qhostinfo::lookupSpeed()
|
||||
{
|
||||
QFETCH(bool, cache);
|
||||
qt_qhostinfo_enable_cache(cache);
|
||||
|
||||
QStringList hostnameList;
|
||||
hostnameList << "www.ovi.com" << "www.nokia.com" << "qt-project.org" << "www.trolltech.com" << "troll.no"
|
||||
<< "www.qtcentre.org" << "forum.nokia.com" << "www.forum.nokia.com" << "wiki.forum.nokia.com"
|
||||
<< "www.nokia.no" << "nokia.de" << "127.0.0.1" << "----";
|
||||
// also add some duplicates:
|
||||
hostnameList << "www.nokia.com" << "127.0.0.1" << "www.trolltech.com";
|
||||
// and some more
|
||||
hostnameList << hostnameList;
|
||||
|
||||
const int COUNT = hostnameList.size();
|
||||
|
||||
SignalReceiver receiver(COUNT);
|
||||
|
||||
QBENCHMARK {
|
||||
for (int i = 0; i < hostnameList.size(); i++)
|
||||
QHostInfo::lookupHost(hostnameList.at(i), &receiver, SLOT(resultsReady(QHostInfo)));
|
||||
QTestEventLoop::instance().enterLoop(20);
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QTEST_MAIN(tst_qhostinfo)
|
||||
|
||||
#include "main.moc"
|
6
tests/benchmarks/network/socket/CMakeLists.txt
Normal file
6
tests/benchmarks/network/socket/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
add_subdirectory(qlocalsocket)
|
||||
add_subdirectory(qtcpserver)
|
||||
add_subdirectory(qudpsocket)
|
14
tests/benchmarks/network/socket/qlocalsocket/CMakeLists.txt
Normal file
14
tests/benchmarks/network/socket/qlocalsocket/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qlocalsocket Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qlocalsocket
|
||||
SOURCES
|
||||
tst_qlocalsocket.cpp
|
||||
LIBRARIES
|
||||
Qt::Network
|
||||
Qt::Test
|
||||
)
|
@ -0,0 +1,212 @@
|
||||
// Copyright (C) 2021 The Qt Company Ltd.
|
||||
// Copyright (C) 2021 Alex Trotsenko <alex1973tr@gmail.com>
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QTest>
|
||||
#include <QtTest/qtesteventloop.h>
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/qthread.h>
|
||||
#include <QtCore/qsemaphore.h>
|
||||
#include <QtCore/qbytearray.h>
|
||||
#include <QtCore/qvector.h>
|
||||
#include <QtCore/qelapsedtimer.h>
|
||||
#include <QtNetwork/qlocalsocket.h>
|
||||
#include <QtNetwork/qlocalserver.h>
|
||||
|
||||
class tst_QLocalSocket : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void pingPong_data();
|
||||
void pingPong();
|
||||
void dataExchange_data();
|
||||
void dataExchange();
|
||||
};
|
||||
|
||||
class ServerThread : public QThread
|
||||
{
|
||||
public:
|
||||
QSemaphore running;
|
||||
|
||||
explicit ServerThread(int chunkSize)
|
||||
{
|
||||
buffer.resize(chunkSize);
|
||||
}
|
||||
|
||||
void run() override
|
||||
{
|
||||
QLocalServer server;
|
||||
|
||||
connect(&server, &QLocalServer::newConnection, [this, &server]() {
|
||||
auto socket = server.nextPendingConnection();
|
||||
|
||||
connect(socket, &QLocalSocket::readyRead, [this, socket]() {
|
||||
const qint64 bytesAvailable = socket->bytesAvailable();
|
||||
Q_ASSERT(bytesAvailable <= this->buffer.size());
|
||||
|
||||
QCOMPARE(socket->read(this->buffer.data(), bytesAvailable), bytesAvailable);
|
||||
QCOMPARE(socket->write(this->buffer.data(), bytesAvailable), bytesAvailable);
|
||||
});
|
||||
});
|
||||
|
||||
// TODO QTBUG-95136: on failure, remove the socket file and retry.
|
||||
QVERIFY2(server.listen("foo"), qPrintable(server.errorString()));
|
||||
|
||||
running.release();
|
||||
exec();
|
||||
}
|
||||
|
||||
protected:
|
||||
QByteArray buffer;
|
||||
};
|
||||
|
||||
class SocketFactory : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
bool stopped = false;
|
||||
|
||||
explicit SocketFactory(int chunkSize, int connections)
|
||||
{
|
||||
buffer.resize(chunkSize);
|
||||
for (int i = 0; i < connections; ++i) {
|
||||
QLocalSocket *socket = new QLocalSocket(this);
|
||||
Q_CHECK_PTR(socket);
|
||||
|
||||
connect(this, &SocketFactory::start, [this, socket]() {
|
||||
QCOMPARE(socket->write(this->buffer), this->buffer.size());
|
||||
});
|
||||
|
||||
connect(socket, &QLocalSocket::readyRead, [i, this, socket]() {
|
||||
const qint64 bytesAvailable = socket->bytesAvailable();
|
||||
Q_ASSERT(bytesAvailable <= this->buffer.size());
|
||||
|
||||
QCOMPARE(socket->read(this->buffer.data(), bytesAvailable), bytesAvailable);
|
||||
emit this->bytesReceived(i, bytesAvailable);
|
||||
|
||||
if (!this->stopped)
|
||||
QCOMPARE(socket->write(this->buffer.data(), bytesAvailable), bytesAvailable);
|
||||
});
|
||||
|
||||
socket->connectToServer("foo");
|
||||
QVERIFY2(socket->waitForConnected(), "The system is probably reaching the maximum "
|
||||
"number of open file descriptors. On Unix, "
|
||||
"try to increase the limit with 'ulimit -n 32000' "
|
||||
"and run the test again.");
|
||||
QCOMPARE(socket->state(), QLocalSocket::ConnectedState);
|
||||
}
|
||||
}
|
||||
|
||||
signals:
|
||||
void start();
|
||||
void bytesReceived(int channel, qint64 bytes);
|
||||
|
||||
protected:
|
||||
QByteArray buffer;
|
||||
};
|
||||
|
||||
void tst_QLocalSocket::pingPong_data()
|
||||
{
|
||||
QTest::addColumn<int>("connections");
|
||||
for (int value : {10, 50, 100, 1000, 5000})
|
||||
QTest::addRow("connections: %d", value) << value;
|
||||
}
|
||||
|
||||
void tst_QLocalSocket::pingPong()
|
||||
{
|
||||
QFETCH(int, connections);
|
||||
|
||||
const int iterations = 100000;
|
||||
Q_ASSERT(iterations >= connections && connections > 0);
|
||||
|
||||
ServerThread serverThread(1);
|
||||
serverThread.start();
|
||||
// Wait for server to start.
|
||||
QVERIFY(serverThread.running.tryAcquire(1, 3000));
|
||||
|
||||
SocketFactory factory(1, connections);
|
||||
QTestEventLoop eventLoop;
|
||||
QVector<qint64> bytesToRead;
|
||||
QElapsedTimer timer;
|
||||
|
||||
bytesToRead.fill(iterations / connections, connections);
|
||||
connect(&factory, &SocketFactory::bytesReceived,
|
||||
[&bytesToRead, &connections, &factory, &eventLoop](int channel, qint64 bytes) {
|
||||
Q_UNUSED(bytes);
|
||||
|
||||
if (--bytesToRead[channel] == 0 && --connections == 0) {
|
||||
factory.stopped = true;
|
||||
eventLoop.exitLoop();
|
||||
}
|
||||
});
|
||||
|
||||
timer.start();
|
||||
emit factory.start();
|
||||
// QtTestLib's Watchdog defaults to 300 seconds; we want to give up before
|
||||
// it bites.
|
||||
eventLoop.enterLoop(290);
|
||||
|
||||
if (eventLoop.timeout())
|
||||
qDebug("Timed out after %.1f s", timer.elapsed() / 1000.0);
|
||||
else if (!QTest::currentTestFailed())
|
||||
qDebug("Elapsed time: %.1f s", timer.elapsed() / 1000.0);
|
||||
serverThread.quit();
|
||||
serverThread.wait();
|
||||
}
|
||||
|
||||
void tst_QLocalSocket::dataExchange_data()
|
||||
{
|
||||
QTest::addColumn<int>("connections");
|
||||
QTest::addColumn<int>("chunkSize");
|
||||
for (int connections : {1, 5, 10}) {
|
||||
for (int chunkSize : {100, 1000, 10000, 100000}) {
|
||||
QTest::addRow("connections: %d, chunk size: %d",
|
||||
connections, chunkSize) << connections << chunkSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QLocalSocket::dataExchange()
|
||||
{
|
||||
QFETCH(int, connections);
|
||||
QFETCH(int, chunkSize);
|
||||
|
||||
Q_ASSERT(chunkSize > 0 && connections > 0);
|
||||
const qint64 timeToTest = 5000;
|
||||
|
||||
ServerThread serverThread(chunkSize);
|
||||
serverThread.start();
|
||||
// Wait for server to start.
|
||||
QVERIFY(serverThread.running.tryAcquire(1, 3000));
|
||||
|
||||
SocketFactory factory(chunkSize, connections);
|
||||
QTestEventLoop eventLoop;
|
||||
qint64 totalReceived = 0;
|
||||
QElapsedTimer timer;
|
||||
|
||||
connect(&factory, &SocketFactory::bytesReceived, [&](int channel, qint64 bytes) {
|
||||
Q_UNUSED(channel);
|
||||
|
||||
totalReceived += bytes;
|
||||
if (timer.elapsed() >= timeToTest) {
|
||||
factory.stopped = true;
|
||||
eventLoop.exitLoop();
|
||||
}
|
||||
});
|
||||
|
||||
timer.start();
|
||||
emit factory.start();
|
||||
eventLoop.enterLoopMSecs(timeToTest * 2);
|
||||
|
||||
if (!QTest::currentTestFailed())
|
||||
qDebug("Transfer rate: %.1f MB/s", totalReceived / 1048.576 / timer.elapsed());
|
||||
serverThread.quit();
|
||||
serverThread.wait();
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QLocalSocket)
|
||||
|
||||
#include "tst_qlocalsocket.moc"
|
14
tests/benchmarks/network/socket/qtcpserver/CMakeLists.txt
Normal file
14
tests/benchmarks/network/socket/qtcpserver/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qtcpserver Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qtcpserver
|
||||
SOURCES
|
||||
tst_qtcpserver.cpp
|
||||
LIBRARIES
|
||||
Qt::Network
|
||||
Qt::Test
|
||||
)
|
241
tests/benchmarks/network/socket/qtcpserver/tst_qtcpserver.cpp
Normal file
241
tests/benchmarks/network/socket/qtcpserver/tst_qtcpserver.cpp
Normal file
@ -0,0 +1,241 @@
|
||||
// Copyright (C) 2020 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QTest>
|
||||
#include <QtCore/QElapsedTimer>
|
||||
#include <qglobal.h>
|
||||
#include <qcoreapplication.h>
|
||||
#include <qtcpsocket.h>
|
||||
#include <qtcpserver.h>
|
||||
#include <qhostaddress.h>
|
||||
#include <qstringlist.h>
|
||||
#include <qplatformdefs.h>
|
||||
#include <qhostinfo.h>
|
||||
|
||||
#include <QNetworkProxy>
|
||||
|
||||
#include "../../../../auto/network-settings.h"
|
||||
|
||||
class tst_QTcpServer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
tst_QTcpServer();
|
||||
virtual ~tst_QTcpServer();
|
||||
|
||||
|
||||
public slots:
|
||||
void initTestCase_data();
|
||||
void initTestCase();
|
||||
void init();
|
||||
void cleanup();
|
||||
private slots:
|
||||
void ipv4LoopbackPerformanceTest();
|
||||
void ipv6LoopbackPerformanceTest();
|
||||
void ipv4PerformanceTest();
|
||||
};
|
||||
|
||||
tst_QTcpServer::tst_QTcpServer()
|
||||
{
|
||||
}
|
||||
|
||||
tst_QTcpServer::~tst_QTcpServer()
|
||||
{
|
||||
}
|
||||
|
||||
void tst_QTcpServer::initTestCase_data()
|
||||
{
|
||||
QTest::addColumn<bool>("setProxy");
|
||||
QTest::addColumn<int>("proxyType");
|
||||
|
||||
QTest::newRow("WithoutProxy") << false << 0;
|
||||
#ifndef QT_NO_NETWORKPROXY
|
||||
QTest::newRow("WithSocks5Proxy") << true << int(QNetworkProxy::Socks5Proxy);
|
||||
#endif
|
||||
}
|
||||
|
||||
void tst_QTcpServer::initTestCase()
|
||||
{
|
||||
if (!QtNetworkSettings::verifyTestNetworkSettings())
|
||||
QSKIP("No network test server available");
|
||||
}
|
||||
|
||||
void tst_QTcpServer::init()
|
||||
{
|
||||
QFETCH_GLOBAL(bool, setProxy);
|
||||
if (setProxy) {
|
||||
#ifndef QT_NO_NETWORKPROXY
|
||||
QFETCH_GLOBAL(int, proxyType);
|
||||
if (proxyType == QNetworkProxy::Socks5Proxy) {
|
||||
QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080));
|
||||
}
|
||||
#else // !QT_NO_NETWORKPROXY
|
||||
QSKIP("No proxy support");
|
||||
#endif // QT_NO_NETWORKPROXY
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QTcpServer::cleanup()
|
||||
{
|
||||
#ifndef QT_NO_NETWORKPROXY
|
||||
QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy);
|
||||
#endif
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
void tst_QTcpServer::ipv4LoopbackPerformanceTest()
|
||||
{
|
||||
QFETCH_GLOBAL(bool, setProxy);
|
||||
if (setProxy)
|
||||
return;
|
||||
|
||||
QTcpServer server;
|
||||
QVERIFY(server.listen(QHostAddress::LocalHost));
|
||||
|
||||
QVERIFY(server.isListening());
|
||||
|
||||
QTcpSocket clientA;
|
||||
clientA.connectToHost(QHostAddress::LocalHost, server.serverPort());
|
||||
QVERIFY(clientA.waitForConnected(5000));
|
||||
QVERIFY(clientA.state() == QAbstractSocket::ConnectedState);
|
||||
|
||||
QVERIFY(server.waitForNewConnection());
|
||||
QTcpSocket *clientB = server.nextPendingConnection();
|
||||
QVERIFY(clientB);
|
||||
|
||||
QByteArray buffer(16384, '@');
|
||||
QElapsedTimer stopWatch;
|
||||
stopWatch.start();
|
||||
qlonglong totalWritten = 0;
|
||||
while (stopWatch.elapsed() < 5000) {
|
||||
QVERIFY(clientA.write(buffer.data(), buffer.size()) > 0);
|
||||
clientA.flush();
|
||||
totalWritten += buffer.size();
|
||||
while (clientB->waitForReadyRead(100)) {
|
||||
if (clientB->bytesAvailable() == 16384)
|
||||
break;
|
||||
}
|
||||
clientB->read(buffer.data(), buffer.size());
|
||||
clientB->write(buffer.data(), buffer.size());
|
||||
clientB->flush();
|
||||
totalWritten += buffer.size();
|
||||
while (clientA.waitForReadyRead(100)) {
|
||||
if (clientA.bytesAvailable() == 16384)
|
||||
break;
|
||||
}
|
||||
clientA.read(buffer.data(), buffer.size());
|
||||
}
|
||||
|
||||
qDebug("\t\t%s: %.1fMB/%.1fs: %.1fMB/s",
|
||||
server.serverAddress().toString().toLatin1().constData(),
|
||||
totalWritten / (1024.0 * 1024.0),
|
||||
stopWatch.elapsed() / 1000.0,
|
||||
(totalWritten / (stopWatch.elapsed() / 1000.0)) / (1024 * 1024));
|
||||
|
||||
delete clientB;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
void tst_QTcpServer::ipv6LoopbackPerformanceTest()
|
||||
{
|
||||
QFETCH_GLOBAL(bool, setProxy);
|
||||
if (setProxy)
|
||||
return;
|
||||
|
||||
QTcpServer server;
|
||||
if (!server.listen(QHostAddress::LocalHostIPv6, 0)) {
|
||||
QVERIFY(server.serverError() == QAbstractSocket::UnsupportedSocketOperationError);
|
||||
} else {
|
||||
QTcpSocket clientA;
|
||||
clientA.connectToHost(server.serverAddress(), server.serverPort());
|
||||
QVERIFY(clientA.waitForConnected(5000));
|
||||
|
||||
QVERIFY(server.waitForNewConnection(5000));
|
||||
QTcpSocket *clientB = server.nextPendingConnection();
|
||||
QVERIFY(clientB);
|
||||
|
||||
QByteArray buffer(16384, '@');
|
||||
QElapsedTimer stopWatch;
|
||||
stopWatch.start();
|
||||
qlonglong totalWritten = 0;
|
||||
while (stopWatch.elapsed() < 5000) {
|
||||
clientA.write(buffer.data(), buffer.size());
|
||||
clientA.flush();
|
||||
totalWritten += buffer.size();
|
||||
while (clientB->waitForReadyRead(100)) {
|
||||
if (clientB->bytesAvailable() == 16384)
|
||||
break;
|
||||
}
|
||||
clientB->read(buffer.data(), buffer.size());
|
||||
clientB->write(buffer.data(), buffer.size());
|
||||
clientB->flush();
|
||||
totalWritten += buffer.size();
|
||||
while (clientA.waitForReadyRead(100)) {
|
||||
if (clientA.bytesAvailable() == 16384)
|
||||
break;
|
||||
}
|
||||
clientA.read(buffer.data(), buffer.size());
|
||||
}
|
||||
|
||||
qDebug("\t\t%s: %.1fMB/%.1fs: %.1fMB/s",
|
||||
server.serverAddress().toString().toLatin1().constData(),
|
||||
totalWritten / (1024.0 * 1024.0),
|
||||
stopWatch.elapsed() / 1000.0,
|
||||
(totalWritten / (stopWatch.elapsed() / 1000.0)) / (1024 * 1024));
|
||||
delete clientB;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
void tst_QTcpServer::ipv4PerformanceTest()
|
||||
{
|
||||
QTcpSocket probeSocket;
|
||||
probeSocket.connectToHost(QtNetworkSettings::serverName(), 143);
|
||||
QVERIFY(probeSocket.waitForConnected(5000));
|
||||
|
||||
QTcpServer server;
|
||||
QVERIFY(server.listen(probeSocket.localAddress(), 0));
|
||||
|
||||
QTcpSocket clientA;
|
||||
clientA.connectToHost(server.serverAddress(), server.serverPort());
|
||||
QVERIFY(clientA.waitForConnected(5000));
|
||||
|
||||
QVERIFY(server.waitForNewConnection(5000));
|
||||
QTcpSocket *clientB = server.nextPendingConnection();
|
||||
QVERIFY(clientB);
|
||||
|
||||
QByteArray buffer(16384, '@');
|
||||
QElapsedTimer stopWatch;
|
||||
stopWatch.start();
|
||||
qlonglong totalWritten = 0;
|
||||
while (stopWatch.elapsed() < 5000) {
|
||||
qlonglong writtenA = clientA.write(buffer.data(), buffer.size());
|
||||
clientA.flush();
|
||||
totalWritten += buffer.size();
|
||||
while (clientB->waitForReadyRead(100)) {
|
||||
if (clientB->bytesAvailable() == writtenA)
|
||||
break;
|
||||
}
|
||||
clientB->read(buffer.data(), buffer.size());
|
||||
qlonglong writtenB = clientB->write(buffer.data(), buffer.size());
|
||||
clientB->flush();
|
||||
totalWritten += buffer.size();
|
||||
while (clientA.waitForReadyRead(100)) {
|
||||
if (clientA.bytesAvailable() == writtenB)
|
||||
break;
|
||||
}
|
||||
clientA.read(buffer.data(), buffer.size());
|
||||
}
|
||||
|
||||
qDebug("\t\t%s: %.1fMB/%.1fs: %.1fMB/s",
|
||||
probeSocket.localAddress().toString().toLatin1().constData(),
|
||||
totalWritten / (1024.0 * 1024.0),
|
||||
stopWatch.elapsed() / 1000.0,
|
||||
(totalWritten / (stopWatch.elapsed() / 1000.0)) / (1024 * 1024));
|
||||
|
||||
delete clientB;
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QTcpServer)
|
||||
#include "tst_qtcpserver.moc"
|
14
tests/benchmarks/network/socket/qudpsocket/CMakeLists.txt
Normal file
14
tests/benchmarks/network/socket/qudpsocket/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qudpsocket Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qudpsocket
|
||||
SOURCES
|
||||
tst_qudpsocket.cpp
|
||||
LIBRARIES
|
||||
Qt::Network
|
||||
Qt::Test
|
||||
)
|
@ -0,0 +1,55 @@
|
||||
// Copyright (C) 2019 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QTest>
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#include <QtNetwork/qudpsocket.h>
|
||||
#include <QtNetwork/qnetworkdatagram.h>
|
||||
|
||||
class tst_QUdpSocket : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
tst_QUdpSocket();
|
||||
|
||||
private slots:
|
||||
void pendingDatagramSize_data();
|
||||
void pendingDatagramSize();
|
||||
};
|
||||
|
||||
tst_QUdpSocket::tst_QUdpSocket()
|
||||
{
|
||||
}
|
||||
|
||||
void tst_QUdpSocket::pendingDatagramSize_data()
|
||||
{
|
||||
QTest::addColumn<int>("size");
|
||||
for (int value : {52, 1024, 2049, 4500, 4098, 8192, 12000, 25000, 32 * 1024, 63 * 1024})
|
||||
QTest::addRow("%d", value) << value;
|
||||
}
|
||||
|
||||
void tst_QUdpSocket::pendingDatagramSize()
|
||||
{
|
||||
QFETCH(int, size);
|
||||
QUdpSocket socket;
|
||||
socket.bind();
|
||||
|
||||
QNetworkDatagram datagram;
|
||||
datagram.setData(QByteArray(size, 'a'));
|
||||
datagram.setDestination(QHostAddress::SpecialAddress::LocalHost, socket.localPort());
|
||||
|
||||
auto sent = socket.writeDatagram(datagram);
|
||||
QCOMPARE(sent, size);
|
||||
|
||||
auto res = QTest::qWaitFor([&socket]() { return socket.hasPendingDatagrams(); }, 5000);
|
||||
QVERIFY(res);
|
||||
|
||||
QBENCHMARK {
|
||||
auto pendingSize = socket.pendingDatagramSize();
|
||||
Q_UNUSED(pendingSize);
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QUdpSocket)
|
||||
#include "tst_qudpsocket.moc"
|
4
tests/benchmarks/network/ssl/CMakeLists.txt
Normal file
4
tests/benchmarks/network/ssl/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
add_subdirectory(qsslsocket)
|
14
tests/benchmarks/network/ssl/qsslsocket/CMakeLists.txt
Normal file
14
tests/benchmarks/network/ssl/qsslsocket/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_bench_qsslsocket Binary:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_benchmark(tst_bench_qsslsocket
|
||||
SOURCES
|
||||
tst_qsslsocket.cpp
|
||||
LIBRARIES
|
||||
Qt::Network
|
||||
Qt::Test
|
||||
)
|
75
tests/benchmarks/network/ssl/qsslsocket/tst_qsslsocket.cpp
Normal file
75
tests/benchmarks/network/ssl/qsslsocket/tst_qsslsocket.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QTest>
|
||||
|
||||
#include <qcoreapplication.h>
|
||||
#include <qsslconfiguration.h>
|
||||
#include <qsslsocket.h>
|
||||
|
||||
|
||||
#include "../../../../auto/network-settings.h"
|
||||
|
||||
class tst_QSslSocket : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
tst_QSslSocket();
|
||||
virtual ~tst_QSslSocket();
|
||||
|
||||
|
||||
public slots:
|
||||
void initTestCase();
|
||||
void init();
|
||||
void cleanup();
|
||||
private slots:
|
||||
void rootCertLoading();
|
||||
void systemCaCertificates();
|
||||
};
|
||||
|
||||
tst_QSslSocket::tst_QSslSocket()
|
||||
{
|
||||
}
|
||||
|
||||
tst_QSslSocket::~tst_QSslSocket()
|
||||
{
|
||||
}
|
||||
|
||||
void tst_QSslSocket::initTestCase()
|
||||
{
|
||||
if (!QtNetworkSettings::verifyTestNetworkSettings())
|
||||
QSKIP("No network test server available");
|
||||
}
|
||||
|
||||
void tst_QSslSocket::init()
|
||||
{
|
||||
}
|
||||
|
||||
void tst_QSslSocket::cleanup()
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
void tst_QSslSocket::rootCertLoading()
|
||||
{
|
||||
QBENCHMARK_ONCE {
|
||||
QSslSocket socket;
|
||||
socket.connectToHostEncrypted(QtNetworkSettings::serverName(), 443);
|
||||
socket.waitForEncrypted();
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QSslSocket::systemCaCertificates()
|
||||
{
|
||||
// The results of this test change if the benchmarking system changes too much.
|
||||
// Therefore this benchmark is only good for manual regression checking between
|
||||
// Qt versions.
|
||||
QBENCHMARK_ONCE {
|
||||
QList<QSslCertificate> list = QSslConfiguration::defaultConfiguration().systemCaCertificates();
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QSslSocket)
|
||||
#include "tst_qsslsocket.moc"
|
Reference in New Issue
Block a user