forked from mirrors/gecko-dev
492 lines
14 KiB
JavaScript
492 lines
14 KiB
JavaScript
// Tests that system add-on upgrades work.
|
|
|
|
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "2");
|
|
|
|
let distroDir = FileUtils.getDir("ProfD", ["sysfeatures", "empty"]);
|
|
distroDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
|
|
registerDirectory("XREAppFeat", distroDir);
|
|
|
|
AddonTestUtils.usePrivilegedSignatures = () => "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 testing functions to re-import XPIProvider,
|
|
// XPIDatabase, and XPIInstall modules, which would hit unexpected failures
|
|
// if done while system addon updates are still running in the background.
|
|
|
|
const { XPIExports } = ChromeUtils.importESModule(
|
|
"resource://gre/modules/addons/XPIExports.sys.mjs"
|
|
);
|
|
let systemAddonLocation = XPIExports.XPIInternal.XPIStates.getLocation(
|
|
XPIExports.XPIInternal.KEY_APP_SYSTEM_ADDONS
|
|
);
|
|
await TestUtils.waitForCondition(() => {
|
|
return systemAddonLocation.installer._stagingDirLock == 0;
|
|
}, "Wait for staging dir to be released");
|
|
}
|