summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKatja Marttila <katja.marttila@qt.io>2019-12-27 10:24:45 +0200
committerKatja Marttila <katja.marttila@qt.io>2020-03-24 14:36:03 +0200
commite97b7ef213b21669bad38ed42cbcccd663f39e1b (patch)
treeb80c738ed545db539ddaa898fe396ac5542be9fb
parent14a2502c7781a7e8036912767eea990a92dd560c (diff)
Refactor and add unit tests for metadatajob
Split long functions into smaller understandable functions, added unit tests for metadatajob. Change-Id: Ib423eab3c9ae7771fb032b99f767f96e52266ea7 Reviewed-by: Iikka Eklund <iikka.eklund@qt.io>
-rw-r--r--doc/scripting-api/packagemanagercore.qdoc12
-rw-r--r--src/libs/installer/metadatajob.cpp234
-rw-r--r--src/libs/installer/metadatajob.h9
-rw-r--r--src/libs/installer/packagemanagercore.cpp9
-rw-r--r--src/libs/installer/packagemanagercore.h1
-rw-r--r--tests/auto/installer/installer.pro3
-rw-r--r--tests/auto/installer/metadatajob/data/config.xml8
-rw-r--r--tests/auto/installer/metadatajob/data/repository/C/1.0.0-1content.7zbin0 -> 182 bytes
-rw-r--r--tests/auto/installer/metadatajob/data/repository/C/1.0.0-1content.7z.sha11
-rw-r--r--tests/auto/installer/metadatajob/data/repository/C/1.0.0-1meta.7zbin0 -> 106 bytes
-rw-r--r--tests/auto/installer/metadatajob/data/repository/Updates.xml16
-rw-r--r--tests/auto/installer/metadatajob/data/repositoryActionAdd/A/1.0.2-1content.7zbin0 -> 182 bytes
-rw-r--r--tests/auto/installer/metadatajob/data/repositoryActionAdd/A/1.0.2-1content.7z.sha11
-rw-r--r--tests/auto/installer/metadatajob/data/repositoryActionAdd/A/1.0.2-1meta.7zbin0 -> 106 bytes
-rw-r--r--tests/auto/installer/metadatajob/data/repositoryActionAdd/B/1.0.0-1content.7zbin0 -> 182 bytes
-rw-r--r--tests/auto/installer/metadatajob/data/repositoryActionAdd/B/1.0.0-1content.7z.sha11
-rw-r--r--tests/auto/installer/metadatajob/data/repositoryActionAdd/B/1.0.0-1meta.7zbin0 -> 106 bytes
-rw-r--r--tests/auto/installer/metadatajob/data/repositoryActionAdd/Updates.xml30
-rw-r--r--tests/auto/installer/metadatajob/data/repositoryActionRemove/C/1.0.0-1content.7zbin0 -> 182 bytes
-rw-r--r--tests/auto/installer/metadatajob/data/repositoryActionRemove/C/1.0.0-1content.7z.sha11
-rw-r--r--tests/auto/installer/metadatajob/data/repositoryActionRemove/C/1.0.0-1meta.7zbin0 -> 106 bytes
-rw-r--r--tests/auto/installer/metadatajob/data/repositoryActionRemove/Updates.xml19
-rw-r--r--tests/auto/installer/metadatajob/metadatajob.pro8
-rw-r--r--tests/auto/installer/metadatajob/settings.qrc8
-rw-r--r--tests/auto/installer/metadatajob/tst_metadatajob.cpp108
-rw-r--r--tools/common/repositorygen.cpp2
26 files changed, 362 insertions, 109 deletions
diff --git a/doc/scripting-api/packagemanagercore.qdoc b/doc/scripting-api/packagemanagercore.qdoc
index e8191d99e..50666d3be 100644
--- a/doc/scripting-api/packagemanagercore.qdoc
+++ b/doc/scripting-api/packagemanagercore.qdoc
@@ -682,6 +682,14 @@
*/
/*!
+ \qmlmethod void installer::setInstaller()
+
+ Forces an installer context.
+
+ \sa isInstaller, setUpdater, setUninstaller, setPackageManager
+*/
+
+/*!
\qmlmethod boolean installer::isInstaller()
Returns \c true if the application, binary, or executable is executed in
@@ -701,7 +709,7 @@
Forces an uninstaller context.
- \sa isUninstaller, setUpdater, setPackageManager
+ \sa isUninstaller, setUpdater, setPackageManager, setInstaller
*/
/*!
@@ -718,7 +726,7 @@
Forces an updater context.
- \sa isUpdater, setUninstaller, setPackageManager
+ \sa isUpdater, setUninstaller, setPackageManager, setInstaller
*/
/*!
diff --git a/src/libs/installer/metadatajob.cpp b/src/libs/installer/metadatajob.cpp
index 5fe660315..7651ee51c 100644
--- a/src/libs/installer/metadatajob.cpp
+++ b/src/libs/installer/metadatajob.cpp
@@ -600,25 +600,12 @@ MetadataJob::Status MetadataJob::parseUpdatesXml(const QList<FileTaskResult> &re
if (!el.isNull() && el.tagName() == QLatin1String("PackageUpdate")) {
const QDomNodeList c2 = el.childNodes();
QString packageName, packageVersion, packageHash;
- for (int j = 0; j < c2.count(); ++j) {
- if (c2.at(j).toElement().tagName() == scName)
- packageName = c2.at(j).toElement().text();
- else if (c2.at(j).toElement().tagName() == scVersion)
- packageVersion = (online ? c2.at(j).toElement().text() : QString());
- else if ((c2.at(j).toElement().tagName() == QLatin1String("SHA1")) && testCheckSum)
- packageHash = c2.at(j).toElement().text();
- else {
- foreach (QString meta, metaElements) {
- if (c2.at(j).toElement().tagName() == meta) {
- metaFound = true;
- break;
- }
- }
- }
- }
- const QString repoUrl = metadata.repository.url().toString();
- //If script element is not found, no need to fetch metadata
+ metaFound = parsePackageUpdate(c2, packageName, packageVersion, packageHash,
+ online, testCheckSum);
+
+ //If meta element (script, licenses, etc.) is not found, no need to fetch metadata
if (metaFound) {
+ const QString repoUrl = metadata.repository.url().toString();
addFileTaskItem(QString::fromLatin1("%1/%2/%3meta.7z").arg(repoUrl, packageName, packageVersion),
metadata.directory + QString::fromLatin1("/%1-%2-meta.7z").arg(packageName, packageVersion),
metadata, packageHash, packageName);
@@ -663,93 +650,13 @@ MetadataJob::Status MetadataJob::parseUpdatesXml(const QList<FileTaskResult> &re
// search for additional repositories that we might need to check
const QDomNode repositoryUpdate = root.firstChildElement(QLatin1String("RepositoryUpdate"));
- if (repositoryUpdate.isNull())
- continue;
-
- QHash<QString, QPair<Repository, Repository> > repositoryUpdates;
- children = repositoryUpdate.toElement().childNodes();
- for (int i = 0; i < children.count(); ++i) {
- const QDomElement el = children.at(i).toElement();
- if (!el.isNull() && el.tagName() == QLatin1String("Repository")) {
- const QString action = el.attribute(QLatin1String("action"));
- if (action == QLatin1String("add")) {
- // add a new repository to the defaults list
- Repository repository(resolveUrl(result, el.attribute(QLatin1String("url"))), true);
- repository.setUsername(el.attribute(QLatin1String("username")));
- repository.setPassword(el.attribute(QLatin1String("password")));
- repository.setDisplayName(el.attribute(QLatin1String("displayname")));
- if (ProductKeyCheck::instance()->isValidRepository(repository)) {
- repositoryUpdates.insertMulti(action, qMakePair(repository, Repository()));
- qCDebug(QInstaller::lcGeneral) << "Repository to add:"
- << repository.displayname();
- }
- } else if (action == QLatin1String("remove")) {
- // remove possible default repositories using the given server url
- Repository repository(resolveUrl(result, el.attribute(QLatin1String("url"))), true);
- repository.setDisplayName(el.attribute(QLatin1String("displayname")));
- repositoryUpdates.insertMulti(action, qMakePair(repository, Repository()));
-
- qCDebug(QInstaller::lcGeneral) << "Repository to remove:"
- << repository.displayname();
- } else if (action == QLatin1String("replace")) {
- // replace possible default repositories using the given server url
- Repository oldRepository(resolveUrl(result, el.attribute(QLatin1String("oldUrl"))), true);
- Repository newRepository(resolveUrl(result, el.attribute(QLatin1String("newUrl"))), true);
- newRepository.setUsername(el.attribute(QLatin1String("username")));
- newRepository.setPassword(el.attribute(QLatin1String("password")));
- newRepository.setDisplayName(el.attribute(QLatin1String("displayname")));
-
- if (ProductKeyCheck::instance()->isValidRepository(newRepository)) {
- // store the new repository and the one old it replaces
- repositoryUpdates.insertMulti(action, qMakePair(newRepository, oldRepository));
- qCDebug(QInstaller::lcGeneral) << "Replace repository"
- << oldRepository.displayname() << "with" << newRepository.displayname();
- }
- } else {
- qCWarning(QInstaller::lcInstallerInstallLog) << "Invalid additional repositories action set "
- "in Updates.xml fetched from" << metadata.repository.displayname()
- << "line:" << el.lineNumber();
- }
- }
- }
-
- if (!repositoryUpdates.isEmpty()) {
- Settings &s = m_core->settings();
- const QSet<Repository> temporaries = s.temporaryRepositories();
- // in case the temp repository introduced something new, we only want that temporary
- if (temporaries.contains(metadata.repository)) {
- QSet<Repository> tmpRepositories;
- typedef QPair<Repository, Repository> RepositoryPair;
-
- QList<RepositoryPair> values = repositoryUpdates.values(QLatin1String("add"));
- foreach (const RepositoryPair &value, values)
- tmpRepositories.insert(value.first);
-
- values = repositoryUpdates.values(QLatin1String("replace"));
- foreach (const RepositoryPair &value, values)
- tmpRepositories.insert(value.first);
-
- tmpRepositories = tmpRepositories.subtract(temporaries);
- if (tmpRepositories.count() > 0) {
- s.addTemporaryRepositories(tmpRepositories, true);
- QFile::remove(result.target());
- m_metaFromDefaultRepositories.clear();
- return XmlDownloadRetry;
- }
- } else if (s.updateDefaultRepositories(repositoryUpdates) == Settings::UpdatesApplied) {
- if (m_core->isMaintainer()) {
- bool gainedAdminRights = false;
- if (!m_core->directoryWritable(m_core->value(scTargetDir))) {
- m_core->gainAdminRights();
- gainedAdminRights = true;
- }
- m_core->writeMaintenanceConfigFiles();
- if (gainedAdminRights)
- m_core->dropAdminRights();
- }
- m_metaFromDefaultRepositories.clear();
- QFile::remove(result.target());
- return XmlDownloadRetry;
+ if (!repositoryUpdate.isNull()) {
+ QHash<QString, QPair<Repository, Repository> > repositoryUpdates =
+ searchAdditionalRepositories(repositoryUpdate, result, metadata);
+ if (!repositoryUpdates.isEmpty()) {
+ MetadataJob::Status status = setAdditionalRepositories(repositoryUpdates, result, metadata);
+ if (status == XmlDownloadRetry)
+ return status;
}
}
}
@@ -806,4 +713,121 @@ void MetadataJob::addFileTaskItem(const QString &source, const QString &target,
m_packages.append(item);
}
+bool MetadataJob::parsePackageUpdate(const QDomNodeList &c2, QString &packageName,
+ QString &packageVersion, QString &packageHash,
+ bool online, bool testCheckSum)
+{
+ bool metaFound = false;
+ for (int j = 0; j < c2.count(); ++j) {
+ const QDomElement element = c2.at(j).toElement();
+ if (element.tagName() == scName)
+ packageName = element.text();
+ else if (element.tagName() == scVersion)
+ packageVersion = (online ? element.text() : QString());
+ else if ((element.tagName() == QLatin1String("SHA1")) && testCheckSum)
+ packageHash = element.text();
+ else {
+ foreach (QString meta, metaElements) {
+ if (element.tagName() == meta) {
+ metaFound = true;
+ break;
+ }
+ }
+ }
+ }
+ return metaFound;
+}
+
+QHash<QString, QPair<Repository, Repository> > MetadataJob::searchAdditionalRepositories
+ (const QDomNode &repositoryUpdate, const FileTaskResult &result, const Metadata &metadata)
+{
+ QHash<QString, QPair<Repository, Repository> > repositoryUpdates;
+ const QDomNodeList children = repositoryUpdate.toElement().childNodes();
+ for (int i = 0; i < children.count(); ++i) {
+ const QDomElement el = children.at(i).toElement();
+ if (!el.isNull() && el.tagName() == QLatin1String("Repository")) {
+ const QString action = el.attribute(QLatin1String("action"));
+ if (action == QLatin1String("add")) {
+ // add a new repository to the defaults list
+ Repository repository(resolveUrl(result, el.attribute(QLatin1String("url"))), true);
+ repository.setUsername(el.attribute(QLatin1String("username")));
+ repository.setPassword(el.attribute(QLatin1String("password")));
+ repository.setDisplayName(el.attribute(QLatin1String("displayname")));
+ if (ProductKeyCheck::instance()->isValidRepository(repository)) {
+ repositoryUpdates.insertMulti(action, qMakePair(repository, Repository()));
+ qDebug() << "Repository to add:" << repository.displayname();
+ }
+ } else if (action == QLatin1String("remove")) {
+ // remove possible default repositories using the given server url
+ Repository repository(resolveUrl(result, el.attribute(QLatin1String("url"))), true);
+ repository.setDisplayName(el.attribute(QLatin1String("displayname")));
+ repositoryUpdates.insertMulti(action, qMakePair(repository, Repository()));
+
+ qDebug() << "Repository to remove:" << repository.displayname();
+ } else if (action == QLatin1String("replace")) {
+ // replace possible default repositories using the given server url
+ Repository oldRepository(resolveUrl(result, el.attribute(QLatin1String("oldUrl"))), true);
+ Repository newRepository(resolveUrl(result, el.attribute(QLatin1String("newUrl"))), true);
+ newRepository.setUsername(el.attribute(QLatin1String("username")));
+ newRepository.setPassword(el.attribute(QLatin1String("password")));
+ newRepository.setDisplayName(el.attribute(QLatin1String("displayname")));
+
+ if (ProductKeyCheck::instance()->isValidRepository(newRepository)) {
+ // store the new repository and the one old it replaces
+ repositoryUpdates.insertMulti(action, qMakePair(newRepository, oldRepository));
+ qDebug() << "Replace repository" << oldRepository.displayname() << "with"
+ << newRepository.displayname();
+ }
+ } else {
+ qDebug() << "Invalid additional repositories action set in Updates.xml fetched "
+ "from" << metadata.repository.displayname() << "line:" << el.lineNumber();
+ }
+ }
+ }
+ return repositoryUpdates;
+}
+
+MetadataJob::Status MetadataJob::setAdditionalRepositories(QHash<QString, QPair<Repository, Repository> > repositoryUpdates,
+ const FileTaskResult &result, const Metadata& metadata)
+{
+ MetadataJob::Status status = XmlDownloadSuccess;
+ Settings &s = m_core->settings();
+ const QSet<Repository> temporaries = s.temporaryRepositories();
+ // in case the temp repository introduced something new, we only want that temporary
+ if (temporaries.contains(metadata.repository)) {
+ QSet<Repository> tmpRepositories;
+ typedef QPair<Repository, Repository> RepositoryPair;
+
+ QList<RepositoryPair> values = repositoryUpdates.values(QLatin1String("add"));
+ foreach (const RepositoryPair &value, values)
+ tmpRepositories.insert(value.first);
+
+ values = repositoryUpdates.values(QLatin1String("replace"));
+ foreach (const RepositoryPair &value, values)
+ tmpRepositories.insert(value.first);
+
+ tmpRepositories = tmpRepositories.subtract(temporaries);
+ if (tmpRepositories.count() > 0) {
+ s.addTemporaryRepositories(tmpRepositories, true);
+ QFile::remove(result.target());
+ m_metaFromDefaultRepositories.clear();
+ status = XmlDownloadRetry;
+ }
+ } else if (s.updateDefaultRepositories(repositoryUpdates) == Settings::UpdatesApplied) {
+ if (m_core->isMaintainer()) {
+ bool gainedAdminRights = false;
+ if (!m_core->directoryWritable(m_core->value(scTargetDir))) {
+ m_core->gainAdminRights();
+ gainedAdminRights = true;
+ }
+ m_core->writeMaintenanceConfigFiles();
+ if (gainedAdminRights)
+ m_core->dropAdminRights();
+ }
+ m_metaFromDefaultRepositories.clear();
+ QFile::remove(result.target());
+ status = XmlDownloadRetry;
+ }
+ return status;
+}
} // namespace QInstaller
diff --git a/src/libs/installer/metadatajob.h b/src/libs/installer/metadatajob.h
index e3a7f6a44..f8f935529 100644
--- a/src/libs/installer/metadatajob.h
+++ b/src/libs/installer/metadatajob.h
@@ -36,6 +36,9 @@
#include <QFutureWatcher>
+class QDomNodeList;
+class QDomNode;
+
namespace QInstaller {
class PackageManagerCore;
@@ -101,6 +104,12 @@ private:
QSet<Repository> getRepositories();
void addFileTaskItem(const QString &source, const QString &target, const Metadata &metadata,
const QString &sha1, const QString &packageName);
+ bool parsePackageUpdate(const QDomNodeList &c2, QString &packageName, QString &packageVersion,
+ QString &packageHash, bool online, bool testCheckSum);
+ QHash<QString, QPair<Repository, Repository> > searchAdditionalRepositories(const QDomNode &repositoryUpdate,
+ const FileTaskResult &result, const Metadata &metadata);
+ MetadataJob::Status setAdditionalRepositories(QHash<QString, QPair<Repository, Repository> > repositoryUpdates,
+ const FileTaskResult &result, const Metadata& metadata);
private:
PackageManagerCore *m_core;
diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp
index 085de5049..8d3754f8a 100644
--- a/src/libs/installer/packagemanagercore.cpp
+++ b/src/libs/installer/packagemanagercore.cpp
@@ -2922,6 +2922,15 @@ QString PackageManagerCore::installerBinaryPath() const
}
/*!
+ \sa {installer::setInstaller}{installer.setInstaller}
+ \sa isInstaller(), setUpdater(), setPackageManager()
+*/
+void PackageManagerCore::setInstaller()
+{
+ d->m_magicBinaryMarker = BinaryContent::MagicInstallerMarker;
+}
+
+/*!
Returns \c true if running as installer.
\sa {installer::isInstaller}{installer.isInstaller}
diff --git a/src/libs/installer/packagemanagercore.h b/src/libs/installer/packagemanagercore.h
index 75bdfb863..6c32fcb29 100644
--- a/src/libs/installer/packagemanagercore.h
+++ b/src/libs/installer/packagemanagercore.h
@@ -223,6 +223,7 @@ public:
bool uninstallComponentsSilently(const QStringList& components);
// convenience
+ Q_INVOKABLE void setInstaller();
Q_INVOKABLE bool isInstaller() const;
Q_INVOKABLE bool isOfflineOnly() const;
diff --git a/tests/auto/installer/installer.pro b/tests/auto/installer/installer.pro
index 8528f599a..6803c7a07 100644
--- a/tests/auto/installer/installer.pro
+++ b/tests/auto/installer/installer.pro
@@ -25,7 +25,8 @@ SUBDIRS += \
factory \
replaceoperation \
brokeninstaller \
- cliinterface
+ cliinterface \
+ metadatajob
win32 {
SUBDIRS += registerfiletypeoperation
diff --git a/tests/auto/installer/metadatajob/data/config.xml b/tests/auto/installer/metadatajob/data/config.xml
new file mode 100644
index 000000000..041ce5062
--- /dev/null
+++ b/tests/auto/installer/metadatajob/data/config.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Installer>
+ <Name>Your application</Name>
+ <Version>1.2.3</Version>
+ <MaintenanceToolName></MaintenanceToolName>
+ <MaintenanceToolIniFile></MaintenanceToolIniFile>
+ <TargetConfigurationFile></TargetConfigurationFile>
+</Installer>
diff --git a/tests/auto/installer/metadatajob/data/repository/C/1.0.0-1content.7z b/tests/auto/installer/metadatajob/data/repository/C/1.0.0-1content.7z
new file mode 100644
index 000000000..7d03dca9c
--- /dev/null
+++ b/tests/auto/installer/metadatajob/data/repository/C/1.0.0-1content.7z
Binary files differ
diff --git a/tests/auto/installer/metadatajob/data/repository/C/1.0.0-1content.7z.sha1 b/tests/auto/installer/metadatajob/data/repository/C/1.0.0-1content.7z.sha1
new file mode 100644
index 000000000..91ead97f0
--- /dev/null
+++ b/tests/auto/installer/metadatajob/data/repository/C/1.0.0-1content.7z.sha1
@@ -0,0 +1 @@
+c8b7076fabaaf6b9d27f27350c577118c24f426b \ No newline at end of file
diff --git a/tests/auto/installer/metadatajob/data/repository/C/1.0.0-1meta.7z b/tests/auto/installer/metadatajob/data/repository/C/1.0.0-1meta.7z
new file mode 100644
index 000000000..46bae0179
--- /dev/null
+++ b/tests/auto/installer/metadatajob/data/repository/C/1.0.0-1meta.7z
Binary files differ
diff --git a/tests/auto/installer/metadatajob/data/repository/Updates.xml b/tests/auto/installer/metadatajob/data/repository/Updates.xml
new file mode 100644
index 000000000..17d89cda7
--- /dev/null
+++ b/tests/auto/installer/metadatajob/data/repository/Updates.xml
@@ -0,0 +1,16 @@
+<Updates>
+ <ApplicationName>{AnyApplication}</ApplicationName>
+ <ApplicationVersion>1.0.0</ApplicationVersion>
+ <Checksum>true</Checksum>
+ <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/metadatajob/data/repositoryActionAdd/A/1.0.2-1content.7z b/tests/auto/installer/metadatajob/data/repositoryActionAdd/A/1.0.2-1content.7z
new file mode 100644
index 000000000..5a9383e7e
--- /dev/null
+++ b/tests/auto/installer/metadatajob/data/repositoryActionAdd/A/1.0.2-1content.7z
Binary files differ
diff --git a/tests/auto/installer/metadatajob/data/repositoryActionAdd/A/1.0.2-1content.7z.sha1 b/tests/auto/installer/metadatajob/data/repositoryActionAdd/A/1.0.2-1content.7z.sha1
new file mode 100644
index 000000000..fd0bc548c
--- /dev/null
+++ b/tests/auto/installer/metadatajob/data/repositoryActionAdd/A/1.0.2-1content.7z.sha1
@@ -0,0 +1 @@
+643cb71b2337d5a49d57a5bc3c636ee9b84c0802 \ No newline at end of file
diff --git a/tests/auto/installer/metadatajob/data/repositoryActionAdd/A/1.0.2-1meta.7z b/tests/auto/installer/metadatajob/data/repositoryActionAdd/A/1.0.2-1meta.7z
new file mode 100644
index 000000000..6ef0b7959
--- /dev/null
+++ b/tests/auto/installer/metadatajob/data/repositoryActionAdd/A/1.0.2-1meta.7z
Binary files differ
diff --git a/tests/auto/installer/metadatajob/data/repositoryActionAdd/B/1.0.0-1content.7z b/tests/auto/installer/metadatajob/data/repositoryActionAdd/B/1.0.0-1content.7z
new file mode 100644
index 000000000..dfe41ad15
--- /dev/null
+++ b/tests/auto/installer/metadatajob/data/repositoryActionAdd/B/1.0.0-1content.7z
Binary files differ
diff --git a/tests/auto/installer/metadatajob/data/repositoryActionAdd/B/1.0.0-1content.7z.sha1 b/tests/auto/installer/metadatajob/data/repositoryActionAdd/B/1.0.0-1content.7z.sha1
new file mode 100644
index 000000000..50a632b49
--- /dev/null
+++ b/tests/auto/installer/metadatajob/data/repositoryActionAdd/B/1.0.0-1content.7z.sha1
@@ -0,0 +1 @@
+c7b9ab370efe036171dda7b71cd95021747cb101 \ No newline at end of file
diff --git a/tests/auto/installer/metadatajob/data/repositoryActionAdd/B/1.0.0-1meta.7z b/tests/auto/installer/metadatajob/data/repositoryActionAdd/B/1.0.0-1meta.7z
new file mode 100644
index 000000000..12d54f94c
--- /dev/null
+++ b/tests/auto/installer/metadatajob/data/repositoryActionAdd/B/1.0.0-1meta.7z
Binary files differ
diff --git a/tests/auto/installer/metadatajob/data/repositoryActionAdd/Updates.xml b/tests/auto/installer/metadatajob/data/repositoryActionAdd/Updates.xml
new file mode 100644
index 000000000..da842bdf7
--- /dev/null
+++ b/tests/auto/installer/metadatajob/data/repositoryActionAdd/Updates.xml
@@ -0,0 +1,30 @@
+<Updates>
+ <ApplicationName>{AnyApplication}</ApplicationName>
+ <ApplicationVersion>1.0.0</ApplicationVersion>
+ <Checksum>true</Checksum>
+ <RepositoryUpdate>
+ <Repository action="add" url="../repository" displayname="Example repository"/>
+ </RepositoryUpdate>
+ <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>
+ <UpdateFile CompressedSize="222" OS="Any" UncompressedSize="72"/>
+ <DownloadableArchives>content.7z</DownloadableArchives>
+ <SHA1>9d54e3a5adf3563913feee8ba23a99fb80d46590</SHA1>
+ </PackageUpdate>
+ <PackageUpdate>
+ <Name>B</Name>
+ <DisplayName>B</DisplayName>
+ <Description>Example component B</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>9170d55a6af81c1a6a63d708a4ab6ed359775cd9</SHA1>
+ </PackageUpdate>
+</Updates>
diff --git a/tests/auto/installer/metadatajob/data/repositoryActionRemove/C/1.0.0-1content.7z b/tests/auto/installer/metadatajob/data/repositoryActionRemove/C/1.0.0-1content.7z
new file mode 100644
index 000000000..7d03dca9c
--- /dev/null
+++ b/tests/auto/installer/metadatajob/data/repositoryActionRemove/C/1.0.0-1content.7z
Binary files differ
diff --git a/tests/auto/installer/metadatajob/data/repositoryActionRemove/C/1.0.0-1content.7z.sha1 b/tests/auto/installer/metadatajob/data/repositoryActionRemove/C/1.0.0-1content.7z.sha1
new file mode 100644
index 000000000..91ead97f0
--- /dev/null
+++ b/tests/auto/installer/metadatajob/data/repositoryActionRemove/C/1.0.0-1content.7z.sha1
@@ -0,0 +1 @@
+c8b7076fabaaf6b9d27f27350c577118c24f426b \ No newline at end of file
diff --git a/tests/auto/installer/metadatajob/data/repositoryActionRemove/C/1.0.0-1meta.7z b/tests/auto/installer/metadatajob/data/repositoryActionRemove/C/1.0.0-1meta.7z
new file mode 100644
index 000000000..46bae0179
--- /dev/null
+++ b/tests/auto/installer/metadatajob/data/repositoryActionRemove/C/1.0.0-1meta.7z
Binary files differ
diff --git a/tests/auto/installer/metadatajob/data/repositoryActionRemove/Updates.xml b/tests/auto/installer/metadatajob/data/repositoryActionRemove/Updates.xml
new file mode 100644
index 000000000..b0b30c9d4
--- /dev/null
+++ b/tests/auto/installer/metadatajob/data/repositoryActionRemove/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/metadatajob/metadatajob.pro b/tests/auto/installer/metadatajob/metadatajob.pro
new file mode 100644
index 000000000..2e4b5d2f1
--- /dev/null
+++ b/tests/auto/installer/metadatajob/metadatajob.pro
@@ -0,0 +1,8 @@
+include(../../qttest.pri)
+
+QT += qml
+
+SOURCES += tst_metadatajob.cpp
+
+RESOURCES += \
+ settings.qrc
diff --git a/tests/auto/installer/metadatajob/settings.qrc b/tests/auto/installer/metadatajob/settings.qrc
new file mode 100644
index 000000000..c881f294b
--- /dev/null
+++ b/tests/auto/installer/metadatajob/settings.qrc
@@ -0,0 +1,8 @@
+<RCC>
+ <qresource prefix="/">
+ <file>data/config.xml</file>
+ <file>data/repository/Updates.xml</file>
+ <file>data/repositoryActionAdd/Updates.xml</file>
+ <file>data/repositoryActionRemove/Updates.xml</file>
+ </qresource>
+</RCC>
diff --git a/tests/auto/installer/metadatajob/tst_metadatajob.cpp b/tests/auto/installer/metadatajob/tst_metadatajob.cpp
new file mode 100644
index 000000000..ef7b42940
--- /dev/null
+++ b/tests/auto/installer/metadatajob/tst_metadatajob.cpp
@@ -0,0 +1,108 @@
+/**************************************************************************
+**
+** Copyright (C) 2020 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 "metadatajob.h"
+#include "settings.h"
+
+#include <binarycontent.h>
+#include <component.h>
+#include <errors.h>
+#include <fileutils.h>
+#include <packagemanagercore.h>
+#include <progresscoordinator.h>
+
+#include <QTest>
+
+using namespace QInstaller;
+
+class tst_MetaDataJob : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void testRepository()
+ {
+ Settings settings = Settings::fromFileAndPrefix(":///data/config.xml", ":///data");
+ PackageManagerCore core;
+ core.setInstaller();
+ QSet<Repository> repoList;
+ Repository repo = Repository::fromUserInput(":///data/repository");
+ repoList.insert(repo);
+ core.settings().setDefaultRepositories(repoList);
+ MetadataJob metadata;
+ metadata.setPackageManagerCore(&core);
+ metadata.start();
+ metadata.waitForFinished();
+ QCOMPARE(metadata.metadata().count(), 1);
+ }
+
+ void testRepositoryUpdateActionAdd()
+ {
+ Settings settings = Settings::fromFileAndPrefix(":///data/config.xml", ":///data");
+ PackageManagerCore core;
+ core.setInstaller();
+ QSet<Repository> repoList;
+ Repository repo = Repository::fromUserInput(":///data/repositoryActionAdd");
+ repoList.insert(repo);
+ core.settings().setDefaultRepositories(repoList);
+ MetadataJob metadata;
+ metadata.setPackageManagerCore(&core);
+
+ QTest::ignoreMessage(QtDebugMsg, "Repository to add: \"Example repository\"");
+ QTest::ignoreMessage(QtDebugMsg, "Repository to add: \"Example repository\"");
+ metadata.start();
+ metadata.waitForFinished();
+ QCOMPARE(metadata.metadata().count(), 2);
+ }
+
+ void testRepositoryUpdateActionRemove()
+ {
+ Settings settings = Settings::fromFileAndPrefix(":///data/config.xml", ":///data");
+ PackageManagerCore core;
+ core.setInstaller();
+ QSet<Repository> repoList;
+ Repository repo = Repository::fromUserInput(":///data/repositoryActionRemove");
+ Repository repo2 = Repository::fromUserInput(":///data/repository");
+ repoList.insert(repo);
+ repoList.insert(repo2);
+ core.settings().setDefaultRepositories(repoList);
+ MetadataJob metadata;
+ metadata.setPackageManagerCore(&core);
+
+ QTest::ignoreMessage(QtDebugMsg, "Repository to remove: \"file::///data/repository\"");
+ QTest::ignoreMessage(QtDebugMsg, "Repository to remove: \"file::///data/repository\"");
+ metadata.start();
+ metadata.waitForFinished();
+ QCOMPARE(metadata.metadata().count(), 1);
+ }
+};
+
+
+QTEST_MAIN(tst_MetaDataJob)
+
+#include "tst_metadatajob.moc"
diff --git a/tools/common/repositorygen.cpp b/tools/common/repositorygen.cpp
index d47189764..85d33845a 100644
--- a/tools/common/repositorygen.cpp
+++ b/tools/common/repositorygen.cpp
@@ -684,7 +684,7 @@ void QInstallerTools::compressMetaDirectories(const QString &repoDir, const QStr
continue;
const QString absPath = sd.absolutePath();
const QString fn = QLatin1String(versionPrefix.toLatin1() + "meta.7z");
- const QString tmpTarget = repoDir + QLatin1String("/") +fn;
+ const QString tmpTarget = repoDir + QLatin1String("/") + fn;
Lib7z::createArchive(tmpTarget, QStringList() << absPath, Lib7z::TmpFile::No);
}