tests/auto/qnetworkdiskcache/tst_qnetworkdiskcache.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/auto/qnetworkdiskcache/tst_qnetworkdiskcache.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,610 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+#include <QtNetwork/QtNetwork>
+#include <qnetworkdiskcache.h>
+#include "../../shared/util.h"
+
+#define EXAMPLE_URL "http://user:pass@www.example.com/#foo"
+
+class tst_QNetworkDiskCache : public QObject
+{
+    Q_OBJECT
+
+public slots:
+    void initTestCase();
+    void cleanupTestCase();
+    void init();
+    void cleanup();
+
+private slots:
+    void qnetworkdiskcache_data();
+    void qnetworkdiskcache();
+
+    void prepare();
+    void cacheSize();
+    void clear();
+    void data_data();
+    void data();
+    void metaData();
+    void remove();
+    void setCacheDirectory_data();
+    void setCacheDirectory();
+    void updateMetaData();
+    void fileMetaData();
+    void expire();
+
+    void oldCacheVersionFile_data();
+    void oldCacheVersionFile();
+    
+    void sync();
+};
+
+// Subclass that exposes the protected functions.
+class SubQNetworkDiskCache : public QNetworkDiskCache
+{
+public:
+    ~SubQNetworkDiskCache()
+    {
+        if (!cacheDirectory().isEmpty())
+            clear();
+    }
+
+    QNetworkCacheMetaData call_fileMetaData(QString const &fileName)
+        { return SubQNetworkDiskCache::fileMetaData(fileName); }
+
+    qint64 call_expire()
+        { return SubQNetworkDiskCache::expire(); }
+
+    void setupWithOne(const QUrl &url, const QNetworkCacheMetaData &metaData = QNetworkCacheMetaData())
+    {
+        setCacheDirectory(QDir::tempPath() + "/diskCache");
+
+        QIODevice *d = 0;
+        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);
+    }
+};
+
+// This will be called before the first test function is executed.
+// It is only called once.
+void tst_QNetworkDiskCache::initTestCase()
+{
+    SubQNetworkDiskCache cache;
+    cache.setCacheDirectory(QDir::tempPath() + "/diskCache");
+    cache.clear();
+    QString s = QDir::tempPath() + "/diskCache/";
+    QDir dir;
+    dir.rmdir(s + "http");
+    dir.rmdir(s + "https");
+    dir.rmdir(s + "prepared");
+    dir.rmdir(s);
+}
+
+// This will be called after the last test function is executed.
+// It is only called once.
+void tst_QNetworkDiskCache::cleanupTestCase()
+{
+}
+
+// This will be called before each test function is executed.
+void tst_QNetworkDiskCache::init()
+{
+}
+
+// This will be called after every test function.
+void tst_QNetworkDiskCache::cleanup()
+{
+}
+
+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(QDir::tempPath() + "/diskCache");
+    badCache.prepare(metaData);
+}
+
+void tst_QNetworkDiskCache::prepare()
+{
+    SubQNetworkDiskCache cache;
+    cache.setCacheDirectory(QDir::tempPath() + "/diskCache");
+
+    QUrl url(EXAMPLE_URL);
+    QNetworkCacheMetaData metaData;
+    metaData.setUrl(url);
+
+    cache.prepare(metaData);
+    cache.remove(url);
+}
+
+// public qint64 cacheSize() const
+void tst_QNetworkDiskCache::cacheSize()
+{
+    SubQNetworkDiskCache cache;
+    cache.setCacheDirectory(QDir::tempPath() + "/diskCache");
+    QCOMPARE(cache.cacheSize(), qint64(0));
+
+    QUrl url(EXAMPLE_URL);
+    QNetworkCacheMetaData metaData;
+    metaData.setUrl(url);
+    QIODevice *d = cache.prepare(metaData);
+    cache.insert(d);
+    QVERIFY(cache.cacheSize() > qint64(0));
+
+    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(url);
+    QVERIFY(cache.cacheSize() > qint64(0));
+
+    QString cacheDirectory = cache.cacheDirectory();
+    QCOMPARE(countFiles(cacheDirectory).count(), 3);
+    cache.clear();
+    QCOMPARE(countFiles(cacheDirectory).count(), 2);
+
+    // don't delete files that it didn't create
+    QTemporaryFile file(cacheDirectory + "/cache_XXXXXX");
+    if (file.open()) {
+        QCOMPARE(countFiles(cacheDirectory).count(), 3);
+        cache.clear();
+        QCOMPARE(countFiles(cacheDirectory).count(), 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("null") << metaData;
+}
+
+// public QIODevice* data(QUrl const& url)
+void tst_QNetworkDiskCache::data()
+{
+#ifdef Q_OS_SYMBIAN
+    QSKIP("Due to mmap(...) bug in Open C [Temtrack DEF142242]", SkipAll);
+#endif
+    QFETCH(QNetworkCacheMetaData, data);
+    SubQNetworkDiskCache cache;
+    QUrl url(EXAMPLE_URL);
+    cache.setupWithOne(url, data);
+
+    // flush the cache
+    QTemporaryFile file(cache.cacheDirectory() + "/cache_XXXXXX.cache");
+    if (file.open()) {
+        cache.call_fileMetaData(file.fileName());
+    }
+
+    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(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(url);
+    QString cacheDirectory = cache.cacheDirectory();
+    QCOMPARE(countFiles(cacheDirectory).count(), 3);
+    cache.remove(url);
+    QCOMPARE(countFiles(cacheDirectory).count(), 2);
+}
+
+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()
+{
+#ifdef Q_OS_SYMBIAN
+    QSKIP("Due to mmap(...) bug in Open C [Temtrack DEF142242]", SkipAll);
+#endif
+    QUrl url(EXAMPLE_URL);
+    SubQNetworkDiskCache cache;
+    cache.setupWithOne(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(url);
+
+    url.setPassword(QString());
+    url.setFragment(QString());
+
+    QString cacheDirectory = cache.cacheDirectory();
+    QStringList list = countFiles(cacheDirectory);
+    QCOMPARE(list.count(), 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(QDir::tempPath() + "/diskCache");
+    QCOMPARE(cache.call_expire(), (qint64)0);
+    QUrl url(EXAMPLE_URL);
+    cache.setupWithOne(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://www.foo.com/" + 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());
+        }
+    }
+    qSort(cacheList);
+    for (int i = 0; i < cacheList.count(); ++i) {
+        QString fileName = cacheList[i];
+        QCOMPARE(fileName, QString("http://www.foo.com/%1").arg(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(url);
+
+    if (pass == 0) {
+        QString name;
+        {
+        QTemporaryFile file(cache.cacheDirectory() + "/cache_XXXXXX.cache");
+        file.setAutoRemove(false);
+        QVERIFY(file.open());
+        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.count(), 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));
+    }
+}
+
+class Runner : public QThread
+{
+
+public:
+    Runner()
+        : QThread()
+        , other(0)
+    {}
+
+    void run()
+    {
+        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(QDir::tempPath() + "/diskCache");
+
+        int read = 0;
+
+        int i = 0;
+        for (; i < 5000; ++i) {
+            if (other && other->isFinished())
+                break;
+
+            if (write) {
+                QNetworkCacheMetaData m;
+                if (qrand() % 2 == 0)
+                    m = metaData;
+                else
+                    m = metaData2;
+
+                if (qrand() % 20 == 1) {
+                    //qDebug() << "write update";
+                    cache.updateMetaData(m);
+                    continue;
+                }
+
+                QIODevice *device = cache.prepare(m);
+                if (qrand() % 20 == 1) {
+                    //qDebug() << "write remove";
+                    cache.remove(url);
+                    continue;
+                }
+                QVERIFY(device);
+                if (qrand() % 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.length() << QString(x);
+                        gotMetaData = cache.metaData(url);
+                        qDebug() << (gotMetaData.url().toString())
+                         << gotMetaData.lastModified()
+                         << gotMetaData.expirationDate()
+                         << gotMetaData.saveToDisk();
+                    }
+                    if (gotMetaData.isValid())
+                        QVERIFY(x == longString || x == longString2);
+                    read++;
+                    delete d;
+                }
+            }
+            if (qrand() % 5 == 1)
+                cache.remove(url);
+            if (qrand() % 5 == 1)
+                cache.clear();
+            sleep(0);
+        }
+        //qDebug() << "read!" << read << i;
+    }
+
+    QDateTime dt;
+    bool write;
+    Runner *other;
+};
+
+void tst_QNetworkDiskCache::sync()
+{
+    // This tests would be a nice to have, but is currently not supported.
+    return;
+
+    QTime midnight(0, 0, 0);
+    qsrand(midnight.secsTo(QTime::currentTime()));
+    Runner reader;
+    reader.dt = QDateTime::currentDateTime();
+    reader.write = false;
+
+    Runner writer;
+    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"
+