/* import-globals-from head_addons.js */
const PREF_SYSTEM_ADDON_SET = "extensions.systemAddonSet";
const PREF_SYSTEM_ADDON_UPDATE_URL = "extensions.systemAddon.update.url";
const PREF_SYSTEM_ADDON_UPDATE_ENABLED =
"extensions.systemAddon.update.enabled";
// See bug 1507255
Services.prefs.setBoolPref("media.gmp-manager.updateEnabled", true);
function root(server) {
let { primaryScheme, primaryHost, primaryPort } = server.identity;
return `${primaryScheme}://${primaryHost}:${primaryPort}/data`;
}
ChromeUtils.defineLazyGetter(this, "testserver", () => {
let server = new HttpServer();
server.start();
Services.prefs.setCharPref(
PREF_SYSTEM_ADDON_UPDATE_URL,
`${root(server)}/update.xml`
);
return server;
});
async function serveSystemUpdate(xml, perform_update) {
testserver.registerPathHandler("/data/update.xml", (request, response) => {
response.write(xml);
});
try {
await perform_update();
} finally {
testserver.registerPathHandler("/data/update.xml", null);
}
}
// Runs an update check making it use the passed in xml string. Uses the direct
// call to the update function so we get rejections on failure.
async function installSystemAddons(xml, waitIDs = []) {
info("Triggering system add-on update check.");
await serveSystemUpdate(
xml,
async function () {
let { XPIExports } = ChromeUtils.importESModule(
"resource://gre/modules/addons/XPIExports.sys.mjs"
);
await Promise.all([
XPIExports.XPIProvider.updateSystemAddons(),
...waitIDs.map(id => promiseWebExtensionStartup(id)),
]);
},
testserver
);
}
// Runs a full add-on update check which will in some cases do a system add-on
// update check. Always succeeds.
async function updateAllSystemAddons(xml) {
info("Triggering full add-on update check.");
await serveSystemUpdate(
xml,
function () {
return new Promise(resolve => {
Services.obs.addObserver(function observer() {
Services.obs.removeObserver(
observer,
"addons-background-update-complete"
);
resolve();
}, "addons-background-update-complete");
// Trigger the background update timer handler
gInternalManager.notify(null);
});
},
testserver
);
}
// Builds an update.xml file for an update check based on the data passed.
function buildSystemAddonUpdates(addons) {
let xml = `\n\n\n`;
if (addons) {
xml += ` \n`;
for (let addon of addons) {
if (addon.xpi) {
testserver.registerFile(`/data/${addon.path}`, addon.xpi);
}
xml += ` \n`;
}
xml += ` \n`;
}
xml += `\n`;
return xml;
}
let _systemXPIs = new Map();
function getSystemAddonXPI(num, version) {
let key = `${num}:${version}`;
if (!_systemXPIs.has(key)) {
_systemXPIs.set(
key,
AddonTestUtils.createTempWebExtensionFile({
manifest: {
name: `System Add-on ${num}`,
version,
browser_specific_settings: {
gecko: {
id: `system${num}@tests.mozilla.org`,
},
},
},
})
);
}
return _systemXPIs.get(key);
}
async function promiseUpdateSystemAddonsSet(systemAddonUpdates) {
const waitForStartupIDs = new Set();
let promises = [];
let updates = [];
for (const { id, version, waitForStartup = true } of systemAddonUpdates) {
let xpi = AddonTestUtils.createTempWebExtensionFile({
manifest: {
version,
browser_specific_settings: {
gecko: { id },
},
},
});
updates.push({ id, version, xpi, path: xpi.leafName });
if (waitForStartup) {
waitForStartupIDs.add(id);
} else {
// If we're not expecting a startup we need to wait for install to end.
promises.push(
AddonTestUtils.promiseAddonEvent(
"onInstalled",
addon => addon.id === id
)
);
}
}
let xml = buildSystemAddonUpdates(updates);
promises.push(installSystemAddons(xml, Array.from(waitForStartupIDs)));
return Promise.all(promises);
}
async function promiseUpdateSystemAddon(id, version, waitForStartup = true) {
const ADDON_ID = "updates@test";
return promiseUpdateSystemAddonsSet([
{
id: id ?? ADDON_ID,
version,
waitForStartup,
},
]);
}
async function getSystemBuiltin(num, addon_version, res_url) {
const id = `system${num}@tests.mozilla.org`;
const version = addon_version ?? "1.0";
const addon_res_url_path = res_url ?? `builtin-system${num}`;
await setupBuiltinExtension(
{
manifest: {
name: `Built-in add-on #${num}`,
version,
browser_specific_settings: { gecko: { id } },
},
},
addon_res_url_path
);
return {
addon_id: id,
addon_version: version,
res_url: `resource://${addon_res_url_path}/`,
};
}
async function initSystemAddonDirs() {
let hiddenSystemAddonDir = FileUtils.getDir("ProfD", [
"sysfeatures",
"hidden",
]);
hiddenSystemAddonDir.create(
Ci.nsIFile.DIRECTORY_TYPE,
FileUtils.PERMS_DIRECTORY
);
let system1_1 = await getSystemAddonXPI(1, "1.0");
system1_1.copyTo(hiddenSystemAddonDir, "system1@tests.mozilla.org.xpi");
let system2_1 = await getSystemAddonXPI(2, "1.0");
system2_1.copyTo(hiddenSystemAddonDir, "system2@tests.mozilla.org.xpi");
let prefilledSystemAddonDir = FileUtils.getDir("ProfD", [
"sysfeatures",
"prefilled",
]);
prefilledSystemAddonDir.create(
Ci.nsIFile.DIRECTORY_TYPE,
FileUtils.PERMS_DIRECTORY
);
let system2_2 = await getSystemAddonXPI(2, "2.0");
system2_2.copyTo(prefilledSystemAddonDir, "system2@tests.mozilla.org.xpi");
let system3_2 = await getSystemAddonXPI(3, "2.0");
system3_2.copyTo(prefilledSystemAddonDir, "system3@tests.mozilla.org.xpi");
}
/**
* Returns current system add-on update directory (stored in pref).
*/
function getCurrentSystemAddonUpdatesDir() {
const updatesDir = FileUtils.getDir("ProfD", ["features"]);
let dir = updatesDir.clone();
let set = JSON.parse(Services.prefs.getCharPref(PREF_SYSTEM_ADDON_SET));
dir.append(set.directory);
return dir;
}
/**
* Removes all files from system add-on update directory.
*/
function clearSystemAddonUpdatesDir() {
const updatesDir = FileUtils.getDir("ProfD", ["features"]);
// Delete any existing directories
if (updatesDir.exists()) {
updatesDir.remove(true);
}
Services.prefs.clearUserPref(PREF_SYSTEM_ADDON_SET);
}
registerCleanupFunction(() => {
clearSystemAddonUpdatesDir();
});
/**
* Installs a known set of add-ons into the system add-on update directory.
*/
async function buildPrefilledUpdatesDir() {
clearSystemAddonUpdatesDir();
// Build the test set
let dir = FileUtils.getDir("ProfD", ["features", "prefilled"]);
dir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
let xpi = await getSystemAddonXPI(2, "2.0");
xpi.copyTo(dir, "system2@tests.mozilla.org.xpi");
xpi = await getSystemAddonXPI(3, "2.0");
xpi.copyTo(dir, "system3@tests.mozilla.org.xpi");
// Mark these in the past so the startup file scan notices when files have changed properly
{
let toModify = await IOUtils.getFile(
PathUtils.profileDir,
"features",
"prefilled",
"system2@tests.mozilla.org.xpi"
);
toModify.lastModifiedTime -= 10000;
toModify = await IOUtils.getFile(
PathUtils.profileDir,
"features",
"prefilled",
"system3@tests.mozilla.org.xpi"
);
toModify.lastModifiedTime -= 10000;
}
Services.prefs.setCharPref(
PREF_SYSTEM_ADDON_SET,
JSON.stringify({
schema: 1,
directory: dir.leafName,
addons: {
"system2@tests.mozilla.org": {
version: "2.0",
},
"system3@tests.mozilla.org": {
version: "2.0",
},
},
})
);
}
/**
* Check currently installed ssystem add-ons against a set of conditions.
*
* @param {Array