if (!_TEST_NAME.includes("toolkit/mozapps/extensions/test/xpcshell/")) { Assert.ok( false, "head_addons.js may not be loaded by tests outside of " + "the add-on manager component."
);
}
// Maximum error in file modification times. Some file systems don't store // modification times exactly. As long as we are closer than this then it // still passes. const MAX_TIME_DIFFERENCE = 3000;
// Time to reset file modified time relative to Date.now() so we can test that // times are modified (10 hours old). const MAKE_FILE_OLD_DIFFERENCE = 10 * 3600 * 1000;
const { AddonManager, AddonManagerPrivate } = ChromeUtils.importESModule( "resource://gre/modules/AddonManager.sys.mjs"
); var { AppConstants } = ChromeUtils.importESModule( "resource://gre/modules/AppConstants.sys.mjs"
); var { FileUtils } = ChromeUtils.importESModule( "resource://gre/modules/FileUtils.sys.mjs"
); var { NetUtil } = ChromeUtils.importESModule( "resource://gre/modules/NetUtil.sys.mjs"
); var { XPCOMUtils } = ChromeUtils.importESModule( "resource://gre/modules/XPCOMUtils.sys.mjs"
); var { AddonRepository } = ChromeUtils.importESModule( "resource://gre/modules/addons/AddonRepository.sys.mjs"
);
var { AddonTestUtils, MockAsyncShutdown } = ChromeUtils.importESModule( "resource://testing-common/AddonTestUtils.sys.mjs"
);
if (method == "update") {
equal(
params.oldVersion,
lastParams.version, "params.oldVersion should match last call"
);
} else {
equal(
params.version,
lastParams.version, "params.version should match last call"
);
}
if (method !== "update" && method !== "uninstall") {
equal(
params.resourceURI.spec,
lastParams.resourceURI.spec,
`params.resourceURI should match last call`
);
checkStarted(id, version = undefined) {
let started = this.started.get(id);
ok(started, `Should have seen startup method call for ${id}`);
if (version !== undefined) {
equal(started.params.version, version, "Expected version number");
} return started;
},
checkNotStarted(id) {
ok(
!this.started.has(id),
`Should not have seen startup method call for ${id}`
);
},
checkInstalled(id, version = undefined) { const installed = this.installed.get(id);
ok(installed, `Should have seen install call for ${id}`);
if (version !== undefined) {
equal(installed.params.version, version, "Expected version number");
}
return installed;
},
checkUpdated(id, version = undefined) { const installed = this.installed.get(id);
equal(installed.method, "update", `Should have seen update call for ${id}`);
if (version !== undefined) {
equal(installed.params.version, version, "Expected version number");
}
return installed;
},
checkNotInstalled(id) {
ok(
!this.installed.has(id),
`Should not have seen install method call for ${id}`
);
},
};
async function restartWithLocales(locales) {
Services.locale.requestedLocales = locales;
await promiseRestartManager();
}
/** *ReturnsamapofAddonobjectsforinstalledadd-onswiththegiven *IDs.ThereturnedmapcontainsakeyfortheIDofeachadd-onthat *isfound.IDsforadd-onswhichdonotexistarenotpresentinthe *map. * *@param{sequence<string>}ids *Thelistofadd-onIDstoget. *@returns{Promise<string,Addon>} *Mapofadd-onsthatwerefound.
*/
async function getAddons(ids) {
let addons = new Map(); for (let addon of await AddonManager.getAddonsByIDs(ids)) { if (addon) {
addons.set(addon.id, addon);
}
} return addons;
}
/** *Checksthatthegivenadd-onhasthegivenexpectedproperties. * *@param{string}id *Theidoftheadd-on. *@param{Addon?}addon *Theadd-onobject,ornulliftheadd-ondoesnotexist. *@param{object?}expected *Anobjectcontainingtheexpectedvaluesforpropertiesofthe *add-on,ornulliftheadd-onisexpectednottoexist.
*/ function checkAddon(id, addon, expected) {
info(`Checking state of addon ${id}`);
if (expected === null) {
ok(!addon, `Addon ${id} should not exist`);
} else {
ok(addon, `Addon ${id} should exist`); for (let [key, value] of Object.entries(expected)) { if (value instanceof Ci.nsIURI) {
equal(
addon[key] && addon[key].spec,
value.spec,
`Expected value of addon.${key}`
);
} else {
deepEqual(addon[key], value, `Expected value of addon.${key}`);
}
}
}
}
/** *Teststhatanadd-ondoesappearinthecrashreportannotations,if *crashreportingisenabled.Thetestwillfailiftheadd-onisnotinthe *annotation. * *@paramaId *TheIDoftheadd-on *@paramaVersion *Theversionoftheadd-on
*/ function do_check_in_crash_annotation(aId, aVersion) { if (!AppConstants.MOZ_CRASHREPORTER) { return;
}
if (!("Add-ons" in gAppInfo.annotations)) { Assert.ok(false, "Cannot find Add-ons entry in crash annotations"); return;
}
let addons = gAppInfo.annotations["Add-ons"].split(","); Assert.ok(
addons.includes(
`${encodeURIComponent(aId)}:${encodeURIComponent(aVersion)}`
)
);
}
/** *Teststhatanadd-ondoesnotappearinthecrashreportannotations,if *crashreportingisenabled.Thetestwillfailiftheadd-onisinthe *annotation. * *@paramaId *TheIDoftheadd-on *@paramaVersion *Theversionoftheadd-on
*/ function do_check_not_in_crash_annotation(aId, aVersion) { if (!AppConstants.MOZ_CRASHREPORTER) { return;
}
if (!("Add-ons" in gAppInfo.annotations)) { Assert.ok(true); return;
}
let addons = gAppInfo.annotations["Add-ons"].split(","); Assert.ok(
!addons.includes(
`${encodeURIComponent(aId)}:${encodeURIComponent(aVersion)}`
)
);
}
function do_get_file_hash(aFile, aAlgorithm) { if (!aAlgorithm) {
aAlgorithm = "sha256";
}
let crypto = Cc["@mozilla.org/security/hash;1"].createInstance(
Ci.nsICryptoHash
);
crypto.initWithString(aAlgorithm);
let fis = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(
Ci.nsIFileInputStream
);
fis.init(aFile, -1, -1, false);
crypto.updateFromStream(fis, aFile.fileSize);
// return the two-digit hexadecimal code for a byte
let toHexString = charCode => ("0" + charCode.toString(16)).slice(-2);
let binary = crypto.finish(false);
let hash = Array.from(binary, c => toHexString(c.charCodeAt(0))); return aAlgorithm + ":" + hash.join("");
}
this.finished = new Promise(resolve => { this.resolveFinished = resolve;
});
AddonManager.addAddonListener(this); if (this.expectedInstalls) {
AddonManager.addInstallListener(this);
}
}
cleanup() {
AddonManager.removeAddonListener(this); if (this.expectedInstalls) {
AddonManager.removeInstallListener(this);
}
}
checkValue(prop, value, flagName) { if (Array.isArray(flagName)) {
let names = flagName.map(name => `AddonManager.${name}`);
Assert.ok(
flagName.map(name => AddonManager[name]).includes(value),
`${prop} value \`${value}\` should be one of [${names.join(", ")}`
);
} else { Assert.equal(
value,
AddonManager[flagName],
`${prop} should have value AddonManager.${flagName}`
);
}
}
checkFlag(prop, value, flagName) { Assert.equal(
value & AddonManager[flagName],
AddonManager[flagName],
`${prop} should have flag AddonManager.${flagName}`
);
}
checkNoFlag(prop, value, flagName) { Assert.ok(
!(value & AddonManager[flagName]),
`${prop} should not have flag AddonManager.${flagName}`
);
}
checkComplete() { if (this.expectedInstalls && this.expectedInstalls.length) { return;
}
if (Object.values(this.expectedEvents).some(events => events.length)) { return;
}
for (let [id, events] of Object.entries(this.expectedEvents)) { Assert.equal(
events.length, 0,
`Should have no remaining events for ${id}`
);
} if (this.expectedInstalls) { Assert.deepEqual( this.expectedInstalls,
[], "Should have no remaining install events"
);
}
}
// Add-on listener events
getExpectedEvent(aId) { if (!(aId in this.expectedEvents)) { returnnull;
}
let events = this.expectedEvents[aId]; Assert.ok(!!events.length, `Should be expecting events for ${aId}`);
// Install listener events.
checkInstall(event, install, details = {}) { // Lazy initialization of the plugin host means we can get spurious // install events for plugins. If we're not looking for plugin // installs, ignore them completely. If we *are* looking for plugin // installs, the onus is on the individual test to ensure it waits // for the plugin host to have done its initial work. if (this.ignorePlugins && install.type == "plugin") {
info(`Ignoring install event for plugin ${install.id}`); return undefined;
}
info(`Got install event "${event}"`);
let expected = this.expectedInstalls.shift(); Assert.ok(expected, "Should be expecting install event");
Assert.equal(
expected.event,
event, "Should be expecting onExternalInstall event"
);
if ("state" in details) { this.checkValue("install.state", install.state, details.state);
}
this.checkComplete();
if ("callback" in expected) {
expected.callback(install);
}
if ("returnValue" in expected) { return expected.returnValue;
} return undefined;
}
onNewInstall(install) {
let result = this.checkInstall("onNewInstall", install, {
state: ["STATE_DOWNLOADED", "STATE_DOWNLOAD_FAILED", "STATE_AVAILABLE"],
});
if (install.state != AddonManager.STATE_DOWNLOAD_FAILED) { Assert.equal(install.error, 0, "Should have no error");
} else { Assert.notEqual(install.error, 0, "Should have error");
}
onInstallCancelled(install) { // If the install was cancelled by a listener returning false from // onInstallStarted, then the state will revert to STATE_DOWNLOADED. returnthis.checkInstall("onInstallCancelled", install, {
state: ["STATE_CANCELED", "STATE_DOWNLOADED"],
error: 0,
});
}
onExternalInstall(addon, existingAddon, requiresRestart) { if (this.ignorePlugins && addon.type == "plugin") {
info(`Ignoring install event for plugin ${addon.id}`); return undefined;
}
let expected = this.expectedInstalls.shift(); Assert.ok(expected, "Should be expecting install event");
Assert.equal(
expected.event, "onExternalInstall", "Should be expecting onExternalInstall event"
); Assert.ok(!requiresRestart, "Should never require restart");
this.checkComplete(); if ("returnValue" in expected) { return expected.returnValue;
} return undefined;
}
}
/** *Runthegivingcallbackfunction,andexpectthegivensetofadd-on *andinstalllistenereventstobeemitted,andreturnsapromise *whichresolveswhentheyhaveallbeenobserved. * *If`callback`returnsapromise,alleventsareexpectedtobe *observedbythetimethepromiseresolves.Ifnot,simplywaitsfor *alleventstobeobservedbeforeresolvingthereturnedpromise. * *@param{object}details *@param{function}callback *@returns{Promise}
*/ /* exported expectEvents */
async function expectEvents(details, callback) {
let checker = new EventChecker(details);
try {
let result = callback();
if (
result && typeof result === "object" && typeof result.then === "function"
) {
result = await result;
checker.ensureComplete();
} else {
await checker.finished;
}
/** *ChangetheschemaversionoftheJSONextensionsdatabase
*/
async function changeXPIDBVersion(aNewVersion) {
let json = await IOUtils.readJSON(gExtensionsJSON.path);
json.schemaVersion = aNewVersion;
await IOUtils.writeJSON(gExtensionsJSON.path, json);
}
async function setInitialState(addon, initialState) { if (initialState.userDisabled) {
await addon.disable();
} elseif (initialState.userDisabled === false) {
await addon.enable();
}
}
async function setupBuiltinExtension(extensionData, location = "ext-test") {
let xpi = await AddonTestUtils.createTempWebExtensionFile(extensionData);
// The built-in location requires a resource: URL that maps to a // jar: or file: URL. This would typically be something bundled // into omni.ja but for testing we just use a temp file.
let base = Services.io.newURI(`jar:file:${xpi.path}!/`);
let resProto = Services.io
.getProtocolHandler("resource")
.QueryInterface(Ci.nsIResProtocolHandler);
resProto.setSubstitution(location, base);
}
async function installBuiltinExtension(extensionData, waitForStartup = true) {
await setupBuiltinExtension(extensionData);
let id =
extensionData.manifest?.browser_specific_settings?.gecko?.id ||
extensionData.manifest?.applications?.gecko?.id;
let wrapper = ExtensionTestUtils.expectExtension(id);
await AddonManager.installBuiltinAddon("resource://ext-test/"); if (waitForStartup) {
await wrapper.awaitStartup();
} return wrapper;
}
function useAMOStageCert() { // NOTE: add_task internally calls add_test which mutate the add_task properties object, // and so we should not reuse the same object as add_task options passed to multiple // add_task calls. return { pref_set: [["xpinstall.signatures.dev-root", true]] };
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.20 Sekunden
(vorverarbeitet am 2026-08-26)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.