diff options
author | Katja Marttila <katja.marttila@qt.io> | 2018-02-28 09:54:22 +0200 |
---|---|---|
committer | Katja Marttila <katja.marttila@qt.io> | 2018-04-05 06:54:21 +0000 |
commit | d2ae9c16c3427c272d41e9a471f705ad8947a97a (patch) | |
tree | 4ed6b3cafd28b11f02ef4f4faa6164bcfbd85b63 /tests | |
parent | 6664ca85f09d6ae195ac30f83a60d53c2355da0f (diff) |
Add attribute to mark parts of install tree unstable
This commit adds new AllowUnstableComponents configuration. Setting
AllowUnstablecomponents to true in config.xml will
* allow installing other components when there are errors in scripts
* allow installing other components when there are missing dependencies
* will mark the 'broken' components uninstallable in treeview
Task-number: QTIFW-930
Change-Id: I8d28cf9c4b0401e0bb76795e87d581f39b64f128
Reviewed-by: Iikka Eklund <iikka.eklund@qt.io>
Diffstat (limited to 'tests')
5 files changed, 436 insertions, 0 deletions
diff --git a/tests/auto/installer/brokeninstaller/brokeninstaller.pro b/tests/auto/installer/brokeninstaller/brokeninstaller.pro new file mode 100644 index 000000000..e48733ac6 --- /dev/null +++ b/tests/auto/installer/brokeninstaller/brokeninstaller.pro @@ -0,0 +1,8 @@ +include(../../qttest.pri) + +QT -= gui +QT += network xml qml + +SOURCES += tst_brokeninstaller.cpp + +RESOURCES += components.qrc diff --git a/tests/auto/installer/brokeninstaller/components.qrc b/tests/auto/installer/brokeninstaller/components.qrc new file mode 100644 index 000000000..1431393a6 --- /dev/null +++ b/tests/auto/installer/brokeninstaller/components.qrc @@ -0,0 +1,6 @@ +<RCC> + <qresource prefix="/"> + <file>data/updates.xml</file> + <file>data/broken_script.qs</file> + </qresource> +</RCC> diff --git a/tests/auto/installer/brokeninstaller/data/broken_script.qs b/tests/auto/installer/brokeninstaller/data/broken_script.qs new file mode 100644 index 000000000..a1574f46d --- /dev/null +++ b/tests/auto/installer/brokeninstaller/data/broken_script.qs @@ -0,0 +1,31 @@ +/************************************************************************** +** +** Copyright (C) 2018 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$ +** +**************************************************************************/ +function Component() +{ + installer.invalidScriptCall() +} diff --git a/tests/auto/installer/brokeninstaller/data/updates.xml b/tests/auto/installer/brokeninstaller/data/updates.xml new file mode 100644 index 000000000..a20275120 --- /dev/null +++ b/tests/auto/installer/brokeninstaller/data/updates.xml @@ -0,0 +1,163 @@ +<Updates> + <ApplicationName>Your application</ApplicationName> + <ApplicationVersion>1.2.3</ApplicationVersion> + <Checksum>true</Checksum> + <PackageUpdate> + <Name>componentinvalidscript</Name> + <DisplayName>Invalid script component</DisplayName> + <Description>Install this example.</Description> + <Version>0.1.0-1</Version> + <ReleaseDate>2010-09-21</ReleaseDate> + <Default>true</Default> + <SortingPriority>1</SortingPriority> + <UpdateFile UncompressedSize="61" + CompressedSize="61"/> + <Licenses> + <License name="Beer Public License Agreement" + file="license.txt"/> + </Licenses> + </PackageUpdate> + <PackageUpdate> + <Name>componentb</Name> + <DisplayName>The second root component</DisplayName> + <Description>Install this example.</Description> + <Version>0.1.0-1</Version> + <ReleaseDate>2010-09-21</ReleaseDate> + <Default>true</Default> + <Script>installscript.qs</Script> + <SortingPriority>1</SortingPriority> + <UpdateFile UncompressedSize="61" + CompressedSize="61"/> + <Licenses> + <License name="Beer Public License Agreement" + file="license.txt"/> + </Licenses> + </PackageUpdate> + <PackageUpdate> + <Name>componentc</Name> + <DisplayName>The third root component</DisplayName> + <Description>Install this example.</Description> + <Version>0.1.0-1</Version> + <ReleaseDate>2010-09-21</ReleaseDate> + <Default>true</Default> + <Script>installscript.qs</Script> + <SortingPriority>1</SortingPriority> + <UpdateFile UncompressedSize="61" + CompressedSize="61"/> + <Licenses> + <License name="Beer Public License Agreement" + file="license.txt"/> + </Licenses> + </PackageUpdate> + <PackageUpdate> + <Name>componentc.subnode</Name> + <DisplayName>A subcomponent for the third root, dependency to component with invalid script</DisplayName> + <Description>Install this example.</Description> + <Version>0.1.0-1</Version> + <ReleaseDate>2010-09-21</ReleaseDate> + <Default>true</Default> + <Script>installscript.qs</Script> + <SortingPriority>1</SortingPriority> + <Dependencies>componentinvalidscript</Dependencies> + <UpdateFile UncompressedSize="61" + CompressedSize="61"/> + <Licenses> + <License name="Beer Public License Agreement" + file="license.txt"/> + </Licenses> + </PackageUpdate> + <PackageUpdate> + <Name>componentc.subnode.sub</Name> + <DisplayName>A subcomponent for the third roots subcomponent</DisplayName> + <Description>Install this example.</Description> + <Version>0.1.0-1</Version> + <ReleaseDate>2010-09-21</ReleaseDate> + <Script>installscript.qs</Script> + <Default>true</Default> + <UpdateFile UncompressedSize="61" + CompressedSize="61"/> + <Licenses> + <License name="Beer Public License Agreement" + file="license.txt"/> + </Licenses> + </PackageUpdate> + <PackageUpdate> + <Name>componentmissingdependency</Name> + <DisplayName>A component that has missing sha</DisplayName> + <Description>Install this example.</Description> + <Version>0.1.0-1</Version> + <ReleaseDate>2010-09-21</ReleaseDate> + <Default>true</Default> + <Script>installscript.qs</Script> + <UpdateFile UncompressedSize="61" + CompressedSize="61"/> + <Licenses> + <License name="Beer Public License Agreement" + file="license.txt"/> + </Licenses> + </PackageUpdate> + <PackageUpdate> + <Name>componentd</Name> + <DisplayName>Component that depends on component which is missing dependency</DisplayName> + <Description>Install this example.</Description> + <Version>0.1.0-1</Version> + <ReleaseDate>2010-09-21</ReleaseDate> + <Script>installscript.qs</Script> + <UpdateFile UncompressedSize="61" + CompressedSize="61"/> + <Licenses> + <License name="Beer Public License Agreement" + file="license.txt"/> + </Licenses> + </PackageUpdate> + <PackageUpdate> + <Name>componentmissingcontent</Name> + <DisplayName>A component which is missing 7z</DisplayName> + <Description>Install this example.</Description> + <Version>0.1.0-1</Version> + <ReleaseDate>2010-09-21</ReleaseDate> + <Default>true</Default> + <Script>installscript.qs</Script> + <SortingPriority>0</SortingPriority> + <DownloadableArchives>content.7z</DownloadableArchives> + <UpdateFile UncompressedSize="61" + CompressedSize="61"/> + <Licenses> + <License name="Beer Public License Agreement" + file="license.txt"/> + </Licenses> + </PackageUpdate> + <PackageUpdate> + <Name>componentmissingcontent.sub</Name> + <DisplayName>A subcomponent of component which is missing 7z</DisplayName> + <Description>Install this example.</Description> + <Version>0.1.0-1</Version> + <ReleaseDate>2010-09-21</ReleaseDate> + <Checkable>true</Checkable> + <Default>true</Default> + <Script>installscript.qs</Script> + <UpdateFile UncompressedSize="61" + CompressedSize="61"/> + <Licenses> + <License name="Beer Public License Agreement" + file="license.txt"/> + </Licenses> + </PackageUpdate> + <PackageUpdate> + <Name>componentE</Name> + <DisplayName>A component which is dependent on subcomponent of missing 7z component</DisplayName> + <Description>Install this example.</Description> + <Version>0.1.0-1</Version> + <ReleaseDate>2010-09-21</ReleaseDate> + <Script>installscript.qs</Script> + <Checkable>true</Checkable> + <Default>true</Default> + <Dependencies>componentmissingcontent.sub</Dependencies> + <UpdateFile UncompressedSize="61" + CompressedSize="61"/> + <Licenses> + <License name="Beer Public License Agreement" + file="license.txt"/> + </Licenses> + </PackageUpdate> +</Updates> diff --git a/tests/auto/installer/brokeninstaller/tst_brokeninstaller.cpp b/tests/auto/installer/brokeninstaller/tst_brokeninstaller.cpp new file mode 100644 index 000000000..95f4ac77d --- /dev/null +++ b/tests/auto/installer/brokeninstaller/tst_brokeninstaller.cpp @@ -0,0 +1,228 @@ +/************************************************************************** +** +** Copyright (C) 2018 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 "component.h" +#include "componentmodel.h" +#include "updatesinfo_p.h" +#include "packagemanagercore.h" +#include "settings.h" + +#include <QTest> +#include <QtCore/QLocale> +#include <QRegularExpression> + +using namespace KDUpdater; +using namespace QInstaller; + +#define EXPECTED_COUNTS_COMPONENTS_VISIBLE 10 +#define EXPECTED_COUNT_ROOT_COMPONENTS 7 +#define EXPECTED_COUNT_INVALID_SCRIPT 7 +#define EXPECTED_COUNT_MISSING_DEPENDENCY 8 + +static const char componentInvalidScript[] = "componentinvalidscript"; +static const char componentB[] = "componentb"; + +static const char componentC[] = "componentc"; +static const char componentCSubnodeDependsOnInvalidScriptComponent[] = "componentc.subnode"; +static const char componentCSubnodeDependsOnInvalidScriptComponentSub[] = "componentc.subnode.sub"; + +static const char componentMissingDependency[] = "componentmissingdependency"; +static const char componentDependsOnMissingDependency[] = "componentd"; + +static const char componentMissingContent[] = "componentmissingcontent"; +static const char componentMissingContentSub[] = "componentmissingcontent.sub"; +static const char componentDependsOnMissingContentSub[] = "componentE"; + +static const QMap<QString, QString> rootComponentDisplayNames = { + {"", QLatin1String("The root component")}, + {"ru_ru", QString::fromUtf8("Корневая компонента")}, + {"de_de", QString::fromUtf8("Wurzel Komponente")} +}; + +using namespace QInstaller; + +class tst_BrokenInstaller : public QObject +{ + Q_OBJECT + +public: + enum Option { + NoFlags = 0x00, + VirtualsVisible = 0x01, + NoForcedInstallation = 0x02 + }; + Q_DECLARE_FLAGS(Options, Option); + +private slots: + void initTestCase() + { + + m_checkedComponentsWithBrokenScript << componentB << componentMissingDependency << componentDependsOnMissingDependency << componentMissingContent + << componentMissingContentSub << componentDependsOnMissingContentSub; + m_uncheckedComponentsWithBrokenScript << componentInvalidScript << componentCSubnodeDependsOnInvalidScriptComponent + << componentCSubnodeDependsOnInvalidScriptComponentSub << componentC; + + m_checkedComponentsWithMissingDependency << componentB << componentMissingContent << componentMissingContentSub << componentDependsOnMissingContentSub + << componentInvalidScript << componentCSubnodeDependsOnInvalidScriptComponent + << componentCSubnodeDependsOnInvalidScriptComponentSub << componentC; + m_uncheckedComponentsWithMissingDependency << componentMissingDependency << componentDependsOnMissingDependency; + + } + + void testNameToIndexAndIndexToName() + { + PackageManagerCore core; + QList<Component*> rootComponents = loadComponents(core); + + ComponentModel *model = new ComponentModel(1, &core); + model->setRootComponents(rootComponents); + // all names should be resolvable + QStringList all; + all << m_checkedComponentsWithBrokenScript << m_uncheckedComponentsWithBrokenScript << m_partiallyCheckedComponentsWithBrokenScript; + foreach (const QString &name, all) { + QVERIFY(model->indexFromComponentName(name).isValid()); + QVERIFY(model->componentFromIndex(model->indexFromComponentName(name)) != 0); + QCOMPARE(model->componentFromIndex(model->indexFromComponentName(name))->name(), name); + } + } + + void testInvalidScript() + { + PackageManagerCore core; + QList<Component*> components = loadComponents(core); + + core.settings().setAllowUnstableComponents(true); + ComponentModel *model = new ComponentModel(1, &core); + Component *invalidScriptComponent = core.componentByName("componentinvalidscript"); + + // Using regexp to ignore the warning message as the message contains + // object address which we don't know + const QString debugMessage = QString("Exception while loading the component script"); + const QRegularExpression re(debugMessage); + QTest::ignoreMessage(QtWarningMsg, re); + invalidScriptComponent->loadComponentScript(":///data/broken_script.qs"); + + model->setRootComponents(components); + testModelState(model, m_checkedComponentsWithBrokenScript, m_partiallyCheckedComponentsWithBrokenScript, m_uncheckedComponentsWithBrokenScript); + } + + void testMissingDependency() + { + PackageManagerCore core; + QList<Component*> components = loadComponents(core); + + core.settings().setAllowUnstableComponents(true); + ComponentModel *model = new ComponentModel(1, &core); + + Component *invalidComponent = core.componentByName("componentmissingdependency"); + invalidComponent->addDependency("missingcomponent"); + + Component *componentDependingOnMissingDependency = core.componentByName("componentd"); + componentDependingOnMissingDependency->addDependency("componentmissingdependency"); + + core.componentsToInstallNeedsRecalculation(); + model->setRootComponents(components); + + testModelState(model, m_checkedComponentsWithMissingDependency, m_partiallyCheckedComponentsWithBrokenScript, m_uncheckedComponentsWithMissingDependency); + } + +private: + + QList<Component*> loadComponents(PackageManagerCore &core) + { + UpdatesInfo updatesInfo; + updatesInfo.setFileName(":///data/updates.xml"); + const QList<UpdateInfo> updateInfos = updatesInfo.updatesInfo(); + + QList <Component*> components; + UpdateInfo info; + for (int i = 0; i < updateInfos.count(); i++) { + info = updateInfos.at(i); + Component *component = new Component(&core); + + // we need at least these to be able to test the model + component->setValue("Name", info.data.value("Name").toString()); + component->setValue("Virtual", info.data.value("Virtual").toString()); + component->setValue("DisplayName", info.data.value("DisplayName").toString()); + component->setValue("Checkable", info.data.value("Checkable").toString()); + component->setValue("Dependencies", info.data.value("Dependencies").toString()); + component->setCheckState(Qt::Checked); + QString forced = info.data.value("ForcedInstallation", scFalse).toString().toLower(); + if (core.noForceInstallation()) + forced = scFalse; + component->setValue("ForcedInstallation", forced); + if (forced == scTrue) { + component->setEnabled(false); + component->setCheckable(false); + } + //If name does not contain dot it is root component + qDebug()<<"component name "<<component->name(); + if (!component->name().contains('.')) { + core.appendRootComponent(component); + } else { //Contains dot, is previous components child component + components.at(i-1)->appendComponent(component); + } + components.append(component); + } + return components; + } + + void testModelState(ComponentModel *model, const QStringList &checked, const QStringList &partially, + const QStringList &unchecked) const + { + QCOMPARE(model->checked().count(), checked.count()); + QCOMPARE(model->partially().count(), partially.count()); + QCOMPARE(model->unchecked().count(), unchecked.count()); + + // these components should have checked state + foreach (Component *const component, model->checked()) + QVERIFY(checked.contains(component->name())); + + // these components should not have partially checked state + foreach (Component *const component, model->partially()) + QVERIFY(partially.contains(component->name())); + + // these components should not have checked state + foreach (Component *const component, model->unchecked()) + QVERIFY(unchecked.contains(component->name())); + } + +private: + QStringList m_checkedComponentsWithBrokenScript; + QStringList m_uncheckedComponentsWithBrokenScript; + QStringList m_partiallyCheckedComponentsWithBrokenScript; + + QStringList m_checkedComponentsWithMissingDependency; + QStringList m_uncheckedComponentsWithMissingDependency; + QStringList m_partiallyCheckedComponentsWithMissingDependency; +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(tst_BrokenInstaller::Options) + +QTEST_MAIN(tst_BrokenInstaller) + +#include "tst_brokeninstaller.moc" |