summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorArttu Tarkiainen <arttu.tarkiainen@qt.io>2022-10-12 10:01:31 +0300
committerArttu Tarkiainen <arttu.tarkiainen@qt.io>2022-10-20 09:11:17 +0300
commitc7fb5612215f1f54f1de0af3eafbb6ddaa623c08 (patch)
treede39c2662479ae62588e787e8f4f58a18f70913b /tests
parent499a7a0add7780b4af929716479a18015973a0e9 (diff)
Add auto-tests for metadata cache
Task-number: QTIFW-2621 Change-Id: Ibdc69d8f64f318505df157091438f79fe55190e8 Reviewed-by: Katja Marttila <katja.marttila@qt.io>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/installer/installer.pro3
-rw-r--r--tests/auto/installer/metadatacache/data/existing-cache/manifest.json7
-rw-r--r--tests/auto/installer/metadatacache/data/existing-cache/placeholder_sha1/Updates.xml19
-rw-r--r--tests/auto/installer/metadatacache/data/existing-cache/placeholder_sha1/repository.txt1
-rw-r--r--tests/auto/installer/metadatacache/data/local-temp-repository/A/example-license.txt1
-rw-r--r--tests/auto/installer/metadatacache/data/local-temp-repository/Updates.xml17
-rw-r--r--tests/auto/installer/metadatacache/metadatacache.pro8
-rw-r--r--tests/auto/installer/metadatacache/settings.qrc9
-rw-r--r--tests/auto/installer/metadatacache/tst_metadatacache.cpp347
9 files changed, 411 insertions, 1 deletions
diff --git a/tests/auto/installer/installer.pro b/tests/auto/installer/installer.pro
index 5d93f2132..9325e71c5 100644
--- a/tests/auto/installer/installer.pro
+++ b/tests/auto/installer/installer.pro
@@ -41,7 +41,8 @@ SUBDIRS += \
treename \
createoffline \
contentshaupdate \
- componentreplace
+ componentreplace \
+ metadatacache
CONFIG(libarchive) {
SUBDIRS += libarchivearchive
diff --git a/tests/auto/installer/metadatacache/data/existing-cache/manifest.json b/tests/auto/installer/metadatacache/data/existing-cache/manifest.json
new file mode 100644
index 000000000..0ef247e8e
--- /dev/null
+++ b/tests/auto/installer/metadatacache/data/existing-cache/manifest.json
@@ -0,0 +1,7 @@
+{
+ "items": [
+ "placeholder_sha1"
+ ],
+ "type": "Metadata",
+ "version": "1.0.0"
+}
diff --git a/tests/auto/installer/metadatacache/data/existing-cache/placeholder_sha1/Updates.xml b/tests/auto/installer/metadatacache/data/existing-cache/placeholder_sha1/Updates.xml
new file mode 100644
index 000000000..b0b30c9d4
--- /dev/null
+++ b/tests/auto/installer/metadatacache/data/existing-cache/placeholder_sha1/Updates.xml
@@ -0,0 +1,19 @@
+<Updates>
+ <ApplicationName>{AnyApplication}</ApplicationName>
+ <ApplicationVersion>1.0.0</ApplicationVersion>
+ <Checksum>true</Checksum>
+ <RepositoryUpdate>
+ <Repository action="remove" url="../repository"/>
+ </RepositoryUpdate>
+ <PackageUpdate>
+ <Name>C</Name>
+ <DisplayName>C</DisplayName>
+ <Description>Example component C</Description>
+ <Version>1.0.0-1</Version>
+ <ReleaseDate>2015-01-01</ReleaseDate>
+ <Default>true</Default>
+ <UpdateFile CompressedSize="222" OS="Any" UncompressedSize="72"/>
+ <DownloadableArchives>content.7z</DownloadableArchives>
+ <SHA1>5b3939da1af492382c68388fc796837e4c36b876</SHA1>
+ </PackageUpdate>
+</Updates>
diff --git a/tests/auto/installer/metadatacache/data/existing-cache/placeholder_sha1/repository.txt b/tests/auto/installer/metadatacache/data/existing-cache/placeholder_sha1/repository.txt
new file mode 100644
index 000000000..7224edd52
--- /dev/null
+++ b/tests/auto/installer/metadatacache/data/existing-cache/placeholder_sha1/repository.txt
@@ -0,0 +1 @@
+/example-repository
diff --git a/tests/auto/installer/metadatacache/data/local-temp-repository/A/example-license.txt b/tests/auto/installer/metadatacache/data/local-temp-repository/A/example-license.txt
new file mode 100644
index 000000000..1ffdcc8df
--- /dev/null
+++ b/tests/auto/installer/metadatacache/data/local-temp-repository/A/example-license.txt
@@ -0,0 +1 @@
+Example license file
diff --git a/tests/auto/installer/metadatacache/data/local-temp-repository/Updates.xml b/tests/auto/installer/metadatacache/data/local-temp-repository/Updates.xml
new file mode 100644
index 000000000..03e54572d
--- /dev/null
+++ b/tests/auto/installer/metadatacache/data/local-temp-repository/Updates.xml
@@ -0,0 +1,17 @@
+<Updates>
+ <ApplicationName>{AnyApplication}</ApplicationName>
+ <ApplicationVersion>1.0.0</ApplicationVersion>
+ <Checksum>false</Checksum>
+ <PackageUpdate>
+ <Name>A</Name>
+ <DisplayName>A</DisplayName>
+ <Description>Example component A</Description>
+ <Version>1.0.2-1</Version>
+ <ReleaseDate>2015-01-01</ReleaseDate>
+ <Default>true</Default>
+ <SHA1>f46c677db8bc779d70d0c72fae264a321caea6f8</SHA1>
+ <Licenses>
+ <License name="Example license" file="example-license.txt"/>
+ </Licenses>
+ </PackageUpdate>
+</Updates>
diff --git a/tests/auto/installer/metadatacache/metadatacache.pro b/tests/auto/installer/metadatacache/metadatacache.pro
new file mode 100644
index 000000000..df1542dc7
--- /dev/null
+++ b/tests/auto/installer/metadatacache/metadatacache.pro
@@ -0,0 +1,8 @@
+include(../../qttest.pri)
+
+QT += qml
+
+SOURCES += tst_metadatacache.cpp
+
+RESOURCES += \
+ settings.qrc
diff --git a/tests/auto/installer/metadatacache/settings.qrc b/tests/auto/installer/metadatacache/settings.qrc
new file mode 100644
index 000000000..96383fdcb
--- /dev/null
+++ b/tests/auto/installer/metadatacache/settings.qrc
@@ -0,0 +1,9 @@
+<RCC>
+ <qresource prefix="/">
+ <file>data/local-temp-repository/Updates.xml</file>
+ <file>data/local-temp-repository/A/example-license.txt</file>
+ <file>data/existing-cache/manifest.json</file>
+ <file>data/existing-cache/placeholder_sha1/repository.txt</file>
+ <file>data/existing-cache/placeholder_sha1/Updates.xml</file>
+ </qresource>
+</RCC>
diff --git a/tests/auto/installer/metadatacache/tst_metadatacache.cpp b/tests/auto/installer/metadatacache/tst_metadatacache.cpp
new file mode 100644
index 000000000..46e4d1dfe
--- /dev/null
+++ b/tests/auto/installer/metadatacache/tst_metadatacache.cpp
@@ -0,0 +1,347 @@
+/**************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Installer Framework.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+**************************************************************************/
+
+#include "../shared/packagemanager.h"
+
+#include <errors.h>
+#include <fileutils.h>
+#include <genericdatacache.h>
+#include <metadata.h>
+#include <repository.h>
+
+#include <QCryptographicHash>
+#include <QDir>
+#include <QFileInfo>
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QObject>
+#include <QTest>
+
+using namespace QInstaller;
+
+static const QByteArray scPlaceholderSha1("placeholder_sha1");
+
+class tst_metadatacache : public QObject
+{
+ Q_OBJECT
+
+private:
+ void copyExistingCacheFromResourceTree()
+ {
+ try {
+ QInstaller::copyDirectoryContents(":/data/existing-cache/", m_cachePath);
+
+ // We need to modify the test data here because the checksums of
+ // files may differ on Windows and Unix platforms.
+ QVERIFY(QDir().rename(m_cachePath + QDir::separator() + scPlaceholderSha1,
+ m_cachePath + QDir::separator() + m_oldMetadataItemChecksum));
+
+ QFile manifestFile(m_cachePath + QDir::separator() + "manifest.json");
+ // The file lost the write bit after copying from resource
+ QInstaller::setDefaultFilePermissions(&manifestFile, QInstaller::NonExecutable);
+ QVERIFY2(manifestFile.open(QIODevice::ReadWrite), qPrintable(manifestFile.errorString()));
+
+ const QByteArray manifestData = manifestFile.readAll();
+ QJsonDocument manifestJsonDoc(QJsonDocument::fromJson(manifestData));
+ QJsonObject docJsonObject = manifestJsonDoc.object();
+
+ QJsonArray itemsJsonArray;
+ itemsJsonArray.append(QJsonValue(QLatin1String(m_oldMetadataItemChecksum)));
+
+ docJsonObject.insert(QLatin1String("items"), itemsJsonArray);
+ manifestJsonDoc.setObject(docJsonObject);
+
+ manifestFile.seek(0);
+ QVERIFY(manifestFile.write(manifestJsonDoc.toJson()) != -1);
+
+ } catch (const Error &e) {
+ QVERIFY2(false, QString::fromLatin1("Error while copying item to path %1: %2")
+ .arg(m_cachePath, e.message()).toLatin1());
+ }
+ }
+
+ QByteArray checksumFromUpdateFile(const QString &directory)
+ {
+ QFile updateFile(directory + QDir::separator() + QLatin1String("Updates.xml"));
+ if (!updateFile.open(QIODevice::ReadOnly))
+ return QByteArray();
+
+ QCryptographicHash hash(QCryptographicHash::Sha1);
+ hash.addData(&updateFile);
+ return hash.result().toHex();
+ }
+
+private slots:
+ void init()
+ {
+ m_cachePath = generateTemporaryFileName();
+ }
+
+ void cleanup()
+ {
+ if (QFileInfo::exists(m_cachePath))
+ QInstaller::removeDirectory(m_cachePath, true);
+ }
+
+ void initTestCase()
+ {
+ m_newMetadataItemChecksum = checksumFromUpdateFile(":/data/local-temp-repository");
+ m_oldMetadataItemChecksum = checksumFromUpdateFile(":/data/existing-cache/"
+ + QLatin1String(scPlaceholderSha1));
+
+ QVERIFY(!m_newMetadataItemChecksum.isEmpty());
+ QVERIFY(!m_oldMetadataItemChecksum.isEmpty());
+
+ qInstallMessageHandler(silentTestMessageHandler);
+ }
+
+ void testRegisterItemToEmptyCache()
+ {
+ GenericDataCache<Metadata> cache(m_cachePath, "Metadata", "1.0.0");
+ Metadata *metadata = new Metadata(":/data/local-temp-repository/");
+
+ QVERIFY(cache.registerItem(metadata));
+ metadata = cache.itemByChecksum(m_newMetadataItemChecksum);
+ QVERIFY(metadata);
+ QVERIFY(metadata->isValid());
+
+ QVERIFY(cache.clear());
+ QVERIFY(!QFileInfo::exists(m_cachePath));
+ }
+
+ void testRegisterItemToExistingCache()
+ {
+ copyExistingCacheFromResourceTree();
+
+ GenericDataCache<Metadata> cache(m_cachePath, "Metadata", "1.0.0");
+ Metadata *metadata = new Metadata(":/data/local-temp-repository/");
+
+ QVERIFY(cache.registerItem(metadata));
+ metadata = cache.itemByChecksum(m_newMetadataItemChecksum);
+ QVERIFY(metadata);
+ QVERIFY(metadata->isValid());
+
+ QVERIFY(cache.clear());
+ QVERIFY(!QFileInfo::exists(m_cachePath));
+ }
+
+ void testRegisterItemFails()
+ {
+ // 1. Test fail due to invalidated cache
+ GenericDataCache<Metadata> cache;
+ Metadata *metadata = new Metadata(":/data/local-temp-repository/");
+
+ QVERIFY(!cache.registerItem(metadata));
+ QCOMPARE(cache.errorString(), "Cannot register item to invalidated cache.");
+
+ delete metadata;
+ metadata = nullptr;
+
+ // 2. Test fail due to null metadata
+ cache.setPath(m_cachePath);
+ cache.setType("Metadata");
+ cache.setVersion("1.0.0");
+ QVERIFY(cache.initialize());
+
+ QVERIFY(!cache.registerItem(metadata));
+ QCOMPARE(cache.errorString(), "Cannot register null item.");
+
+ // 3. Test fail due to invalid metadata
+ metadata = new Metadata;
+ QVERIFY(!cache.registerItem(metadata));
+ QCOMPARE(cache.errorString(), "Cannot register invalid item with checksum ");
+
+ // 4. Test fail due to duplicate metadata item
+ metadata->setPath(":/data/local-temp-repository/");
+ QVERIFY(cache.registerItem(metadata));
+ QVERIFY(cache.itemByChecksum(m_newMetadataItemChecksum)->isValid());
+ QVERIFY(!cache.registerItem(metadata));
+ QCOMPARE(cache.errorString(), QString::fromLatin1("Cannot register item with checksum "
+ "%1. An item with the same checksum already exists in cache.")
+ .arg(QString::fromLatin1(m_newMetadataItemChecksum)).toLatin1());
+
+ QVERIFY(cache.clear());
+ QVERIFY(!QFileInfo::exists(m_cachePath));
+ }
+
+ void testInitializeExistingCache()
+ {
+ copyExistingCacheFromResourceTree();
+
+ GenericDataCache<Metadata> cache(m_cachePath, "Metadata", "1.0.0");
+ Metadata *metadata = cache.itemByChecksum(m_oldMetadataItemChecksum);
+ QVERIFY(metadata);
+ QVERIFY(metadata->isValid());
+
+ QVERIFY(cache.clear());
+ QVERIFY(!QFileInfo::exists(m_cachePath));
+ }
+
+ void testInitializeForeignCache_data()
+ {
+ QTest::addColumn<QString>("type");
+ QTest::addColumn<QString>("version");
+
+ QTest::newRow("Type mismatch") << "MyCacheableType" << "1.0.0";
+ QTest::newRow("Version mismatch") << "Metadata" << "0.9.1";
+ }
+
+ void testInitializeForeignCache()
+ {
+ QFETCH(QString, type);
+ QFETCH(QString, version);
+
+ copyExistingCacheFromResourceTree();
+
+ GenericDataCache<Metadata> cache(m_cachePath, type, version);
+ QVERIFY(cache.isValid());
+ QVERIFY(!cache.itemByChecksum(m_oldMetadataItemChecksum));
+
+ QVERIFY(cache.clear());
+ // The 'foreign' entry prevents removing the directory
+ QVERIFY(QFileInfo::exists(m_cachePath));
+ }
+
+ void testInitializeCacheFails()
+ {
+ GenericDataCache<Metadata> cache;
+ QVERIFY(!cache.initialize());
+ QCOMPARE(cache.errorString(), "Cannot initialize cache with empty path.");
+ }
+
+ void testRemoveItemFromCache()
+ {
+ copyExistingCacheFromResourceTree();
+
+ GenericDataCache<Metadata> cache(m_cachePath, "Metadata", "1.0.0");
+ Metadata *metadata = cache.itemByChecksum(m_oldMetadataItemChecksum);
+ QVERIFY(metadata);
+ QVERIFY(metadata->isValid());
+ QVERIFY(cache.removeItem(m_oldMetadataItemChecksum));
+
+ QVERIFY(cache.clear());
+ QVERIFY(!QFileInfo::exists(m_cachePath));
+ }
+
+ void testRemoveItemFails()
+ {
+ copyExistingCacheFromResourceTree();
+
+ GenericDataCache<Metadata> cache(m_cachePath, "Metadata", "1.0.0");
+ QVERIFY(!cache.removeItem("12345"));
+ QCOMPARE(cache.errorString(), "Cannot remove item specified by checksum 12345: no such item exists.");
+
+ QVERIFY(cache.clear());
+ QVERIFY(!QFileInfo::exists(m_cachePath));
+ }
+
+ void testRetrieveItemFromCache()
+ {
+ GenericDataCache<Metadata> cache(m_cachePath, "Metadata", "1.0.0");
+ Metadata *metadata = new Metadata(":/data/local-temp-repository/");
+
+ QVERIFY(cache.registerItem(metadata));
+ metadata = cache.itemByChecksum(m_newMetadataItemChecksum);
+ QVERIFY(metadata);
+ QVERIFY(metadata->isValid());
+
+ metadata = cache.itemByPath(metadata->path());
+ QVERIFY(metadata);
+ QVERIFY(metadata->isValid());
+
+ QVERIFY(cache.clear());
+ QVERIFY(!QFileInfo::exists(m_cachePath));
+ }
+
+ void testRetrieveItemFails()
+ {
+ GenericDataCache<Metadata> cache(m_cachePath, "Metadata", "1.0.0");
+ Metadata *metadata = new Metadata(":/data/local-temp-repository/");
+ const QString metadataPath = metadata->path();
+
+ QVERIFY(cache.registerItem(metadata));
+ QVERIFY(cache.clear());
+
+ QVERIFY(!cache.itemByChecksum(m_newMetadataItemChecksum));
+ QVERIFY(!cache.itemByPath(metadataPath));
+ QCOMPARE(cache.errorString(), "Cannot retrieve item from invalidated cache.");
+
+ QVERIFY(!QFileInfo::exists(m_cachePath));
+ }
+
+ void testItemObsoletesOther()
+ {
+ copyExistingCacheFromResourceTree();
+
+ GenericDataCache<Metadata> cache(m_cachePath, "Metadata", "1.0.0");
+ Metadata *metadata = new Metadata(":/data/local-temp-repository/");
+
+ QVERIFY(cache.registerItem(metadata));
+ metadata->setRepository(Repository(QUrl("file:///example-repository"), true));
+ metadata->setPersistentRepositoryPath(QUrl("file:///example-repository"));
+ QVERIFY(metadata->isActive());
+
+ metadata = cache.itemByChecksum(m_newMetadataItemChecksum);
+ QVERIFY(metadata);
+ QVERIFY(metadata->isValid());
+
+ metadata = cache.itemByChecksum(m_oldMetadataItemChecksum);
+ QVERIFY(metadata);
+ QVERIFY(metadata->isValid());
+
+ Metadata *obsolete = cache.obsoleteItems().first();
+ QVERIFY(!obsolete->isActive());
+ QCOMPARE(obsolete->checksum(), m_oldMetadataItemChecksum);
+
+ QVERIFY(cache.clear());
+ QVERIFY(!QFileInfo::exists(m_cachePath));
+ }
+
+ void testClearCacheFails()
+ {
+ GenericDataCache<Metadata> cache(m_cachePath, "Metadata", "1.0.0");
+ Metadata *metadata = new Metadata(":/data/local-temp-repository/");
+
+ QVERIFY(cache.registerItem(metadata));
+ QVERIFY(cache.clear());
+ QVERIFY(!cache.clear());
+ QCOMPARE(cache.errorString(), "Cannot clear invalidated cache.");
+
+ QVERIFY(!QFileInfo::exists(m_cachePath));
+ }
+
+private:
+ QString m_cachePath;
+ QByteArray m_newMetadataItemChecksum;
+ QByteArray m_oldMetadataItemChecksum;
+};
+
+QTEST_MAIN(tst_metadatacache)
+
+#include "tst_metadatacache.moc"