1
/****************************************************************************
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the test suite of the Qt Toolkit.
8
** $QT_BEGIN_LICENSE:LGPL$
9
** Commercial License Usage
10
** Licensees holding valid commercial Qt licenses may use this file in
11
** accordance with the commercial license agreement provided with the
12
** Software or, alternatively, in accordance with the terms contained in
13
** a written agreement between you and Digia. For licensing terms and
14
** conditions see http://qt.digia.com/licensing. For further information
15
** use the contact form at http://qt.digia.com/contact-us.
17
** GNU Lesser General Public License Usage
18
** Alternatively, this file may be used under the terms of the GNU Lesser
19
** General Public License version 2.1 as published by the Free Software
20
** Foundation and appearing in the file LICENSE.LGPL included in the
21
** packaging of this file. Please review the following information to
22
** ensure the GNU Lesser General Public License version 2.1 requirements
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25
** In addition, as a special exception, Digia gives you certain additional
26
** rights. These rights are described in the Digia Qt LGPL Exception
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29
** GNU General Public License Usage
30
** Alternatively, this file may be used under the terms of the GNU
31
** General Public License version 3.0 as published by the Free Software
32
** Foundation and appearing in the file LICENSE.GPL included in the
33
** packaging of this file. Please review the following information to
34
** ensure the GNU General Public License version 3.0 requirements will be
35
** met: http://www.gnu.org/copyleft/gpl.html.
40
****************************************************************************/
42
#include <QNetworkDiskCache>
43
#include <QNetworkCacheMetaData>
46
#include <QTextStream>
48
#include <QtTest/QtTest>
50
#include <QStandardPaths>
54
enum Numbers { NumFakeCacheObjects = 200, //entries in pre-populated cache
55
NumInsertions = 100, //insertions to be timed
56
NumRemovals = 100, //removals to be timed
57
NumReadContent = 100, //meta requests to be timed
58
HugeCacheLimit = 50*1024*1024, // max size for a big cache
59
TinyCacheLimit = 1*512*1024}; // max size for a tiny cache
61
const QString fakeURLbase = "http://127.0.0.1/fake/";
62
//fake HTTP body aka payload
63
const QByteArray payload("Qt rocks!");
65
class tst_qnetworkdiskcache : public QObject
69
void injectFakeData();
71
bool isUrlCached(quint32 id);
72
void cleanRecursive(QString &path);
73
void cleanupCacheObject();
74
void initCacheObject();
76
QNetworkDiskCache *cache;
80
void cleanupTestCase();
84
void timeInsertion_data();
88
void timeRemoval_data();
91
void timeExpiration_data();
92
void timeExpiration();
96
void tst_qnetworkdiskcache::initTestCase()
102
void tst_qnetworkdiskcache::cleanupTestCase()
104
cleanupCacheObject();
105
cleanRecursive(cacheDir);
108
void tst_qnetworkdiskcache::timeInsertion_data()
110
QTest::addColumn<QString>("cacheRootDirectory");
112
QString cacheLoc = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
113
QTest::newRow("QStandardPaths Cache Location") << cacheLoc;
116
//This functions times an insert() operation.
117
//You can run it after populating the cache with
118
//fake data so that more realistic performance
119
//estimates are obtained.
120
void tst_qnetworkdiskcache::timeInsertion()
123
QFETCH(QString, cacheRootDirectory);
125
cacheDir = QString( cacheRootDirectory + QDir::separator() + "man_qndc");
127
qDebug() << "Setting cache directory to = " << d.absoluteFilePath(cacheDir);
130
cleanRecursive(cacheDir); // slow op.
133
cache->setCacheDirectory(cacheDir);
134
cache->setMaximumCacheSize(qint64(HugeCacheLimit));
137
//populate some fake data to simulate partially full cache
138
injectFakeData(); // SLOW
140
//Sanity-check that the first URL that we insert below isn't already in there.
141
QVERIFY(isUrlCached(NumFakeCacheObjects) == false);
143
// IMPORTANT: max cache size should be HugeCacheLimit, to avoid evictions below
144
//time insertion of previously-uncached URLs.
146
for (quint32 i = NumFakeCacheObjects; i < (NumFakeCacheObjects + NumInsertions); i++) {
147
//prepare metata for url
148
QNetworkCacheMetaData meta;
150
QTextStream stream(&fakeURL);
151
stream << fakeURLbase << i;
154
meta.setSaveToDisk(true);
156
//commit payload and metadata to disk
157
QIODevice *device = cache->prepare(meta);
158
device->write(payload);
159
cache->insert(device);
164
cleanupCacheObject();
165
cleanRecursive(cacheDir);
169
void tst_qnetworkdiskcache::timeRead_data()
171
QTest::addColumn<QString>("cacheRootDirectory");
173
QString cacheLoc = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
174
QTest::newRow("QStandardPaths Cache Location") << cacheLoc;
177
//Times metadata as well payload lookup
178
// i.e metaData(), rawHeaders() and data()
179
void tst_qnetworkdiskcache::timeRead()
182
QFETCH(QString, cacheRootDirectory);
184
cacheDir = QString( cacheRootDirectory + QDir::separator() + "man_qndc");
186
qDebug() << "Setting cache directory to = " << d.absoluteFilePath(cacheDir);
189
cleanRecursive(cacheDir); // slow op.
191
cache->setCacheDirectory(cacheDir);
192
cache->setMaximumCacheSize(qint64(HugeCacheLimit));
195
//populate some fake data to simulate partially full cache
198
//Entries in the cache should be > what we try to remove
199
QVERIFY(NumFakeCacheObjects > NumReadContent);
201
//time metadata lookup of previously inserted URL.
203
for (quint32 i = 0; i < NumReadContent; i++) {
205
QTextStream stream(&fakeURL);
206
stream << fakeURLbase << i;
209
QNetworkCacheMetaData qndc = cache->metaData(url);
210
QVERIFY(qndc.isValid()); // we must have read the metadata
212
QNetworkCacheMetaData::RawHeaderList raw(qndc.rawHeaders());
213
QVERIFY(raw.size()); // we must have parsed the headers from the meta
215
QIODevice *iodevice(cache->data(url));
216
QVERIFY(iodevice); //must not be NULL
223
cleanupCacheObject();
224
cleanRecursive(cacheDir);
228
void tst_qnetworkdiskcache::timeRemoval_data()
230
QTest::addColumn<QString>("cacheRootDirectory");
232
QString cacheLoc = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
233
QTest::newRow("QStandardPaths Cache Location") << cacheLoc;
236
void tst_qnetworkdiskcache::timeRemoval()
239
QFETCH(QString, cacheRootDirectory);
241
cacheDir = QString( cacheRootDirectory + QDir::separator() + "man_qndc");
243
qDebug() << "Setting cache directory to = " << d.absoluteFilePath(cacheDir);
247
cleanRecursive(cacheDir); // slow op.
248
cache->setCacheDirectory(cacheDir);
249
// Make max cache size HUGE, so that evictions don't happen below
250
cache->setMaximumCacheSize(qint64(HugeCacheLimit));
253
//populate some fake data to simulate partially full cache
256
//Sanity-check that the URL is already in there somewhere
257
QVERIFY(isUrlCached(NumRemovals-1) == true);
258
//Entries in the cache should be > what we try to remove
259
QVERIFY(NumFakeCacheObjects > NumRemovals);
261
//time removal of previously-inserted URL.
263
for (quint32 i = 0; i < NumRemovals; i++) {
265
QTextStream stream(&fakeURL);
266
stream << fakeURLbase << i;
273
cleanupCacheObject();
274
cleanRecursive(cacheDir);
278
void tst_qnetworkdiskcache::timeExpiration_data()
280
QTest::addColumn<QString>("cacheRootDirectory");
282
QString cacheLoc = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
283
QTest::newRow("QStandardPaths Cache Location") << cacheLoc;
286
void tst_qnetworkdiskcache::timeExpiration()
289
QFETCH(QString, cacheRootDirectory);
291
cacheDir = QString( cacheRootDirectory + QDir::separator() + "man_qndc");
293
qDebug() << "Setting cache directory to = " << d.absoluteFilePath(cacheDir);
297
cleanRecursive(cacheDir); // slow op.
298
cache->setCacheDirectory(cacheDir);
299
// Make max cache size HUGE, so that evictions don't happen below
300
cache->setMaximumCacheSize(qint64(HugeCacheLimit));
303
//populate some fake data to simulate partially full cache
306
//Sanity-check that the URL is already in there somewhere
307
QVERIFY(isUrlCached(NumRemovals-1) == true);
308
//Entries in the cache should be > what we try to remove
309
QVERIFY(NumFakeCacheObjects > NumRemovals);
312
//Set cache limit lower, so this force 1 round of eviction
313
cache->setMaximumCacheSize(qint64(TinyCacheLimit));
315
//time insertions of additional content, which is likely to internally cause evictions
317
for (quint32 i = NumFakeCacheObjects; i < (NumFakeCacheObjects + NumInsertions); i++) {
318
//prepare metata for url
319
QNetworkCacheMetaData meta;
321
QTextStream stream(&fakeURL);
322
stream << fakeURLbase << i;//codescanner::leave
325
meta.setSaveToDisk(true);
327
//commit payload and metadata to disk
328
QIODevice *device = cache->prepare(meta);
329
device->write(payload);
330
cache->insert(device); // this should trigger evictions, if TinyCacheLimit is small enough
335
cleanupCacheObject();
336
cleanRecursive(cacheDir);
339
// This function simulates a partially or fully occupied disk cache
340
// like a normal user of a cache might encounter is real-life browsing.
341
// The point of this is to trigger degradation in file-system and media performance
342
// that occur due to the quantity and layout of data.
343
void tst_qnetworkdiskcache::injectFakeData()
346
QNetworkCacheMetaData::RawHeaderList headers;
347
headers.append(qMakePair(QByteArray("X-TestHeader"),QByteArray("HeaderValue")));
350
//Prep cache dir with fake data using QNetworkDiskCache APIs
351
for (quint32 i = 0; i < NumFakeCacheObjects; i++) {
353
//prepare metata for url
354
QNetworkCacheMetaData meta;
356
QTextStream stream(&fakeURL);
357
stream << fakeURLbase << i;
360
meta.setRawHeaders(headers);
361
meta.setSaveToDisk(true);
363
//commit payload and metadata to disk
364
QIODevice *device = cache->prepare(meta);
365
device->write(payload);
366
cache->insert(device);
372
// Checks if the fake URL #id is already cached or not.
373
bool tst_qnetworkdiskcache::isUrlCached(quint32 id)
376
QTextStream stream(&str);
377
stream << fakeURLbase << id;
379
QIODevice *iod = cache->data(url);
380
return ((iod == 0) ? false : true) ;
385
// Utility function for recursive directory cleanup.
386
void tst_qnetworkdiskcache::cleanRecursive(QString &path)
388
QDirIterator it(path, QDir::Files | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
389
while (it.hasNext()) {
391
bool err = f.remove();
395
QDirIterator it2(path, QDir::AllDirs | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
396
while (it2.hasNext()) {
397
QString s(it2.next());
403
void tst_qnetworkdiskcache::cleanupCacheObject()
409
void tst_qnetworkdiskcache::initCacheObject()
412
cache = new QNetworkDiskCache();
415
QTEST_MAIN(tst_qnetworkdiskcache)
416
#include "tst_qnetworkdiskcache.moc"