summaryrefslogtreecommitdiffstats
path: root/tests/auto/qml/applicationmanager/tst_applicationmanager.qml
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/qml/applicationmanager/tst_applicationmanager.qml')
-rw-r--r--tests/auto/qml/applicationmanager/tst_applicationmanager.qml503
1 files changed, 503 insertions, 0 deletions
diff --git a/tests/auto/qml/applicationmanager/tst_applicationmanager.qml b/tests/auto/qml/applicationmanager/tst_applicationmanager.qml
new file mode 100644
index 00000000..04ae409d
--- /dev/null
+++ b/tests/auto/qml/applicationmanager/tst_applicationmanager.qml
@@ -0,0 +1,503 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2019 Luxoft Sweden AB
+// Copyright (C) 2018 Pelagicore AG
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick 2.3
+import QtQuick.Window 2.0
+import QtTest 1.0
+import QtApplicationManager.SystemUI 2.0
+import QtApplicationManager.Test
+
+TestCase {
+ id: testCase
+ when: windowShown
+ name: "ApplicationManager"
+
+ property ApplicationObject simpleApplication
+ property ApplicationObject capsApplication
+ // Either appman is build in single-process mode or it was started with --force-single-process
+ property bool singleProcess : Qt.application.arguments.indexOf("--force-single-process") !== -1
+ || !AmTest.buildConfig[0].QT_FEATURES.QT_FEATURE_am_multi_process
+ property WindowObject lastWindowAdded: null
+ property QtObject windowHandler: QtObject {
+ function windowAddedHandler(window) {
+ // console.info("window " + window + " added");
+ lastWindowAdded = window
+ }
+
+
+ function windowContentStateChangedHandler(window) {
+ // console.info("window content state = " + window.contentState);
+ }
+ }
+
+ ListView {
+ id: listView
+ model: ApplicationManager
+ delegate: Item {
+ property var modelData: model
+ }
+ }
+
+ ApplicationModel {
+ id: appModel
+ sortFunction: function(la, ra) { return la.id > ra.id }
+ }
+
+ function initTestCase() {
+ WindowManager.windowAdded.connect(windowHandler.windowAddedHandler)
+ WindowManager.windowContentStateChanged.connect(windowHandler.windowContentStateChangedHandler)
+
+ compare(ApplicationManager.count, 2)
+ simpleApplication = ApplicationManager.application(0);
+ capsApplication = ApplicationManager.application(1);
+ }
+
+ function test_properties() {
+ // Only true for the dummyimports
+ compare(ApplicationManager.dummy, false)
+ // Disabled in the am-config.yaml
+ compare(ApplicationManager.securityChecksEnabled, false)
+
+ compare(ApplicationManager.singleProcess, singleProcess)
+ }
+
+ function test_systemProperties() {
+ compare(ApplicationManager.systemProperties.ignored, undefined)
+ compare(ApplicationManager.systemProperties.booleanTest, true)
+ compare(ApplicationManager.systemProperties.stringTest, "pelagicore")
+ compare(ApplicationManager.systemProperties.intTest, -1)
+ compare(ApplicationManager.systemProperties.floatTest, .5)
+ compare(ApplicationManager.systemProperties.arrayTest[0], "value1")
+ compare(ApplicationManager.systemProperties.arrayTest[1], "value2")
+ compare(ApplicationManager.systemProperties.mapTest["key1"], "1")
+ compare(ApplicationManager.systemProperties.mapTest["key2"], "2")
+ compare(ApplicationManager.systemProperties.nested.level21, 21)
+ compare(ApplicationManager.systemProperties.nested.level2.level31, 31)
+ compare(ApplicationManager.systemProperties.nested.level2.level32, undefined)
+ compare(ApplicationManager.systemProperties.nested.level21, 21)
+ compare(ApplicationManager.systemProperties.nested.level22, 22)
+ compare(ApplicationManager.systemProperties.pub1, 'pub1')
+ compare(ApplicationManager.systemProperties.pro1, 'pro1')
+ compare(ApplicationManager.systemProperties.pubandpro, 'pro2')
+ compare(ApplicationManager.systemProperties.pubandpri, 'pri3')
+ compare(ApplicationManager.systemProperties.proandpri, 'pri4')
+ compare(ApplicationManager.systemProperties.inall, 'private')
+ compare(ApplicationManager.systemProperties.nullTest, null)
+ }
+
+ function test_package() {
+ compare(PackageManager.count, 2)
+ verify(simpleApplication.package !== capsApplication.package)
+ compare(simpleApplication.package, PackageManager.package("tld.test.simple1"))
+ compare(simpleApplication.package.id, "tld.test.simple1")
+ compare(simpleApplication.package.applications.length, 1)
+ compare(simpleApplication.package.applications[0], simpleApplication)
+ }
+
+ function test_application() {
+ var id = simpleApplication.id;
+ compare(simpleApplication.id, "tld.test.simple1")
+ compare(simpleApplication.runtimeName, "qml")
+ compare(simpleApplication.icon.toString(), Qt.resolvedUrl("apps/tld.test.simple1/icon.png"))
+ compare(simpleApplication.documentUrl, "")
+ compare(simpleApplication.builtIn, true)
+ compare(simpleApplication.alias, false)
+ compare(simpleApplication.nonAliased, simpleApplication)
+ compare(simpleApplication.capabilities.length, 0)
+ compare(simpleApplication.supportedMimeTypes.length, 2)
+ compare(simpleApplication.categories.length, 0)
+ //Why is runtime null ? we should document this, as this is not really clear
+ compare(simpleApplication.runtime, null)
+ compare(simpleApplication.lastExitCode, 0)
+ compare(simpleApplication.lastExitStatus, Am.NormalExit)
+ compare(simpleApplication.version, "1.0")
+
+ // Test the name getter and verify that it's returning the same object
+ compare(simpleApplication, ApplicationManager.application(id))
+ }
+
+ function test_applicationProperties() {
+ compare(simpleApplication.applicationProperties.ignored, undefined)
+ compare(simpleApplication.applicationProperties.pro1, "pro1")
+ compare(simpleApplication.applicationProperties.proandpri, "pro2")
+ compare(simpleApplication.applicationProperties.pri1, undefined)
+ }
+
+ function test_indexOfApplication() {
+ // Test index of
+ compare(ApplicationManager.indexOfApplication(simpleApplication.id), 0)
+ compare(ApplicationManager.indexOfApplication(capsApplication.id), 1)
+ compare(ApplicationManager.indexOfApplication("error"), -1)
+ }
+
+ function test_applicationIds() {
+ // Test app ids
+ var apps = ApplicationManager.applicationIds()
+ compare(apps.length, ApplicationManager.count)
+ compare(ApplicationManager.applicationIds()[0], simpleApplication.id)
+ compare(ApplicationManager.applicationIds()[1], capsApplication.id)
+ }
+
+ function test_capabilities() {
+ var emptyCaps = ApplicationManager.capabilities(simpleApplication.id)
+ compare(emptyCaps.length, 0)
+ var caps = ApplicationManager.capabilities(capsApplication.id)
+ compare(caps.length, 2)
+ }
+
+ function test_modelData() {
+ compare(listView.count, ApplicationManager.count)
+ listView.currentIndex = 0;
+ compare(listView.currentItem.modelData.application, simpleApplication)
+ compare(listView.currentItem.modelData.applicationId, simpleApplication.id)
+ compare(listView.currentItem.modelData.name, "Simple1")
+ compare(listView.currentItem.modelData.icon.toString(), Qt.resolvedUrl(simpleApplication.icon))
+ compare(listView.currentItem.modelData.runtimeName, "qml")
+ compare(listView.currentItem.modelData.isRunning, false)
+ compare(listView.currentItem.modelData.isStartingUp, false)
+ compare(listView.currentItem.modelData.isShuttingDown, false)
+ compare(listView.currentItem.modelData.isBlocked, false)
+ compare(listView.currentItem.modelData.isUpdating, false)
+ compare(listView.currentItem.modelData.isRemovable, false)
+ compare(listView.currentItem.modelData.updateProgress, 0.0)
+ verify(listView.currentItem.modelData.codeFilePath.indexOf("apps/tld.test.simple1/app1.qml") !== -1)
+ compare(listView.currentItem.modelData.capabilities, simpleApplication.capabilities)
+ compare(listView.currentItem.modelData.version, "1.0")
+ }
+
+ SignalSpy {
+ id: appModelCountSpy
+ target: appModel
+ signalName: "countChanged"
+ }
+
+ function test_applicationModel() {
+ compare(appModel.count, 2);
+ compare(appModel.indexOfApplication(capsApplication.id), 0);
+ compare(appModel.indexOfApplication(simpleApplication.id), 1);
+ compare(appModel.mapToSource(0), ApplicationManager.indexOfApplication(capsApplication.id));
+ compare(appModel.mapFromSource(ApplicationManager.indexOfApplication(simpleApplication.id)), 1);
+
+ appModel.sortFunction = undefined;
+ compare(appModel.indexOfApplication(simpleApplication.id),
+ ApplicationManager.indexOfApplication(simpleApplication.id));
+ compare(appModel.indexOfApplication(capsApplication.id),
+ ApplicationManager.indexOfApplication(capsApplication.id));
+
+ appModelCountSpy.clear();
+ appModel.filterFunction = function(app) { return app.capabilities.indexOf("cameraAccess") >= 0; };
+ appModelCountSpy.wait(1000 * AmTest.timeoutFactor);
+ compare(appModelCountSpy.count, 1);
+ compare(appModel.count, 1);
+ compare(appModel.indexOfApplication(capsApplication.id), 0);
+ compare(appModel.indexOfApplication(simpleApplication.id), -1);
+
+ listView.model = appModel;
+ listView.currentIndex = 0;
+ compare(listView.currentItem.modelData.name, "Caps");
+ listView.model = ApplicationManager;
+
+ appModel.filterFunction = function() {};
+ compare(appModel.count, 0);
+
+ appModel.filterFunction = undefined;
+ compare(appModel.count, 2);
+ }
+
+ function test_get_data() {
+ return [
+ {tag: "get(row)", argument: 0 },
+ {tag: "get(id)", argument: simpleApplication.id },
+ ];
+ }
+
+ function test_get(data) {
+ var appData = ApplicationManager.get(data.argument);
+
+ compare(appData.application, simpleApplication)
+ compare(appData.applicationId, simpleApplication.id)
+ compare(appData.name, "Simple1")
+ compare(appData.icon.toString(), Qt.resolvedUrl(simpleApplication.icon))
+ compare(appData.runtimeName, "qml")
+ compare(appData.isRunning, false)
+ compare(appData.isStartingUp, false)
+ compare(appData.isShuttingDown, false)
+ compare(appData.isBlocked, false)
+ compare(appData.isUpdating, false)
+ compare(appData.isRemovable, false)
+ compare(appData.updateProgress, 0.0)
+ verify(appData.codeFilePath.indexOf("apps/tld.test.simple1/app1.qml") !== -1)
+ compare(appData.capabilities, simpleApplication.capabilities)
+ compare(appData.version, "1.0")
+ }
+
+ function test_application_object_ownership() {
+ // Check that the returned Application is not owned by javascript and deleted
+ // by the garbage collector
+ var app = ApplicationManager.application(0);
+ var id = app.id
+ app = null;
+ // app gets deleted now as there is now javascript reference anymore
+ gc()
+ // Test that the Application in the ApplicationManager is still valid
+ // by accessing one of it's properties
+ compare(id, ApplicationManager.application(0).id)
+ }
+
+ SignalSpy {
+ id: runStateChangedSpy
+ target: ApplicationManager
+ signalName: "applicationRunStateChanged"
+ }
+
+ function checkApplicationState(id, state) {
+ if (runStateChangedSpy.count < 1)
+ runStateChangedSpy.wait(10000 * AmTest.timeoutFactor);
+ verify(runStateChangedSpy.count)
+ compare(runStateChangedSpy.signalArguments[0][0], id)
+ compare(runStateChangedSpy.signalArguments[0][1], state)
+ compare(ApplicationManager.application(id).runState, state);
+ runStateChangedSpy.clear();
+ }
+
+ function test_startAndStopApplication_data() {
+ return [
+ {tag: "StartStop", appId: "tld.test.simple1", index: 0, forceKill: false,
+ exitCode: 0, exitStatus: Am.NormalExit },
+ {tag: "Debug", appId: "tld.test.simple1", index: 0, forceKill: false,
+ exitCode: 0, exitStatus: Am.NormalExit },
+ {tag: "ForceKill", appId: "tld.test.simple2", index: 1, forceKill: true,
+ exitCode: 9, exitStatus: Am.ForcedExit },
+ {tag: "AutoTerminate", appId: "tld.test.simple2", index: 1, forceKill: false,
+ exitCode: 15, exitStatus: Am.ForcedExit }
+ ];
+ }
+
+ function test_startAndStopApplication(data) {
+ compare(ApplicationManager.application(data.appId).runState, Am.NotRunning);
+
+ var started = false;
+ if (data.tag === "Debug") {
+ if (singleProcess)
+ ignoreWarning("Using debug-wrappers is not supported when the application manager is running in single-process mode.");
+ started = ApplicationManager.debugApplication(data.appId, "%program% %arguments%");
+ if (singleProcess) {
+ verify(!started);
+ return;
+ }
+ } else {
+ started = ApplicationManager.startApplication(data.appId);
+ }
+ verify(started);
+
+ checkApplicationState(data.appId, Am.StartingUp);
+ listView.currentIndex = data.index;
+ compare(listView.currentItem.modelData.isStartingUp, true)
+ compare(listView.currentItem.modelData.isRunning, false)
+ compare(listView.currentItem.modelData.isShuttingDown, false)
+ checkApplicationState(data.appId, Am.Running);
+ compare(listView.currentItem.modelData.isStartingUp, false)
+ compare(listView.currentItem.modelData.isRunning, true)
+ compare(listView.currentItem.modelData.isShuttingDown, false)
+
+ // make sure we have a window
+ tryCompare(WindowManager, "count", 1)
+ compare(WindowManager.windowsOfApplication(data.appId).length, 1)
+ compare(WindowManager.windowsOfApplication(data.appId)[0], lastWindowAdded)
+
+ ApplicationManager.stopApplication(data.appId, data.forceKill);
+
+ checkApplicationState(data.appId, Am.ShuttingDown);
+ compare(listView.currentItem.modelData.isStartingUp, false)
+ compare(listView.currentItem.modelData.isRunning, false)
+ compare(listView.currentItem.modelData.isShuttingDown, true)
+ checkApplicationState(data.appId, Am.NotRunning);
+ compare(listView.currentItem.modelData.isStartingUp, false)
+ compare(listView.currentItem.modelData.isRunning, false)
+ compare(listView.currentItem.modelData.isShuttingDown, false)
+ compare(listView.currentItem.modelData.application.lastExitCode, data.exitCode)
+ compare(listView.currentItem.modelData.application.lastExitStatus, data.exitStatus)
+ }
+
+ function test_startAndStopAllApplications_data() {
+ return [
+ {tag: "StopAllApplications", appId1: "tld.test.simple1", index1: 0,
+ appId2: "tld.test.simple2", index2: 1, forceKill: false, exitCode: 0,
+ exitStatus: Am.NormalExit }
+ ];
+ }
+
+ function test_startAndStopAllApplications(data) {
+ compare(ApplicationManager.application(data.appId1).runState, Am.NotRunning);
+ compare(ApplicationManager.application(data.appId2).runState, Am.NotRunning);
+
+ var started = false;
+
+ started = ApplicationManager.startApplication(data.appId1);
+ verify(started);
+
+
+ checkApplicationState(data.appId1, Am.StartingUp);
+ listView.currentIndex = data.index1;
+ compare(listView.currentItem.modelData.isStartingUp, true)
+ compare(listView.currentItem.modelData.isRunning, false)
+ compare(listView.currentItem.modelData.isShuttingDown, false)
+ checkApplicationState(data.appId1, Am.Running);
+ compare(listView.currentItem.modelData.isStartingUp, false)
+ compare(listView.currentItem.modelData.isRunning, true)
+ compare(listView.currentItem.modelData.isShuttingDown, false)
+
+ started = ApplicationManager.startApplication(data.appId2);
+ verify(started);
+
+ checkApplicationState(data.appId2, Am.StartingUp);
+ listView.currentIndex = data.index2;
+ compare(listView.currentItem.modelData.isStartingUp, true)
+ compare(listView.currentItem.modelData.isRunning, false)
+ compare(listView.currentItem.modelData.isShuttingDown, false)
+ checkApplicationState(data.appId2, Am.Running);
+ compare(listView.currentItem.modelData.isStartingUp, false)
+ compare(listView.currentItem.modelData.isRunning, true)
+ compare(listView.currentItem.modelData.isShuttingDown, false)
+
+ ApplicationManager.stopAllApplications(data.forceKill);
+
+ while (runStateChangedSpy.count < 4)
+ runStateChangedSpy.wait(10000 * AmTest.timeoutFactor);
+
+ var args = runStateChangedSpy.signalArguments
+
+ for (var i = 0; i < 4; ++i) {
+ var id = args[i][0]
+ var state = args[i][1]
+
+ var atPos = id.indexOf('@')
+ if (atPos >= 0)
+ id = id.substring(0, atPos)
+
+ // not perfect, but the basic signal sequence is already tested in test_startAndStopApplication
+ verify(id === data.appId1 || id === data.appId2, "id = " + id)
+ verify(state === Am.ShuttingDown || state === Am.NotRunning)
+ }
+ runStateChangedSpy.clear()
+ }
+
+ function test_errors() {
+ ignoreWarning("ApplicationManager::application(index): invalid index: -1");
+ verify(!ApplicationManager.application(-1));
+ verify(!ApplicationManager.application("invalidApplication"));
+ ignoreWarning("ApplicationManager::get(index): invalid index: -1");
+ compare(ApplicationManager.get(-1), {});
+ compare(ApplicationManager.get("invalidApplication"), {});
+ compare(ApplicationManager.applicationRunState("invalidApplication"), Am.NotRunning);
+
+ ignoreWarning("Cannot start application: id 'invalidApplication' is not known");
+ verify(!ApplicationManager.startApplication("invalidApplication"))
+
+ //All following tests don't work in single-process mode
+ if (singleProcess)
+ return;
+
+ ignoreWarning("Tried to start application tld.test.simple1 using an invalid debug-wrapper specification: ");
+ verify(!ApplicationManager.debugApplication(simpleApplication.id, " "))
+
+ verify(ApplicationManager.startApplication(simpleApplication.id));
+ checkApplicationState(simpleApplication.id, Am.StartingUp);
+ checkApplicationState(simpleApplication.id, Am.Running);
+ ignoreWarning("Application tld.test.simple1 is already running - cannot start with debug-wrapper: %program% %arguments%");
+ verify(!ApplicationManager.debugApplication(simpleApplication.id, "%program% %arguments%"))
+ ApplicationManager.stopApplication(simpleApplication.id);
+ checkApplicationState(simpleApplication.id, Am.ShuttingDown);
+ checkApplicationState(simpleApplication.id, Am.NotRunning);
+ }
+
+ function test_openUrl_data() {
+ return [
+ {tag: "customMimeType", url: "x-test://12345", expectedApp: simpleApplication.id },
+ {tag: "text/plain", url: "file://text-file.txt", expectedApp: simpleApplication.id }
+ ];
+ }
+
+ function test_openUrl(data) {
+ verify(ApplicationManager.openUrl(data.url));
+ checkApplicationState(data.expectedApp, Am.StartingUp);
+ checkApplicationState(data.expectedApp, Am.Running);
+ ApplicationManager.stopApplication(data.expectedApp);
+ checkApplicationState(data.expectedApp, Am.ShuttingDown);
+ checkApplicationState(data.expectedApp, Am.NotRunning);
+
+ Qt.openUrlExternally(data.url);
+ checkApplicationState(data.expectedApp, Am.StartingUp);
+ checkApplicationState(data.expectedApp, Am.Running);
+ ApplicationManager.stopApplication(data.expectedApp);
+ checkApplicationState(data.expectedApp, Am.ShuttingDown);
+ checkApplicationState(data.expectedApp, Am.NotRunning);
+ }
+
+ property bool containerSelectionCalled: false
+ property string containerSelectionAppId
+ property string containerSelectionConId
+ function containerSelection(appId, containerId) {
+ containerSelectionCalled = true;
+ containerSelectionAppId = appId;
+ containerSelectionConId = containerId;
+
+ return containerId;
+ }
+
+ function test_containerSelectionFunction() {
+ if (singleProcess)
+ skip("The containerSelectionFunction doesn't work in single-process mode");
+
+ compare(ApplicationManager.containerSelectionFunction, undefined);
+ ApplicationManager.containerSelectionFunction = containerSelection;
+ ApplicationManager.startApplication(simpleApplication.id);
+ checkApplicationState(simpleApplication.id, Am.StartingUp);
+ checkApplicationState(simpleApplication.id, Am.Running);
+ ApplicationManager.stopApplication(simpleApplication.id);
+ checkApplicationState(simpleApplication.id, Am.ShuttingDown);
+ checkApplicationState(simpleApplication.id, Am.NotRunning);
+ verify(containerSelectionCalled);
+ compare(containerSelectionAppId, simpleApplication.id);
+ compare(containerSelectionConId, "process");
+ }
+
+ function test_applicationInterface() {
+ let req = IntentClient.sendIntentRequest("applicationInterfaceProperties", simpleApplication.id, { })
+ verify(req)
+ tryVerify(() => { return req.succeeded })
+ const ai = {
+ "applicationId": simpleApplication.id,
+ "applicationProperties": {
+ "pri1": "pri1",
+ "pro1": "pro1",
+ "proandpri": "pri2"
+ },
+ "icon": simpleApplication.icon.toString().split('/').pop(),
+ "systemProperties": {
+ "inall": "protected",
+ "nested": {
+ "level2": {
+ "level31": "overwritten",
+ "level32": "hidden"
+ }
+ },
+ "pro1": "pro1",
+ "proandpri": "pro4",
+ "pub1": "pub1",
+ "pubandpri": "pub3",
+ "pubandpro": "pro2"
+ },
+ "version": simpleApplication.version
+ }
+
+ compare(req.result, ai)
+
+ // cleanup
+ compare(simpleApplication.runState, Am.Running)
+ ApplicationManager.stopApplication(simpleApplication.id)
+ tryVerify(() => { return simpleApplication.runState === Am.NotRunning })
+ }
+}