From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../test/xpcshell/test_system_update_custom.js | 492 +++++++++++++++++++++ 1 file changed, 492 insertions(+) create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_system_update_custom.js (limited to 'toolkit/mozapps/extensions/test/xpcshell/test_system_update_custom.js') diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_system_update_custom.js b/toolkit/mozapps/extensions/test/xpcshell/test_system_update_custom.js new file mode 100644 index 0000000000..3aa61fed51 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/test_system_update_custom.js @@ -0,0 +1,492 @@ +// Tests that system add-on upgrades work. + +createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "2"); + +let distroDir = FileUtils.getDir("ProfD", ["sysfeatures", "empty"], true); +registerDirectory("XREAppFeat", distroDir); + +AddonTestUtils.usePrivilegedSignatures = id => "system"; + +add_task(initSystemAddonDirs); + +/** + * Defines the set of initial conditions to run each test against. Each should + * define the following properties: + * + * setup: A task to setup the profile into the initial state. + * initialState: The initial expected system add-on state after setup has run. + */ +const TEST_CONDITIONS = { + // Runs tests with no updated or default system add-ons initially installed + blank: { + setup() { + clearSystemAddonUpdatesDir(); + distroDir.leafName = "empty"; + }, + initialState: [ + { isUpgrade: false, version: null }, + { isUpgrade: false, version: null }, + { isUpgrade: false, version: null }, + { isUpgrade: false, version: null }, + { isUpgrade: false, version: null }, + ], + }, + // Runs tests with default system add-ons installed + withAppSet: { + setup() { + clearSystemAddonUpdatesDir(); + distroDir.leafName = "prefilled"; + }, + initialState: [ + { isUpgrade: false, version: null }, + { isUpgrade: false, version: "2.0" }, + { isUpgrade: false, version: "2.0" }, + { isUpgrade: false, version: null }, + { isUpgrade: false, version: null }, + ], + }, + + // Runs tests with updated system add-ons installed + withProfileSet: { + async setup() { + await buildPrefilledUpdatesDir(); + distroDir.leafName = "empty"; + }, + initialState: [ + { isUpgrade: false, version: null }, + { isUpgrade: true, version: "2.0" }, + { isUpgrade: true, version: "2.0" }, + { isUpgrade: false, version: null }, + { isUpgrade: false, version: null }, + ], + }, + + // Runs tests with both default and updated system add-ons installed + withBothSets: { + async setup() { + await buildPrefilledUpdatesDir(); + distroDir.leafName = "hidden"; + }, + initialState: [ + { isUpgrade: false, version: "1.0" }, + { isUpgrade: true, version: "2.0" }, + { isUpgrade: true, version: "2.0" }, + { isUpgrade: false, version: null }, + { isUpgrade: false, version: null }, + ], + }, +}; + +// Test that the update check is performed as part of the regular add-on update +// check +add_task(async function test_addon_update() { + Services.prefs.setBoolPref(PREF_SYSTEM_ADDON_UPDATE_ENABLED, true); + await setupSystemAddonConditions(TEST_CONDITIONS.blank, distroDir); + + let updateXML = buildSystemAddonUpdates([ + { + id: "system2@tests.mozilla.org", + version: "2.0", + path: "system2_2.xpi", + xpi: await getSystemAddonXPI(2, "2.0"), + }, + { + id: "system3@tests.mozilla.org", + version: "2.0", + path: "system3_2.xpi", + xpi: await getSystemAddonXPI(3, "2.0"), + }, + ]); + + const promiseInstallsEnded = createInstallsEndedPromise(2); + + await Promise.all([ + updateAllSystemAddons(updateXML), + promiseWebExtensionStartup("system2@tests.mozilla.org"), + promiseWebExtensionStartup("system3@tests.mozilla.org"), + ]); + + await promiseInstallsEnded; + + await verifySystemAddonState( + TEST_CONDITIONS.blank.initialState, + [ + { isUpgrade: false, version: null }, + { isUpgrade: true, version: "2.0" }, + { isUpgrade: true, version: "2.0" }, + { isUpgrade: false, version: null }, + { isUpgrade: false, version: null }, + ], + false, + distroDir + ); + + await promiseShutdownManager(); +}); + +// Disabling app updates should block system add-on updates +add_task(async function test_app_update_disabled() { + await setupSystemAddonConditions(TEST_CONDITIONS.blank, distroDir); + + Services.prefs.setBoolPref(PREF_SYSTEM_ADDON_UPDATE_ENABLED, false); + let updateXML = buildSystemAddonUpdates([ + { + id: "system2@tests.mozilla.org", + version: "2.0", + path: "system2_2.xpi", + xpi: await getSystemAddonXPI(2, "2.0"), + }, + { + id: "system3@tests.mozilla.org", + version: "2.0", + path: "system3_2.xpi", + xpi: await getSystemAddonXPI(3, "2.0"), + }, + ]); + await updateAllSystemAddons(updateXML); + Services.prefs.clearUserPref(PREF_SYSTEM_ADDON_UPDATE_ENABLED); + + await verifySystemAddonState( + TEST_CONDITIONS.blank.initialState, + undefined, + false, + distroDir + ); + + await promiseShutdownManager(); +}); + +// Safe mode should block system add-on updates +add_task(async function test_safe_mode() { + gAppInfo.inSafeMode = true; + + await setupSystemAddonConditions(TEST_CONDITIONS.blank, distroDir); + + Services.prefs.setBoolPref(PREF_SYSTEM_ADDON_UPDATE_ENABLED, false); + let updateXML = buildSystemAddonUpdates([ + { + id: "system2@tests.mozilla.org", + version: "2.0", + path: "system2_2.xpi", + xpi: await getSystemAddonXPI(2, "2.0"), + }, + { + id: "system3@tests.mozilla.org", + version: "2.0", + path: "system3_2.xpi", + xpi: await getSystemAddonXPI(3, "2.0"), + }, + ]); + await updateAllSystemAddons(updateXML); + Services.prefs.clearUserPref(PREF_SYSTEM_ADDON_UPDATE_ENABLED); + + await verifySystemAddonState( + TEST_CONDITIONS.blank.initialState, + undefined, + false, + distroDir + ); + + await promiseShutdownManager(); + + gAppInfo.inSafeMode = false; +}); + +// Tests that a set that matches the default set does nothing +add_task(async function test_match_default() { + await setupSystemAddonConditions(TEST_CONDITIONS.withAppSet, distroDir); + + let installXML = buildSystemAddonUpdates([ + { + id: "system2@tests.mozilla.org", + version: "2.0", + path: "system2_2.xpi", + xpi: await getSystemAddonXPI(2, "2.0"), + }, + { + id: "system3@tests.mozilla.org", + version: "2.0", + path: "system3_2.xpi", + xpi: await getSystemAddonXPI(3, "2.0"), + }, + ]); + await installSystemAddons(installXML); + + // Shouldn't have installed an updated set + await verifySystemAddonState( + TEST_CONDITIONS.withAppSet.initialState, + undefined, + false, + distroDir + ); + + await promiseShutdownManager(); +}); + +// Tests that a set that matches the hidden default set works +add_task(async function test_match_default_revert() { + await setupSystemAddonConditions(TEST_CONDITIONS.withBothSets, distroDir); + + let installXML = buildSystemAddonUpdates([ + { + id: "system1@tests.mozilla.org", + version: "1.0", + path: "system1_1.xpi", + xpi: await getSystemAddonXPI(1, "1.0"), + }, + { + id: "system2@tests.mozilla.org", + version: "1.0", + path: "system2_1.xpi", + xpi: await getSystemAddonXPI(2, "1.0"), + }, + ]); + await installSystemAddons(installXML); + + // This should revert to the default set instead of installing new versions + // into an updated set. + await verifySystemAddonState( + TEST_CONDITIONS.withBothSets.initialState, + [ + { isUpgrade: false, version: "1.0" }, + { isUpgrade: false, version: "1.0" }, + { isUpgrade: false, version: null }, + { isUpgrade: false, version: null }, + { isUpgrade: false, version: null }, + ], + false, + distroDir + ); + + await promiseShutdownManager(); +}); + +// Tests that a set that matches the current set works +add_task(async function test_match_current() { + await setupSystemAddonConditions(TEST_CONDITIONS.withBothSets, distroDir); + + let installXML = buildSystemAddonUpdates([ + { + id: "system2@tests.mozilla.org", + version: "2.0", + path: "system2_2.xpi", + xpi: await getSystemAddonXPI(2, "2.0"), + }, + { + id: "system3@tests.mozilla.org", + version: "2.0", + path: "system3_2.xpi", + xpi: await getSystemAddonXPI(3, "2.0"), + }, + ]); + await installSystemAddons(installXML); + + // This should remain with the current set instead of creating a new copy + let set = JSON.parse(Services.prefs.getCharPref(PREF_SYSTEM_ADDON_SET)); + Assert.equal(set.directory, "prefilled"); + + await verifySystemAddonState( + TEST_CONDITIONS.withBothSets.initialState, + undefined, + false, + distroDir + ); + + await promiseShutdownManager(); +}); + +// Tests that a set with a minor change doesn't re-download existing files +add_task(async function test_no_download() { + await setupSystemAddonConditions(TEST_CONDITIONS.withBothSets, distroDir); + + // The missing file here is unneeded since there is a local version already + let installXML = buildSystemAddonUpdates([ + { id: "system2@tests.mozilla.org", version: "2.0", path: "missing.xpi" }, + { + id: "system4@tests.mozilla.org", + version: "1.0", + path: "system4_1.xpi", + xpi: await getSystemAddonXPI(4, "1.0"), + }, + ]); + + const promiseInstallsEnded = createInstallsEndedPromise(2); + + await Promise.all([ + installSystemAddons(installXML), + promiseWebExtensionStartup("system4@tests.mozilla.org"), + ]); + + // NOTE: verifySystemAddonState does call AddonTestUtils.promiseShutdownManager + // internally, and so we need to wait for the system addons to be fully + // installed and the system addon location's stating dir to have been released. + info("Wait for system addon installs to be completed"); + await promiseInstallsEnded; + info("Wait for system addons stating dir to be released"); + await waitForSystemAddonStagingDirReleased(); + + await verifySystemAddonState( + TEST_CONDITIONS.withBothSets.initialState, + [ + { isUpgrade: false, version: "1.0" }, + { isUpgrade: true, version: "2.0" }, + { isUpgrade: false, version: null }, + { isUpgrade: true, version: "1.0" }, + { isUpgrade: false, version: null }, + ], + false, + distroDir + ); + + await promiseShutdownManager(); +}); + +// Tests that a second update before a restart works +add_task(async function test_double_update() { + await setupSystemAddonConditions(TEST_CONDITIONS.withAppSet, distroDir); + + let installXML = buildSystemAddonUpdates([ + { + id: "system2@tests.mozilla.org", + version: "2.0", + path: "system2_2.xpi", + xpi: await getSystemAddonXPI(2, "2.0"), + }, + { + id: "system3@tests.mozilla.org", + version: "1.0", + path: "system3_1.xpi", + xpi: await getSystemAddonXPI(3, "1.0"), + }, + ]); + await Promise.all([ + installSystemAddons(installXML), + promiseWebExtensionStartup("system2@tests.mozilla.org"), + promiseWebExtensionStartup("system3@tests.mozilla.org"), + ]); + + installXML = buildSystemAddonUpdates([ + { + id: "system3@tests.mozilla.org", + version: "2.0", + path: "system3_2.xpi", + xpi: await getSystemAddonXPI(3, "2.0"), + }, + { + id: "system4@tests.mozilla.org", + version: "1.0", + path: "system4_1.xpi", + xpi: await getSystemAddonXPI(4, "1.0"), + }, + ]); + await Promise.all([ + installSystemAddons(installXML), + promiseWebExtensionStartup("system3@tests.mozilla.org"), + promiseWebExtensionStartup("system4@tests.mozilla.org"), + ]); + + await verifySystemAddonState( + TEST_CONDITIONS.withAppSet.initialState, + [ + { isUpgrade: false, version: null }, + { isUpgrade: false, version: "2.0" }, + { isUpgrade: true, version: "2.0" }, + { isUpgrade: true, version: "1.0" }, + { isUpgrade: false, version: null }, + ], + true, + distroDir + ); + + await promiseShutdownManager(); +}); + +// A second update after a restart will delete the original unused set +add_task(async function test_update_purges() { + await setupSystemAddonConditions(TEST_CONDITIONS.withBothSets, distroDir); + + let installXML = buildSystemAddonUpdates([ + { + id: "system2@tests.mozilla.org", + version: "2.0", + path: "system2_2.xpi", + xpi: await getSystemAddonXPI(2, "2.0"), + }, + { + id: "system3@tests.mozilla.org", + version: "1.0", + path: "system3_1.xpi", + xpi: await getSystemAddonXPI(3, "1.0"), + }, + ]); + await Promise.all([ + installSystemAddons(installXML), + promiseWebExtensionStartup("system2@tests.mozilla.org"), + promiseWebExtensionStartup("system3@tests.mozilla.org"), + ]); + + await verifySystemAddonState( + TEST_CONDITIONS.withBothSets.initialState, + [ + { isUpgrade: false, version: "1.0" }, + { isUpgrade: true, version: "2.0" }, + { isUpgrade: true, version: "1.0" }, + { isUpgrade: false, version: null }, + { isUpgrade: false, version: null }, + ], + false, + distroDir + ); + + await installSystemAddons(buildSystemAddonUpdates(null)); + + let dirs = await getSystemAddonDirectories(); + Assert.equal(dirs.length, 1); + + await promiseShutdownManager(); +}); + +function createInstallsEndedPromise(expectedCount) { + // Addon installation triggers the execution of an un-awaited promise. We need + // to keep track of addon installs so that we can tell when these async + // processes have finished. + + return new Promise(resolve => { + let installsEnded = 0; + + const listener = { + onInstallStarted() {}, + onInstallEnded() { + installsEnded++; + + if (installsEnded === expectedCount) { + AddonManager.removeInstallListener(listener); + resolve(); + } + }, + onInstallCancelled() {}, + onInstallFailed() {}, + }; + + AddonManager.addInstallListener(listener); + }); +} + +async function waitForSystemAddonStagingDirReleased() { + // Wait for the staging dir to be released, which prevents unexpected test failure due to + // AddonTestUtils.promiseShutdownManager being mocking an AddonManager shutdown by using + // Cu.unload to unload all XPIProvider jsm modules, which would hit unexpected failures + // if done while system addon updates are still running in the background (due to the + // fact that the jsm global to have been already nuked while AddonInstall startInstall + // method may still being executed asynchronously). + + const { XPIInternal } = ChromeUtils.import( + "resource://gre/modules/addons/XPIProvider.jsm" + ); + let systemAddonLocation = XPIInternal.XPIStates.getLocation( + XPIInternal.KEY_APP_SYSTEM_ADDONS + ); + await TestUtils.waitForCondition(() => { + return systemAddonLocation.installer._stagingDirLock == 0; + }, "Wait for staging dir to be released"); +} -- cgit v1.2.3