mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-06 17:25:24 +08:00
qt 6.5.1 original
This commit is contained in:
13
tests/auto/network/access/qnetworkdiskcache/CMakeLists.txt
Normal file
13
tests/auto/network/access/qnetworkdiskcache/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#####################################################################
|
||||
## tst_qnetworkdiskcache Test:
|
||||
#####################################################################
|
||||
|
||||
qt_internal_add_test(tst_qnetworkdiskcache
|
||||
SOURCES
|
||||
tst_qnetworkdiskcache.cpp
|
||||
LIBRARIES
|
||||
Qt::Network
|
||||
)
|
@ -0,0 +1,818 @@
|
||||
// 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 <QtNetwork/QtNetwork>
|
||||
#include <QTest>
|
||||
#include <QTestEventLoop>
|
||||
#include <qnetworkdiskcache.h>
|
||||
#include <qrandom.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#define EXAMPLE_URL "http://user:pass@localhost:4/#foo"
|
||||
#define EXAMPLE_URL2 "http://user:pass@localhost:4/bar"
|
||||
//cached objects are organized into these many subdirs
|
||||
#define NUM_SUBDIRECTORIES 15
|
||||
|
||||
class tst_QNetworkDiskCache : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
tst_QNetworkDiskCache();
|
||||
|
||||
public slots:
|
||||
void accessAfterRemoveReadyReadSlot();
|
||||
void setCookieHeaderMetaDataChangedSlot();
|
||||
|
||||
private slots:
|
||||
void initTestCase();
|
||||
void cleanupTestCase();
|
||||
void qnetworkdiskcache_data();
|
||||
void qnetworkdiskcache();
|
||||
|
||||
void prepare();
|
||||
void cacheSize();
|
||||
void clear();
|
||||
void data_data();
|
||||
void data();
|
||||
void metaData();
|
||||
void remove();
|
||||
void accessAfterRemove(); // QTBUG-17400
|
||||
void setCookieHeader(); // QTBUG-41514
|
||||
void setCacheDirectory_data();
|
||||
void setCacheDirectory();
|
||||
void updateMetaData();
|
||||
void fileMetaData();
|
||||
void expire();
|
||||
|
||||
void oldCacheVersionFile_data();
|
||||
void oldCacheVersionFile();
|
||||
|
||||
void streamVersion_data();
|
||||
void streamVersion();
|
||||
|
||||
void sync();
|
||||
|
||||
void crashWhenParentingCache();
|
||||
|
||||
private:
|
||||
QTemporaryDir tempDir;
|
||||
QUrl url; // used by accessAfterRemove(), setCookieHeader()
|
||||
QNetworkDiskCache *diskCache; // used by accessAfterRemove()
|
||||
QNetworkAccessManager *manager; // used by setCookieHeader()
|
||||
};
|
||||
|
||||
// FIXME same as in tst_qnetworkreply.cpp .. could be unified
|
||||
// Does not work for POST/PUT!
|
||||
class MiniHttpServer: public QTcpServer
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QTcpSocket *client; // always the last one that was received
|
||||
QByteArray dataToTransmit;
|
||||
QByteArray receivedData;
|
||||
bool doClose;
|
||||
bool multiple;
|
||||
int totalConnections;
|
||||
|
||||
MiniHttpServer(const QByteArray &data) : client(0), dataToTransmit(data), doClose(true), multiple(false), totalConnections(0)
|
||||
{
|
||||
listen();
|
||||
connect(this, SIGNAL(newConnection()), this, SLOT(doAccept()));
|
||||
}
|
||||
|
||||
public slots:
|
||||
void doAccept()
|
||||
{
|
||||
client = nextPendingConnection();
|
||||
client->setParent(this);
|
||||
++totalConnections;
|
||||
connect(client, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
|
||||
}
|
||||
|
||||
void readyReadSlot()
|
||||
{
|
||||
receivedData += client->readAll();
|
||||
int doubleEndlPos = receivedData.indexOf("\r\n\r\n");
|
||||
|
||||
if (doubleEndlPos != -1) {
|
||||
// multiple requests incoming. remove the bytes of the current one
|
||||
if (multiple)
|
||||
receivedData.remove(0, doubleEndlPos+4);
|
||||
|
||||
client->write(dataToTransmit);
|
||||
if (doClose) {
|
||||
client->disconnectFromHost();
|
||||
disconnect(client, 0, this, 0);
|
||||
client = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Subclass that exposes the protected functions.
|
||||
class SubQNetworkDiskCache : public QNetworkDiskCache
|
||||
{
|
||||
public:
|
||||
~SubQNetworkDiskCache()
|
||||
{
|
||||
if (!cacheDirectory().isEmpty() && clearOnDestruction)
|
||||
clear();
|
||||
}
|
||||
|
||||
QNetworkCacheMetaData call_fileMetaData(QString const &fileName)
|
||||
{ return SubQNetworkDiskCache::fileMetaData(fileName); }
|
||||
|
||||
qint64 call_expire()
|
||||
{ return SubQNetworkDiskCache::expire(); }
|
||||
|
||||
void setupWithOne(const QString &path, const QUrl &url, const QNetworkCacheMetaData &metaData = QNetworkCacheMetaData())
|
||||
{
|
||||
setCacheDirectory(path);
|
||||
|
||||
QIODevice *d = nullptr;
|
||||
if (metaData.isValid()) {
|
||||
d = prepare(metaData);
|
||||
} else {
|
||||
QNetworkCacheMetaData m;
|
||||
m.setUrl(url);
|
||||
QNetworkCacheMetaData::RawHeader header("content-type", "text/html");
|
||||
QNetworkCacheMetaData::RawHeaderList list;
|
||||
list.append(header);
|
||||
m.setRawHeaders(list);
|
||||
d = prepare(m);
|
||||
}
|
||||
d->write("Hello World!");
|
||||
insert(d);
|
||||
}
|
||||
|
||||
void setClearCacheOnDestruction(bool value) { clearOnDestruction = value; }
|
||||
|
||||
private:
|
||||
bool clearOnDestruction = true;
|
||||
};
|
||||
|
||||
tst_QNetworkDiskCache::tst_QNetworkDiskCache()
|
||||
: tempDir(QDir::tempPath() + "/tst_qnetworkdiskcache.XXXXXX")
|
||||
{
|
||||
}
|
||||
|
||||
// This will be called before the first test function is executed.
|
||||
// It is only called once.
|
||||
void tst_QNetworkDiskCache::initTestCase()
|
||||
{
|
||||
QVERIFY(tempDir.isValid());
|
||||
|
||||
SubQNetworkDiskCache cache;
|
||||
cache.setCacheDirectory(tempDir.path());
|
||||
}
|
||||
|
||||
// This will be called after the last test function is executed.
|
||||
// It is only called once.
|
||||
void tst_QNetworkDiskCache::cleanupTestCase()
|
||||
{
|
||||
QDir workingDir("foo");
|
||||
if (workingDir.exists())
|
||||
workingDir.removeRecursively();
|
||||
}
|
||||
|
||||
void tst_QNetworkDiskCache::qnetworkdiskcache_data()
|
||||
{
|
||||
}
|
||||
|
||||
void tst_QNetworkDiskCache::qnetworkdiskcache()
|
||||
{
|
||||
QUrl url(EXAMPLE_URL);
|
||||
SubQNetworkDiskCache cache;
|
||||
QCOMPARE(cache.cacheDirectory(), QString());
|
||||
QCOMPARE(cache.cacheSize(), qint64(0));
|
||||
cache.clear();
|
||||
QCOMPARE(cache.metaData(QUrl()), QNetworkCacheMetaData());
|
||||
QCOMPARE(cache.remove(QUrl()), false);
|
||||
QCOMPARE(cache.remove(url), false);
|
||||
cache.insert((QIODevice*)0);
|
||||
cache.setCacheDirectory(QString());
|
||||
cache.updateMetaData(QNetworkCacheMetaData());
|
||||
cache.prepare(QNetworkCacheMetaData());
|
||||
QCOMPARE(cache.call_fileMetaData(QString()), QNetworkCacheMetaData());
|
||||
|
||||
// leave one hanging around...
|
||||
QNetworkDiskCache badCache;
|
||||
QNetworkCacheMetaData metaData;
|
||||
metaData.setUrl(url);
|
||||
badCache.prepare(metaData);
|
||||
badCache.setCacheDirectory(tempDir.path());
|
||||
badCache.prepare(metaData);
|
||||
}
|
||||
|
||||
void tst_QNetworkDiskCache::prepare()
|
||||
{
|
||||
SubQNetworkDiskCache cache;
|
||||
cache.setCacheDirectory(tempDir.path());
|
||||
|
||||
QUrl url(EXAMPLE_URL);
|
||||
QNetworkCacheMetaData metaData;
|
||||
metaData.setUrl(url);
|
||||
|
||||
cache.prepare(metaData);
|
||||
cache.remove(url);
|
||||
}
|
||||
|
||||
// public qint64 cacheSize() const
|
||||
void tst_QNetworkDiskCache::cacheSize()
|
||||
{
|
||||
qint64 cacheSize = 0;
|
||||
{
|
||||
SubQNetworkDiskCache cache;
|
||||
cache.setCacheDirectory(tempDir.path());
|
||||
QCOMPARE(cache.cacheSize(), qint64(0));
|
||||
|
||||
{
|
||||
QUrl url(EXAMPLE_URL);
|
||||
QNetworkCacheMetaData metaData;
|
||||
metaData.setUrl(url);
|
||||
QIODevice *d = cache.prepare(metaData);
|
||||
cache.insert(d);
|
||||
cacheSize = cache.cacheSize();
|
||||
QVERIFY(cacheSize > qint64(0));
|
||||
}
|
||||
// Add a second item, some difference in behavior when the cache is not empty
|
||||
{
|
||||
QUrl url(EXAMPLE_URL2);
|
||||
QNetworkCacheMetaData metaData;
|
||||
metaData.setUrl(url);
|
||||
QIODevice *d = cache.prepare(metaData);
|
||||
cache.insert(d);
|
||||
QVERIFY(cache.cacheSize() > cacheSize);
|
||||
cacheSize = cache.cacheSize();
|
||||
}
|
||||
|
||||
// Don't clear the cache on destruction so we can re-open the cache and test its size.
|
||||
cache.setClearCacheOnDestruction(false);
|
||||
}
|
||||
|
||||
SubQNetworkDiskCache cache;
|
||||
cache.setCacheDirectory(tempDir.path());
|
||||
QCOMPARE(cache.cacheSize(), cacheSize);
|
||||
cache.clear();
|
||||
QCOMPARE(cache.cacheSize(), qint64(0));
|
||||
}
|
||||
|
||||
static QStringList countFiles(const QString dir)
|
||||
{
|
||||
QStringList list;
|
||||
QDir::Filters filter(QDir::AllEntries | QDir::NoDotAndDotDot);
|
||||
QDirIterator it(dir, filter, QDirIterator::Subdirectories);
|
||||
while (it.hasNext())
|
||||
list.append(it.next());
|
||||
return list;
|
||||
}
|
||||
|
||||
// public void clear()
|
||||
void tst_QNetworkDiskCache::clear()
|
||||
{
|
||||
SubQNetworkDiskCache cache;
|
||||
QUrl url(EXAMPLE_URL);
|
||||
cache.setupWithOne(tempDir.path(), url);
|
||||
QVERIFY(cache.cacheSize() > qint64(0));
|
||||
|
||||
QString cacheDirectory = cache.cacheDirectory();
|
||||
QCOMPARE(countFiles(cacheDirectory).size(), NUM_SUBDIRECTORIES + 3);
|
||||
cache.clear();
|
||||
QCOMPARE(countFiles(cacheDirectory).size(), NUM_SUBDIRECTORIES + 2);
|
||||
|
||||
// don't delete files that it didn't create
|
||||
QTemporaryFile file(cacheDirectory + "/XXXXXX");
|
||||
if (file.open()) {
|
||||
file.fileName(); // make sure it exists with a name
|
||||
QCOMPARE(countFiles(cacheDirectory).size(), NUM_SUBDIRECTORIES + 3);
|
||||
cache.clear();
|
||||
QCOMPARE(countFiles(cacheDirectory).size(), NUM_SUBDIRECTORIES + 3);
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(QNetworkCacheMetaData)
|
||||
void tst_QNetworkDiskCache::data_data()
|
||||
{
|
||||
QTest::addColumn<QNetworkCacheMetaData>("data");
|
||||
|
||||
QTest::newRow("null") << QNetworkCacheMetaData();
|
||||
|
||||
QUrl url(EXAMPLE_URL);
|
||||
QNetworkCacheMetaData metaData;
|
||||
metaData.setUrl(url);
|
||||
QNetworkCacheMetaData::RawHeaderList headers;
|
||||
headers.append(QNetworkCacheMetaData::RawHeader("type", "bin"));
|
||||
metaData.setRawHeaders(headers);
|
||||
QTest::newRow("non-null") << metaData;
|
||||
}
|
||||
|
||||
// public QIODevice* data(QUrl const& url)
|
||||
void tst_QNetworkDiskCache::data()
|
||||
{
|
||||
QFETCH(QNetworkCacheMetaData, data);
|
||||
SubQNetworkDiskCache cache;
|
||||
QUrl url(EXAMPLE_URL);
|
||||
cache.setupWithOne(tempDir.path(), url, data);
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
QIODevice *d = cache.data(url);
|
||||
QVERIFY(d);
|
||||
QCOMPARE(d->readAll(), QByteArray("Hello World!"));
|
||||
delete d;
|
||||
}
|
||||
}
|
||||
|
||||
// public QNetworkCacheMetaData metaData(QUrl const& url)
|
||||
void tst_QNetworkDiskCache::metaData()
|
||||
{
|
||||
SubQNetworkDiskCache cache;
|
||||
|
||||
QUrl url(EXAMPLE_URL);
|
||||
QNetworkCacheMetaData metaData;
|
||||
metaData.setUrl(url);
|
||||
QNetworkCacheMetaData::RawHeaderList headers;
|
||||
headers.append(QNetworkCacheMetaData::RawHeader("type", "bin"));
|
||||
metaData.setRawHeaders(headers);
|
||||
metaData.setLastModified(QDateTime::currentDateTime());
|
||||
metaData.setExpirationDate(QDateTime::currentDateTime());
|
||||
metaData.setSaveToDisk(true);
|
||||
|
||||
cache.setupWithOne(tempDir.path(), url, metaData);
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
QNetworkCacheMetaData cacheMetaData = cache.metaData(url);
|
||||
QVERIFY(cacheMetaData.isValid());
|
||||
QCOMPARE(metaData, cacheMetaData);
|
||||
}
|
||||
}
|
||||
|
||||
// public bool remove(QUrl const& url)
|
||||
void tst_QNetworkDiskCache::remove()
|
||||
{
|
||||
SubQNetworkDiskCache cache;
|
||||
QUrl url(EXAMPLE_URL);
|
||||
cache.setupWithOne(tempDir.path(), url);
|
||||
QString cacheDirectory = cache.cacheDirectory();
|
||||
QCOMPARE(countFiles(cacheDirectory).size(), NUM_SUBDIRECTORIES + 3);
|
||||
cache.remove(url);
|
||||
QCOMPARE(countFiles(cacheDirectory).size(), NUM_SUBDIRECTORIES + 2);
|
||||
}
|
||||
|
||||
void tst_QNetworkDiskCache::accessAfterRemove() // QTBUG-17400
|
||||
{
|
||||
QByteArray data("HTTP/1.1 200 OK\r\n"
|
||||
"Content-Length: 1\r\n"
|
||||
"\r\n"
|
||||
"a");
|
||||
|
||||
MiniHttpServer server(data);
|
||||
|
||||
QNetworkAccessManager *manager = new QNetworkAccessManager();
|
||||
SubQNetworkDiskCache subCache;
|
||||
subCache.setCacheDirectory(QLatin1String("cacheDir"));
|
||||
diskCache = &subCache;
|
||||
manager->setCache(&subCache);
|
||||
|
||||
url = QUrl("http://127.0.0.1:" + QString::number(server.serverPort()));
|
||||
QNetworkRequest request(url);
|
||||
|
||||
QNetworkReply *reply = manager->get(request);
|
||||
connect(reply, SIGNAL(readyRead()), this, SLOT(accessAfterRemoveReadyReadSlot()));
|
||||
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
|
||||
|
||||
QTestEventLoop::instance().enterLoop(5);
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
|
||||
reply->deleteLater();
|
||||
manager->deleteLater();
|
||||
}
|
||||
|
||||
void tst_QNetworkDiskCache::accessAfterRemoveReadyReadSlot()
|
||||
{
|
||||
diskCache->remove(url); // this used to cause a crash later on
|
||||
}
|
||||
|
||||
void tst_QNetworkDiskCache::setCookieHeader() // QTBUG-41514
|
||||
{
|
||||
SubQNetworkDiskCache *cache = new SubQNetworkDiskCache();
|
||||
url = QUrl("http://localhost:4/cookieTest.html"); // hopefully no one is running an HTTP server on port 4
|
||||
QNetworkCacheMetaData metaData;
|
||||
metaData.setUrl(url);
|
||||
|
||||
QNetworkCacheMetaData::RawHeaderList headers;
|
||||
headers.append(QNetworkCacheMetaData::RawHeader("Set-Cookie", "aaa=bbb"));
|
||||
metaData.setRawHeaders(headers);
|
||||
metaData.setSaveToDisk(true);
|
||||
QDateTime expirationDate = QDateTime::currentDateTime().addSecs(500);
|
||||
metaData.setExpirationDate(expirationDate);
|
||||
cache->setupWithOne(tempDir.path(), url, metaData);
|
||||
|
||||
manager = new QNetworkAccessManager();
|
||||
manager->setCache(cache);
|
||||
|
||||
QNetworkRequest request(url);
|
||||
request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
|
||||
QNetworkReply *reply = manager->get(request);
|
||||
connect(reply, SIGNAL(metaDataChanged()), this, SLOT(setCookieHeaderMetaDataChangedSlot()));
|
||||
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
|
||||
|
||||
QTestEventLoop::instance().enterLoop(5);
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
|
||||
QCOMPARE(reply->error(), QNetworkReply::NoError);
|
||||
|
||||
reply->deleteLater();
|
||||
manager->deleteLater();
|
||||
}
|
||||
|
||||
void tst_QNetworkDiskCache::setCookieHeaderMetaDataChangedSlot()
|
||||
{
|
||||
QList<QNetworkCookie> actualCookieJar = manager->cookieJar()->cookiesForUrl(url);
|
||||
QVERIFY(!actualCookieJar.empty());
|
||||
}
|
||||
|
||||
void tst_QNetworkDiskCache::setCacheDirectory_data()
|
||||
{
|
||||
QTest::addColumn<QString>("cacheDir");
|
||||
QTest::newRow("null") << QString();
|
||||
QDir dir("foo");
|
||||
QTest::newRow("foo") << dir.absolutePath() + QString("/");
|
||||
}
|
||||
|
||||
// public void setCacheDirectory(QString const& cacheDir)
|
||||
void tst_QNetworkDiskCache::setCacheDirectory()
|
||||
{
|
||||
QFETCH(QString, cacheDir);
|
||||
|
||||
SubQNetworkDiskCache cache;
|
||||
cache.setCacheDirectory(cacheDir);
|
||||
QCOMPARE(cache.cacheDirectory(), cacheDir);
|
||||
}
|
||||
|
||||
// public void updateMetaData(QNetworkCacheMetaData const& metaData)
|
||||
void tst_QNetworkDiskCache::updateMetaData()
|
||||
{
|
||||
QUrl url(EXAMPLE_URL);
|
||||
SubQNetworkDiskCache cache;
|
||||
cache.setupWithOne(tempDir.path(), url);
|
||||
|
||||
QNetworkCacheMetaData metaData = cache.metaData(url);
|
||||
metaData.setLastModified(QDateTime::currentDateTime());
|
||||
cache.updateMetaData(metaData);
|
||||
QNetworkCacheMetaData newMetaData = cache.metaData(url);
|
||||
QCOMPARE(newMetaData, metaData);
|
||||
}
|
||||
|
||||
// protected QNetworkCacheMetaData fileMetaData(QString const& fileName)
|
||||
void tst_QNetworkDiskCache::fileMetaData()
|
||||
{
|
||||
SubQNetworkDiskCache cache;
|
||||
QUrl url(EXAMPLE_URL);
|
||||
cache.setupWithOne(tempDir.path(), url);
|
||||
|
||||
url.setPassword(QString());
|
||||
url.setFragment(QString());
|
||||
|
||||
QString cacheDirectory = cache.cacheDirectory();
|
||||
QStringList list = countFiles(cacheDirectory);
|
||||
QCOMPARE(list.size(), NUM_SUBDIRECTORIES + 3);
|
||||
foreach(QString fileName, list) {
|
||||
QFileInfo info(fileName);
|
||||
if (info.isFile()) {
|
||||
QNetworkCacheMetaData metaData = cache.call_fileMetaData(fileName);
|
||||
QCOMPARE(metaData.url(), url);
|
||||
}
|
||||
}
|
||||
|
||||
QTemporaryFile file(cacheDirectory + "/qt_temp.XXXXXX");
|
||||
if (file.open()) {
|
||||
QNetworkCacheMetaData metaData = cache.call_fileMetaData(file.fileName());
|
||||
QVERIFY(!metaData.isValid());
|
||||
}
|
||||
}
|
||||
|
||||
// protected qint64 expire()
|
||||
void tst_QNetworkDiskCache::expire()
|
||||
{
|
||||
SubQNetworkDiskCache cache;
|
||||
cache.setCacheDirectory(tempDir.path());
|
||||
QCOMPARE(cache.call_expire(), (qint64)0);
|
||||
QUrl url(EXAMPLE_URL);
|
||||
cache.setupWithOne(tempDir.path(), url);
|
||||
QVERIFY(cache.call_expire() > (qint64)0);
|
||||
qint64 limit = (1024 * 1024 / 4) * 5;
|
||||
cache.setMaximumCacheSize(limit);
|
||||
|
||||
qint64 max = cache.maximumCacheSize();
|
||||
QCOMPARE(max, limit);
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
if (i % 3 == 0)
|
||||
QTest::qWait(2000);
|
||||
QNetworkCacheMetaData m;
|
||||
m.setUrl(QUrl("http://localhost:4/" + QString::number(i)));
|
||||
QIODevice *d = cache.prepare(m);
|
||||
QString bigString;
|
||||
bigString.fill(QLatin1Char('Z'), (1024 * 1024 / 4));
|
||||
d->write(bigString.toLatin1().data());
|
||||
cache.insert(d);
|
||||
QVERIFY(cache.call_expire() < max);
|
||||
}
|
||||
|
||||
QString cacheDirectory = cache.cacheDirectory();
|
||||
QStringList list = countFiles(cacheDirectory);
|
||||
QStringList cacheList;
|
||||
foreach(QString fileName, list) {
|
||||
QFileInfo info(fileName);
|
||||
if (info.isFile()) {
|
||||
QNetworkCacheMetaData metaData = cache.call_fileMetaData(fileName);
|
||||
cacheList.append(metaData.url().toString());
|
||||
}
|
||||
}
|
||||
std::sort(cacheList.begin(), cacheList.end());
|
||||
for (int i = 0; i < cacheList.size(); ++i) {
|
||||
QString fileName = cacheList[i];
|
||||
QCOMPARE(fileName, QLatin1String("http://localhost:4/") + QString::number(i + 6));
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QNetworkDiskCache::oldCacheVersionFile_data()
|
||||
{
|
||||
QTest::addColumn<int>("pass");
|
||||
QTest::newRow("0") << 0;
|
||||
QTest::newRow("1") << 1;
|
||||
}
|
||||
|
||||
void tst_QNetworkDiskCache::oldCacheVersionFile()
|
||||
{
|
||||
QFETCH(int, pass);
|
||||
SubQNetworkDiskCache cache;
|
||||
QUrl url(EXAMPLE_URL);
|
||||
cache.setupWithOne(tempDir.path(), url);
|
||||
|
||||
if (pass == 0) {
|
||||
QString name;
|
||||
{
|
||||
QTemporaryFile file(cache.cacheDirectory() + "/XXXXXX.d");
|
||||
file.setAutoRemove(false);
|
||||
QVERIFY2(file.open(), qPrintable(file.errorString()));
|
||||
QDataStream out(&file);
|
||||
out << qint32(0xe8);
|
||||
out << qint32(2);
|
||||
name = file.fileName();
|
||||
file.close();
|
||||
}
|
||||
|
||||
QVERIFY(QFile::exists(name));
|
||||
QNetworkCacheMetaData metaData = cache.call_fileMetaData(name);
|
||||
QVERIFY(!metaData.isValid());
|
||||
QVERIFY(!QFile::exists(name));
|
||||
} else {
|
||||
QStringList files = countFiles(cache.cacheDirectory());
|
||||
QCOMPARE(files.size(), NUM_SUBDIRECTORIES + 3);
|
||||
// find the file
|
||||
QString cacheFile;
|
||||
foreach (QString file, files) {
|
||||
QFileInfo info(file);
|
||||
if (info.isFile())
|
||||
cacheFile = file;
|
||||
}
|
||||
QVERIFY(QFile::exists(cacheFile));
|
||||
|
||||
QFile file(cacheFile);
|
||||
QVERIFY(file.open(QFile::ReadWrite));
|
||||
QDataStream out(&file);
|
||||
out << qint32(0xe8);
|
||||
out << qint32(2);
|
||||
file.close();
|
||||
|
||||
QIODevice *device = cache.data(url);
|
||||
QVERIFY(!device);
|
||||
QVERIFY(!QFile::exists(cacheFile));
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QNetworkDiskCache::streamVersion_data()
|
||||
{
|
||||
QTest::addColumn<int>("version");
|
||||
QTest::newRow("Qt 5.1") << int(QDataStream::Qt_5_1);
|
||||
QDataStream ds;
|
||||
QTest::newRow("current") << ds.version();
|
||||
QTest::newRow("higher than current") << ds.version() + 1;
|
||||
}
|
||||
|
||||
void tst_QNetworkDiskCache::streamVersion()
|
||||
{
|
||||
SubQNetworkDiskCache cache;
|
||||
QUrl url(EXAMPLE_URL);
|
||||
cache.setupWithOne(tempDir.path(), url);
|
||||
|
||||
QString cacheFile;
|
||||
// find the file
|
||||
QStringList files = countFiles(cache.cacheDirectory());
|
||||
foreach (const QString &file, files) {
|
||||
QFileInfo info(file);
|
||||
if (info.isFile()) {
|
||||
cacheFile = file;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QFile file(cacheFile);
|
||||
QVERIFY(file.open(QFile::ReadWrite|QIODevice::Truncate));
|
||||
QDataStream out(&file);
|
||||
QFETCH(int, version);
|
||||
if (version < out.version())
|
||||
out.setVersion(version);
|
||||
out << qint32(0xe8); // cache magic
|
||||
// Following code works only for cache file version 8 and should be updated on version change
|
||||
out << qint32(8);
|
||||
out << qint32(version);
|
||||
|
||||
QNetworkCacheMetaData md;
|
||||
md.setUrl(url);
|
||||
QNetworkCacheMetaData::RawHeader header("content-type", "text/html");
|
||||
QNetworkCacheMetaData::RawHeaderList list;
|
||||
list.append(header);
|
||||
md.setRawHeaders(list);
|
||||
md.setLastModified(QDateTime::currentDateTimeUtc().toOffsetFromUtc(3600));
|
||||
out << md;
|
||||
|
||||
bool compressed = true;
|
||||
out << compressed;
|
||||
|
||||
QByteArray data("Hello World!");
|
||||
out << qCompress(data);
|
||||
|
||||
file.close();
|
||||
|
||||
QNetworkCacheMetaData cachedMetaData = cache.call_fileMetaData(cacheFile);
|
||||
if (version > out.version()) {
|
||||
QVERIFY(!cachedMetaData.isValid());
|
||||
QVERIFY(!QFile::exists(cacheFile));
|
||||
} else {
|
||||
QVERIFY(cachedMetaData.isValid());
|
||||
QVERIFY(QFile::exists(cacheFile));
|
||||
QIODevice *dataDevice = cache.data(url);
|
||||
QVERIFY(dataDevice != 0);
|
||||
QByteArray cachedData = dataDevice->readAll();
|
||||
QCOMPARE(cachedData, data);
|
||||
}
|
||||
}
|
||||
|
||||
class Runner : public QThread
|
||||
{
|
||||
|
||||
public:
|
||||
Runner(const QString& cachePath)
|
||||
: QThread()
|
||||
, other(0)
|
||||
, cachePath(cachePath)
|
||||
{}
|
||||
|
||||
void run() override
|
||||
{
|
||||
QByteArray longString = "Hello World, this is some long string, well not really that long";
|
||||
for (int j = 0; j < 10; ++j)
|
||||
longString += longString;
|
||||
QByteArray longString2 = "Help, I am stuck in an autotest!";
|
||||
QUrl url(EXAMPLE_URL);
|
||||
|
||||
QNetworkCacheMetaData metaData;
|
||||
metaData.setUrl(url);
|
||||
QNetworkCacheMetaData::RawHeaderList headers;
|
||||
headers.append(QNetworkCacheMetaData::RawHeader("type", "bin"));
|
||||
metaData.setRawHeaders(headers);
|
||||
metaData.setLastModified(dt);
|
||||
metaData.setSaveToDisk(true);
|
||||
|
||||
QNetworkCacheMetaData metaData2 = metaData;
|
||||
metaData2.setExpirationDate(dt);
|
||||
|
||||
QNetworkDiskCache cache;
|
||||
cache.setCacheDirectory(cachePath);
|
||||
|
||||
int i = 0;
|
||||
for (; i < 5000; ++i) {
|
||||
if (other && other->isFinished())
|
||||
break;
|
||||
|
||||
if (write) {
|
||||
QNetworkCacheMetaData m;
|
||||
if (QRandomGenerator::global()->bounded(2) == 0)
|
||||
m = metaData;
|
||||
else
|
||||
m = metaData2;
|
||||
|
||||
if (QRandomGenerator::global()->bounded(20) == 1) {
|
||||
//qDebug() << "write update";
|
||||
cache.updateMetaData(m);
|
||||
continue;
|
||||
}
|
||||
|
||||
QIODevice *device = cache.prepare(m);
|
||||
if (QRandomGenerator::global()->bounded(20) == 1) {
|
||||
//qDebug() << "write remove";
|
||||
cache.remove(url);
|
||||
continue;
|
||||
}
|
||||
QVERIFY(device);
|
||||
if (QRandomGenerator::global()->bounded(2) == 0)
|
||||
device->write(longString);
|
||||
else
|
||||
device->write(longString2);
|
||||
//qDebug() << "write write" << device->size();
|
||||
cache.insert(device);
|
||||
continue;
|
||||
}
|
||||
|
||||
QNetworkCacheMetaData gotMetaData = cache.metaData(url);
|
||||
if (gotMetaData.isValid()) {
|
||||
QVERIFY(gotMetaData == metaData || gotMetaData == metaData2);
|
||||
QIODevice *d = cache.data(url);
|
||||
if (d) {
|
||||
QByteArray x = d->readAll();
|
||||
if (x != longString && x != longString2) {
|
||||
qDebug() << x.size() << QString(x);
|
||||
gotMetaData = cache.metaData(url);
|
||||
qDebug() << (gotMetaData.url().toString())
|
||||
<< gotMetaData.lastModified()
|
||||
<< gotMetaData.expirationDate()
|
||||
<< gotMetaData.saveToDisk();
|
||||
}
|
||||
if (gotMetaData.isValid())
|
||||
QVERIFY(x == longString || x == longString2);
|
||||
delete d;
|
||||
}
|
||||
}
|
||||
if (QRandomGenerator::global()->bounded(5) == 1)
|
||||
cache.remove(url);
|
||||
if (QRandomGenerator::global()->bounded(5) == 1)
|
||||
cache.clear();
|
||||
sleep(0);
|
||||
}
|
||||
}
|
||||
|
||||
QDateTime dt;
|
||||
bool write;
|
||||
Runner *other;
|
||||
QString cachePath;
|
||||
};
|
||||
|
||||
void tst_QNetworkDiskCache::crashWhenParentingCache()
|
||||
{
|
||||
// the trick here is to not send the complete response
|
||||
// but some data. So we get a readyRead() and it gets tried
|
||||
// to be saved to the cache
|
||||
QByteArray data("HTTP/1.0 200 OK\r\nCache-Control: max-age=300\r\nAge: 1\r\nContent-Length: 5\r\n\r\n123");
|
||||
MiniHttpServer server(data);
|
||||
|
||||
QNetworkAccessManager *manager = new QNetworkAccessManager();
|
||||
QNetworkDiskCache *diskCache = new QNetworkDiskCache(manager); // parent to qnam!
|
||||
// we expect the temp dir to be cleaned at some point anyway
|
||||
|
||||
const QString diskCachePath = QDir::tempPath() + QLatin1String("/cacheDir_")
|
||||
+ QString::number(QCoreApplication::applicationPid());
|
||||
diskCache->setCacheDirectory(diskCachePath);
|
||||
manager->setCache(diskCache);
|
||||
|
||||
QUrl url("http://127.0.0.1:" + QString::number(server.serverPort()));
|
||||
QNetworkRequest request(url);
|
||||
// request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork);
|
||||
QNetworkReply *reply = manager->get(request); // new reply is parented to qnam
|
||||
|
||||
// wait for readyRead of reply!
|
||||
connect(reply, SIGNAL(readyRead()), &QTestEventLoop::instance(), SLOT(exitLoop()));
|
||||
QTestEventLoop::instance().enterLoop(5);
|
||||
QVERIFY(!QTestEventLoop::instance().timeout());
|
||||
|
||||
delete manager; // crashed before..
|
||||
}
|
||||
|
||||
void tst_QNetworkDiskCache::sync()
|
||||
{
|
||||
// This tests would be a nice to have, but is currently not supported.
|
||||
return;
|
||||
|
||||
QTime midnight(0, 0, 0);
|
||||
Runner reader(tempDir.path());
|
||||
reader.dt = QDateTime::currentDateTime();
|
||||
reader.write = false;
|
||||
|
||||
Runner writer(tempDir.path());
|
||||
writer.dt = reader.dt;
|
||||
writer.write = true;
|
||||
|
||||
writer.other = &reader;
|
||||
reader.other = &writer;
|
||||
|
||||
writer.start();
|
||||
reader.start();
|
||||
writer.wait();
|
||||
reader.wait();
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QNetworkDiskCache)
|
||||
#include "tst_qnetworkdiskcache.moc"
|
||||
|
Reference in New Issue
Block a user