1
0
Fork 0
firefox/toolkit/mozapps/extensions/test/xpcshell/test_system_upgrades.js
Daniel Baumann 5e9a113729
Adding upstream version 140.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-25 09:37:52 +02:00

468 lines
15 KiB
JavaScript

"use strict";
// Enable SCOPE_APPLICATION for builtin testing. Default in tests is only SCOPE_PROFILE.
let scopes = AddonManager.SCOPE_PROFILE | AddonManager.SCOPE_APPLICATION;
Services.prefs.setIntPref("extensions.enabledScopes", scopes);
AddonTestUtils.createAppInfo(
"xpcshell@tests.mozilla.org",
"XPCShell",
"42",
"42"
);
BootstrapMonitor.init();
// A test directory for default/builtin system addons.
const systemDefaults = FileUtils.getDir("ProfD", [
"app-system-defaults",
"features",
]);
systemDefaults.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
registerDirectory("XREAppFeat", systemDefaults);
AddonTestUtils.usePrivilegedSignatures = () => "system";
const ADDON_ID = "updates@test";
// The test extension uses an insecure update url.
Services.prefs.setBoolPref("extensions.checkUpdateSecurity", false);
let server = createHttpServer();
server.registerPathHandler("/upgrade.json", (request, response) => {
response.setStatusLine(request.httpVersion, 200, "ok");
response.write(
JSON.stringify({
addons: {
[ADDON_ID]: {
updates: [
{
version: "4.0",
update_link: `http://localhost:${server.identity.primaryPort}/${ADDON_ID}.xpi`,
},
],
},
},
})
);
});
function createWebExtensionFile(id, version, update_url) {
return AddonTestUtils.createTempWebExtensionFile({
manifest: {
version,
browser_specific_settings: {
gecko: { id, update_url },
},
},
});
}
let xpiUpdate = createWebExtensionFile(ADDON_ID, "4.0");
server.registerFile(`/${ADDON_ID}.xpi`, xpiUpdate);
async function promiseInstallDefaultSystemAddon(id, version) {
let xpi = createWebExtensionFile(id, version);
await AddonTestUtils.manuallyInstall(xpi, systemDefaults);
return xpi;
}
async function promiseInstallProfileExtension(id, version, update_url) {
return promiseInstallWebExtension({
manifest: {
version,
browser_specific_settings: {
gecko: { id, update_url },
},
},
});
}
async function promiseInstallSystemProfileAddon(id, version) {
let xpi = createWebExtensionFile(id, version);
const install = await AddonManager.getInstallForURL(`file://${xpi.path}`, {
useSystemLocation: true, // KEY_APP_SYSTEM_PROFILE
});
return install.install();
}
async function promiseClearSystemAddons() {
let xml = buildSystemAddonUpdates([]);
return installSystemAddons(xml, []);
}
const builtInOverride = { system: [ADDON_ID], builtins: [] };
async function checkAddon(version, reason, startReason = reason) {
let addons = await AddonManager.getAddonsByTypes(["extension"]);
Assert.equal(addons.length, 1, "one addon expected to be installed");
Assert.equal(addons[0].version, version, `addon ${version} is installed`);
Assert.ok(addons[0].isActive, `addon ${version} is active`);
Assert.ok(!addons[0].disabled, `addon ${version} is enabled`);
let installInfo = BootstrapMonitor.checkInstalled(ADDON_ID, version);
equal(
installInfo.reason,
reason,
`bootstrap monitor verified install reason for ${version}`
);
let started = BootstrapMonitor.checkStarted(ADDON_ID, version);
equal(
started.reason,
startReason,
`bootstrap monitor verified started reason for ${version}`
);
return addons[0];
}
/**
* This test function starts after a 1.0 version of an addon is installed
* either as a builtin ("app-builtin") or as a builtin system addon ("app-system-defaults").
*
* This tests the precedence chain works as expected through upgrades and
* downgrades.
*
* Upgrade to a system addon in the profile location, "app-system-addons"
* Upgrade to a temporary addon
* Uninstalling the temporary addon downgrades to the system addon in "app-system-addons".
* Upgrade to a system addon in the "app-system-profile" location.
* Uninstalling the "app-system-profile" addon downgrades to the one in "app-system-addons".
* Upgrade to a user-installed addon
* Upgrade the addon in "app-system-addons", verify user-install is still active
* Uninstall the addon in "app-system-addons", verify user-install is active
* Test that the update_url upgrades the user-install and becomes active
* Disable the user-install, verify the disabled addon retains precedence
* Uninstall the disabled user-install, verify system addon in "app-system-defaults" is active and enabled
* Upgrade the system addon again, then user-install a lower version, verify downgrade happens.
* Uninstall user-install, verify upgrade happens when the system addon in "app-system-addons" is activated.
*/
async function _test_builtin_addon_override() {
/////
// Upgrade to a system addon in the profile location, "app-system-addons"
/////
await promiseUpdateSystemAddon(ADDON_ID, "2.0");
await checkAddon("2.0", BOOTSTRAP_REASONS.ADDON_UPGRADE);
/////
// Upgrade to a temporary addon
/////
let tmpAddon = createWebExtensionFile(ADDON_ID, "2.1");
await Promise.all([
AddonManager.installTemporaryAddon(tmpAddon),
AddonTestUtils.promiseWebExtensionStartup(ADDON_ID),
]);
let addon = await checkAddon("2.1", BOOTSTRAP_REASONS.ADDON_UPGRADE);
/////
// Downgrade back to the system addon
/////
await addon.uninstall();
await checkAddon("2.0", BOOTSTRAP_REASONS.ADDON_DOWNGRADE);
/////
// Install then uninstall an system profile addon
/////
info("Install an System Profile Addon, then uninstall it.");
await Promise.all([
promiseInstallSystemProfileAddon(ADDON_ID, "2.2"),
AddonTestUtils.promiseWebExtensionStartup(ADDON_ID),
]);
addon = await checkAddon("2.2", BOOTSTRAP_REASONS.ADDON_UPGRADE);
await addon.uninstall();
await checkAddon("2.0", BOOTSTRAP_REASONS.ADDON_DOWNGRADE);
/////
// Upgrade to a user-installed addon
/////
await Promise.all([
promiseInstallProfileExtension(
ADDON_ID,
"3.0",
`http://localhost:${server.identity.primaryPort}/upgrade.json`
),
AddonTestUtils.promiseWebExtensionStartup(ADDON_ID),
]);
await checkAddon("3.0", BOOTSTRAP_REASONS.ADDON_UPGRADE);
/////
// Upgrade the system addon, verify user-install is still active
/////
await promiseUpdateSystemAddon(ADDON_ID, "2.2", false);
await checkAddon("3.0", BOOTSTRAP_REASONS.ADDON_UPGRADE);
/////
// Uninstall the system addon, verify user-install is active
/////
await Promise.all([
promiseClearSystemAddons(),
AddonTestUtils.promiseAddonEvent("onUninstalled"),
]);
addon = await checkAddon("3.0", BOOTSTRAP_REASONS.ADDON_UPGRADE);
/////
// Test that the update_url upgrades the user-install and becomes active
/////
let update = await promiseFindAddonUpdates(addon);
await Promise.all([
promiseCompleteAllInstalls([update.updateAvailable]),
AddonTestUtils.promiseWebExtensionStartup(ADDON_ID),
]);
addon = await checkAddon("4.0", BOOTSTRAP_REASONS.ADDON_UPGRADE);
/////
// Disable the user-install, verify the disabled addon retains precedence
/////
await addon.disable();
await AddonManager.getAddonByID(ADDON_ID);
Assert.ok(!addon.isActive, "4.0 is disabled");
Assert.equal(
addon.version,
"4.0",
"version 4.0 is still the visible version"
);
/////
// Uninstall the disabled user-install, verify system addon is active and enabled
/////
await Promise.all([
addon.uninstall(),
AddonTestUtils.promiseWebExtensionStartup(ADDON_ID),
]);
// We've downgraded all the way to 1.0 from a user-installed addon
addon = await checkAddon("1.0", BOOTSTRAP_REASONS.ADDON_DOWNGRADE);
/////
// Upgrade the system addon again, then user-install a lower version, verify downgrade happens.
/////
await promiseUpdateSystemAddon(ADDON_ID, "5.1");
addon = await checkAddon("5.1", BOOTSTRAP_REASONS.ADDON_UPGRADE);
// user-install a lower version, downgrade happens
await Promise.all([
promiseInstallProfileExtension(ADDON_ID, "5.0"),
AddonTestUtils.promiseWebExtensionStartup(ADDON_ID),
]);
addon = await checkAddon("5.0", BOOTSTRAP_REASONS.ADDON_DOWNGRADE);
/////
// Uninstall user-install, verify upgrade happens when system addon is activated.
/////
await Promise.all([
addon.uninstall(),
AddonTestUtils.promiseWebExtensionStartup(ADDON_ID),
]);
// the "system add-on upgrade" is now revealed
addon = await checkAddon("5.1", BOOTSTRAP_REASONS.ADDON_UPGRADE);
await Promise.all([
addon.uninstall(),
AddonTestUtils.promiseWebExtensionStartup(ADDON_ID),
]);
await checkAddon("1.0", BOOTSTRAP_REASONS.ADDON_DOWNGRADE);
// Downgrading from an installed system addon to a default system
// addon also requires the removal of the file on disk, and removing
// the addon from the pref.
Services.prefs.clearUserPref(PREF_SYSTEM_ADDON_SET);
}
// Run the test again, but starting from a "builtin" addon location
add_task(async function test_manually_installed_builtin_addon_upgrades() {
builtInOverride.system = [];
builtInOverride.builtins = [];
await AddonTestUtils.overrideBuiltIns(builtInOverride);
await AddonTestUtils.promiseStartupManager();
await Promise.all([
installBuiltinExtension({
manifest: {
version: "1.0",
browser_specific_settings: {
gecko: { id: ADDON_ID },
},
},
}),
AddonTestUtils.promiseWebExtensionStartup(ADDON_ID),
]);
await checkAddon("1.0", BOOTSTRAP_REASONS.ADDON_INSTALL);
await _test_builtin_addon_override();
// cleanup the builtin addon manually installed in the builtin location.
let addon = await AddonManager.getAddonByID(ADDON_ID);
await addon.uninstall();
await AddonTestUtils.promiseShutdownManager();
BootstrapMonitor.clear(ADDON_ID);
});
// Run the test again, but starting from a "builtin" addon location
add_task(async function test_auto_installed_builtin_addon_upgrades() {
const ADDON_VERSION = "1.0";
const builtinExtensionDefinitions = {
manifest: {
version: ADDON_VERSION,
browser_specific_settings: {
gecko: { id: ADDON_ID },
},
},
};
await setupBuiltinExtension(builtinExtensionDefinitions, "test-builtin-ext");
builtInOverride.system = [];
builtInOverride.builtins = [
{
addon_id: ADDON_ID,
addon_version: ADDON_VERSION,
res_url: "resource://test-builtin-ext/",
},
];
await AddonTestUtils.overrideBuiltIns(builtInOverride);
await Promise.all([
AddonTestUtils.promiseWebExtensionStartup(ADDON_ID),
AddonTestUtils.promiseStartupManager(),
]);
await checkAddon(ADDON_VERSION, BOOTSTRAP_REASONS.ADDON_INSTALL);
await _test_builtin_addon_override();
// cleanup the system addon auto-installed in the locked system builtin location
await AddonTestUtils.overrideBuiltIns({ system: [], builtins: [] });
await AddonTestUtils.promiseRestartManager();
await AddonTestUtils.promiseShutdownManager();
BootstrapMonitor.clear(ADDON_ID);
});
add_task(async function test_builtin_addon_version_precedence() {
builtInOverride.system = [];
builtInOverride.builtins = [];
await AddonTestUtils.overrideBuiltIns(builtInOverride);
await AddonTestUtils.promiseStartupManager();
await Promise.all([
installBuiltinExtension({
manifest: {
version: "1.0",
browser_specific_settings: {
gecko: { id: ADDON_ID },
},
},
}),
AddonTestUtils.promiseWebExtensionStartup(ADDON_ID),
]);
await checkAddon("1.0", BOOTSTRAP_REASONS.ADDON_INSTALL);
/////
// Upgrade to a system addon in the profile location, "app-system-addons"
/////
await promiseUpdateSystemAddon(ADDON_ID, "2.0");
await checkAddon("2.0", BOOTSTRAP_REASONS.ADDON_UPGRADE);
/////
// Builtin addon is changed, the system addon should still have precedence.
/////
await Promise.all([
installBuiltinExtension(
{
manifest: {
version: "1.5",
browser_specific_settings: {
gecko: { id: ADDON_ID },
},
},
},
false
),
AddonTestUtils.promiseAddonEvent("onInstalled"),
]);
await checkAddon("2.0", BOOTSTRAP_REASONS.ADDON_UPGRADE);
// Uninstall the system addon update.
let addon = await AddonManager.getAddonByID(ADDON_ID);
await addon.uninstall();
// Uninstall the addon version 1.5 manually installed in the builtin location.
addon = await AddonManager.getAddonByID(ADDON_ID);
Assert.equal(
addon?.version,
"1.5",
"Expect builtin addon v1.5 to become visible"
);
await addon.uninstall();
await AddonTestUtils.promiseShutdownManager();
BootstrapMonitor.clear(ADDON_ID);
});
// Same as test_system_addon_precedence but with the system addon
// bundled in the omni jar instead of an xpi installed in the
// app-system-defaults directory location.
add_task(async function test_systembuiltin_addon_version_precedence() {
const ADDON_VERSION = "1.0";
const builtinExtensionDefinitions = {
manifest: {
version: ADDON_VERSION,
browser_specific_settings: {
gecko: { id: ADDON_ID },
},
},
};
await setupBuiltinExtension(builtinExtensionDefinitions, "test-builtin-ext");
builtInOverride.system = [];
builtInOverride.builtins = [
{
addon_id: ADDON_ID,
addon_version: ADDON_VERSION,
res_url: "resource://test-builtin-ext/",
},
];
await AddonTestUtils.overrideBuiltIns(builtInOverride);
await Promise.all([
AddonTestUtils.promiseWebExtensionStartup(ADDON_ID),
AddonTestUtils.promiseStartupManager("1"),
]);
await checkAddon("1.0", BOOTSTRAP_REASONS.ADDON_INSTALL);
/////
// Upgrade to a system addon in the profile location, "app-system-addons"
/////
await promiseUpdateSystemAddon(ADDON_ID, "2.0");
await checkAddon("2.0", BOOTSTRAP_REASONS.ADDON_UPGRADE);
/////
// Prepare an updated system builtin version to mock an app update.
/////
builtinExtensionDefinitions.manifest.version = "1.5";
await setupBuiltinExtension(builtinExtensionDefinitions, "test-builtin-ext");
builtInOverride.builtins[0].addon_version = "1.5";
await AddonTestUtils.overrideBuiltIns(builtInOverride);
/////
// Builtin system addon is changed, it has precedence because when this
// happens we remove all prior system addon upgrades.
/////
await AddonTestUtils.promiseShutdownManager();
await AddonTestUtils.overrideBuiltIns(builtInOverride);
await promiseInstallDefaultSystemAddon(ADDON_ID, "1.5");
await AddonTestUtils.promiseStartupManager("2");
await checkAddon(
"1.5",
BOOTSTRAP_REASONS.ADDON_DOWNGRADE,
BOOTSTRAP_REASONS.APP_STARTUP
);
// Mock a new system addon update check
await promiseUpdateSystemAddon(ADDON_ID, "2.0");
await checkAddon("2.0", BOOTSTRAP_REASONS.ADDON_UPGRADE);
// cleanup the system addon auto-installed in the locked system builtin location
await AddonTestUtils.overrideBuiltIns({ system: [], builtins: [] });
await AddonTestUtils.promiseRestartManager();
await AddonTestUtils.promiseShutdownManager();
BootstrapMonitor.clear(ADDON_ID);
});