--- a/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
+++ b/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
@@ -5,18 +5,16 @@
/* eslint "mozilla/no-aArgs": 1 */
/* eslint "no-unused-vars": [2, {"args": "none", "varsIgnorePattern": "^(Cc|Ci|Cr|Cu|EXPORTED_SYMBOLS)$"}] */
/* eslint "semi": [2, "always"] */
/* eslint "valid-jsdoc": [2, {requireReturn: false}] */
var EXPORTED_SYMBOLS = ["AddonTestUtils", "MockAsyncShutdown"];
const CERTDB_CONTRACTID = "@mozilla.org/security/x509certdb;1";
-const CERTDB_CID = Components.ID("{fb0bbc5c-452e-4783-b32c-80124693d871}");
-
Cu.importGlobalProperties(["fetch", "TextEncoder"]);
ChromeUtils.import("resource://gre/modules/AsyncShutdown.jsm");
ChromeUtils.import("resource://gre/modules/FileUtils.jsm");
ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
@@ -30,16 +28,18 @@ XPCOMUtils.defineLazyGetter(this, "Manag
let {Management} = ChromeUtils.import("resource://gre/modules/Extension.jsm", {});
return Management;
});
ChromeUtils.defineModuleGetter(this, "FileTestUtils",
"resource://testing-common/FileTestUtils.jsm");
ChromeUtils.defineModuleGetter(this, "HttpServer",
"resource://testing-common/httpd.js");
+ChromeUtils.defineModuleGetter(this, "MockRegistrar",
+ "resource://testing-common/MockRegistrar.jsm");
XPCOMUtils.defineLazyServiceGetters(this, {
aomStartup: ["@mozilla.org/addons/addon-manager-startup;1", "amIAddonManagerStartup"],
proxyService: ["@mozilla.org/network/protocol-proxy-service;1", "nsIProtocolProxyService"],
rdfService: ["@mozilla.org/rdf/rdf-service;1", "nsIRDFService"],
uuidGen: ["@mozilla.org/uuid-generator;1", "nsIUUIDGenerator"],
});
@@ -97,16 +97,63 @@ var MockAsyncShutdown = {
}
},
// We can use the real Barrier
Barrier: AsyncShutdown.Barrier,
};
AMscope.AsyncShutdown = MockAsyncShutdown;
+class MockBlocklist {
+ constructor(addons) {
+ if (ChromeUtils.getClassName(addons) === "Object") {
+ addons = new Map(Object.entries(addons));
+ }
+ this.addons = addons;
+ }
+
+ get contractID() {
+ return "@mozilla.org/extensions/blocklist;1";
+ }
+
+ register() {
+ this.originalCID = MockRegistrar.register(this.contractID, this);
+ }
+
+ unregister() {
+ MockRegistrar.unregister(this.originalCID);
+ }
+
+ getAddonBlocklistState(addon, appVersion, toolkitVersion) {
+ return this.addons.get(addon.id, Ci.nsIBlocklistService.STATE_NOT_BLOCKED);
+ }
+
+ getAddonBlocklistEntry(addon, appVersion, toolkitVersion) {
+ let state = this.getAddonBlocklistState(addon, appVersion, toolkitVersion);
+ if (state != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) {
+ return {
+ state,
+ url: "http://example.com/",
+ };
+ }
+ return null;
+ }
+
+ getPluginBlocklistState(plugin, version, appVersion, toolkitVersion) {
+ return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
+ }
+
+ isAddonBlocklisted(addon, appVersion, toolkitVersion) {
+ return this.getAddonBlocklistState(addon, appVersion, toolkitVersion) ==
+ Ci.nsIBlocklistService.STATE_BLOCKED;
+ }
+}
+
+MockBlocklist.prototype.QueryInterface = XPCOMUtils.generateQI(["nsIBlocklistService"]);
+
/**
* Escapes any occurances of &, ", < or > with XML entities.
*
* @param {string} str
* The string to escape.
* @return {string} The escaped string.
*/
@@ -567,26 +614,16 @@ var AddonTestUtils = {
} catch (e) {
// IDs for WebExtensions are extracted from the certificate when
// not present in the manifest, so just generate a random one.
return uuidGen.generateUUID().number;
}
},
overrideCertDB() {
- // Unregister the real database. This only works because the add-ons manager
- // hasn't started up and grabbed the certificate database yet.
- let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
- let factory = registrar.getClassObject(CERTDB_CID, Ci.nsIFactory);
- registrar.unregisterFactory(CERTDB_CID, factory);
-
- // Get the real DB
- let realCertDB = factory.createInstance(null, Ci.nsIX509CertDB);
-
-
let verifyCert = async (file, result, cert, callback) => {
if (result == Cr.NS_ERROR_SIGNED_JAR_NOT_SIGNED &&
!this.useRealCertChecks && callback.wrappedJSObject) {
// Bypassing XPConnect allows us to create a fake x509 certificate from JS
callback = callback.wrappedJSObject;
try {
let manifestURI = this.getManifestURI(file);
@@ -610,53 +647,73 @@ var AddonTestUtils = {
if (file.isFile())
Services.obs.notifyObservers(file, "flush-cache-entry", "cert-override");
}
}
return [callback, result, cert];
};
-
- function FakeCertDB() {
- for (let property of Object.keys(realCertDB)) {
- if (property in this)
- continue;
+ let FakeCertDB = {
+ init() {
+ for (let property of Object.keys(this._genuine.QueryInterface(Ci.nsIX509CertDB))) {
+ if (property in this)
+ continue;
- if (typeof realCertDB[property] == "function")
- this[property] = realCertDB[property].bind(realCertDB);
- }
- }
- FakeCertDB.prototype = {
+ if (typeof this._genuine[property] == "function")
+ this[property] = this._genuine[property].bind(this._genuine);
+ }
+ },
+
openSignedAppFileAsync(root, file, callback) {
// First try calling the real cert DB
- realCertDB.openSignedAppFileAsync(root, file, (result, zipReader, cert) => {
+ this._genuine.openSignedAppFileAsync(root, file, (result, zipReader, cert) => {
verifyCert(file.clone(), result, cert, callback)
.then(([callback, result, cert]) => {
callback.openSignedAppFileFinished(result, zipReader, cert);
});
});
},
verifySignedDirectoryAsync(root, dir, callback) {
// First try calling the real cert DB
- realCertDB.verifySignedDirectoryAsync(root, dir, (result, cert) => {
+ this._genuine.verifySignedDirectoryAsync(root, dir, (result, cert) => {
verifyCert(dir.clone(), result, cert, callback)
.then(([callback, result, cert]) => {
callback.verifySignedDirectoryFinished(result, cert);
});
});
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIX509CertDB]),
};
- let certDBFactory = XPCOMUtils.generateSingletonFactory(FakeCertDB);
- registrar.registerFactory(CERTDB_CID, "CertDB",
- CERTDB_CONTRACTID, certDBFactory);
+ // Unregister the real database. This only works because the add-ons manager
+ // hasn't started up and grabbed the certificate database yet.
+ MockRegistrar.register(CERTDB_CONTRACTID, FakeCertDB);
+
+ // Initialize the mock service.
+ Cc[CERTDB_CONTRACTID].getService();
+ FakeCertDB.init();
+ },
+
+ /**
+ * Overrides the blocklist service, and returns the given blocklist
+ * states for the given add-ons.
+ *
+ * @param {object|Map} addons
+ * A mapping of add-on IDs to their blocklist states.
+ * @returns {MockBlocklist}
+ * A mock blocklist service, which should be unregistered when
+ * the test is complete.
+ */
+ overrideBlocklist(addons) {
+ let mock = new MockBlocklist(addons);
+ mock.register();
+ return mock;
},
/**
* Starts up the add-on manager as if it was started by the application.
*
* @param {boolean} [appChanged = true]
* An optional boolean parameter to simulate the case where the
* application has changed version since the last run. If not passed it
deleted file mode 100644
--- a/toolkit/mozapps/extensions/test/xpcshell/test_bug335238.js
+++ /dev/null
@@ -1,227 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-// Disables security checking our updates which haven't been signed
-Services.prefs.setBoolPref("extensions.checkUpdateSecurity", false);
-
-ChromeUtils.import("resource://testing-common/MockRegistrar.jsm");
-
-// This is the data we expect to see sent as part of the update url.
-var EXPECTED = [
- {
- id: "bug335238_1@tests.mozilla.org",
- version: "1.3.4",
- maxAppVersion: "5",
- status: "userEnabled",
- appId: "xpcshell@tests.mozilla.org",
- appVersion: "1",
- appOs: "XPCShell",
- appAbi: "noarch-spidermonkey",
- locale: "en-US",
- reqVersion: "2"
- },
- {
- id: "bug335238_2@tests.mozilla.org",
- version: "28at",
- maxAppVersion: "7",
- status: "userDisabled",
- appId: "xpcshell@tests.mozilla.org",
- appVersion: "1",
- appOs: "XPCShell",
- appAbi: "noarch-spidermonkey",
- locale: "en-US",
- reqVersion: "2"
- },
- {
- id: "bug335238_3@tests.mozilla.org",
- version: "58",
- maxAppVersion: "*",
- status: "userDisabled,softblocked",
- appId: "xpcshell@tests.mozilla.org",
- appVersion: "1",
- appOs: "XPCShell",
- appAbi: "noarch-spidermonkey",
- locale: "en-US",
- reqVersion: "2"
- },
- {
- id: "bug335238_4@tests.mozilla.org",
- version: "4",
- maxAppVersion: "2+",
- status: "userEnabled,blocklisted",
- appId: "xpcshell@tests.mozilla.org",
- appVersion: "1",
- appOs: "XPCShell",
- appAbi: "noarch-spidermonkey",
- locale: "en-US",
- reqVersion: "2"
- }
-];
-
-const MANIFESTS = [
- {
- id: "bug335238_1@tests.mozilla.org",
- version: "1.3.4",
- name: "Bug 335238",
- updateURL: "http://example.com/0?id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appId=%APP_ID%&appVersion=%APP_VERSION%&appOs=%APP_OS%&appAbi=%APP_ABI%&locale=%APP_LOCALE%&reqVersion=%REQ_VERSION%",
- bootstrap: true,
-
- targetApplications: [{
- id: "xpcshell@tests.mozilla.org",
- minVersion: "1",
- maxVersion: "5"}],
- },
- {
- id: "bug335238_2@tests.mozilla.org",
- version: "28at",
- name: "Bug 335238",
- updateURL: "http://example.com/1?id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appId=%APP_ID%&appVersion=%APP_VERSION%&appOs=%APP_OS%&appAbi=%APP_ABI%&locale=%APP_LOCALE%&reqVersion=%REQ_VERSION%",
- bootstrap: true,
-
- targetApplications: [{
- id: "xpcshell@tests.mozilla.org",
- minVersion: "1",
- maxVersion: "7"}],
- },
- {
- id: "bug335238_3@tests.mozilla.org",
- version: "58",
- name: "Bug 335238",
- updateURL: "http://example.com/2?id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appId=%APP_ID%&appVersion=%APP_VERSION%&appOs=%APP_OS%&appAbi=%APP_ABI%&locale=%APP_LOCALE%&reqVersion=%REQ_VERSION%",
- bootstrap: true,
-
- targetApplications: [{
- id: "xpcshell@tests.mozilla.org",
- minVersion: "1",
- maxVersion: "*"}],
- },
- {
- id: "bug335238_4@tests.mozilla.org",
- version: "4",
- name: "Bug 335238",
- updateURL: "http://example.com/3?id=%ITEM_ID%&version=%ITEM_VERSION%&maxAppVersion=%ITEM_MAXAPPVERSION%&status=%ITEM_STATUS%&appId=%APP_ID%&appVersion=%APP_VERSION%&appOs=%APP_OS%&appAbi=%APP_ABI%&locale=%APP_LOCALE%&reqVersion=%REQ_VERSION%",
- bootstrap: true,
-
- targetApplications: [{
- id: "xpcshell@tests.mozilla.org",
- minVersion: "1",
- maxVersion: "2+"}],
- },
-];
-
-const XPIS = MANIFESTS.map(manifest => createTempXPIFile(manifest));
-
-var ADDONS = [
- {id: "bug335238_1@tests.mozilla.org",
- addon: XPIS[0]},
- {id: "bug335238_2@tests.mozilla.org",
- addon: XPIS[1]},
- {id: "bug335238_3@tests.mozilla.org",
- addon: XPIS[2]},
- {id: "bug335238_4@tests.mozilla.org",
- addon: XPIS[3]}
-];
-
-// This is a replacement for the blocklist service
-var BlocklistService = {
- getAddonBlocklistState(aAddon, aAppVersion, aToolkitVersion) {
- if (aAddon.id == "bug335238_3@tests.mozilla.org")
- return Ci.nsIBlocklistService.STATE_SOFTBLOCKED;
- if (aAddon.id == "bug335238_4@tests.mozilla.org")
- return Ci.nsIBlocklistService.STATE_BLOCKED;
- return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
- },
-
- getAddonBlocklistEntry(aAddon, aAppVersion, aToolkitVersion) {
- let state = this.getAddonBlocklistState(aAddon, aAppVersion, aToolkitVersion);
- if (state != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) {
- return {
- state,
- url: "http://example.com/",
- };
- }
- return null;
- },
-
- getPluginBlocklistState(aPlugin, aVersion, aAppVersion, aToolkitVersion) {
- return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
- },
-
- isAddonBlocklisted(aAddon, aAppVersion, aToolkitVersion) {
- return this.getAddonBlocklistState(aAddon, aAppVersion, aToolkitVersion) ==
- Ci.nsIBlocklistService.STATE_BLOCKED;
- },
-
- QueryInterface(iid) {
- if (iid.equals(Ci.nsIBlocklistService)
- || iid.equals(Ci.nsISupports))
- return this;
-
- throw Cr.NS_ERROR_NO_INTERFACE;
- }
-};
-
-MockRegistrar.register("@mozilla.org/extensions/blocklist;1", BlocklistService);
-
-var server;
-
-var updateListener = {
- pendingCount: 0,
-
- onUpdateAvailable(aAddon) {
- do_throw("Should not have seen an update for " + aAddon.id);
- },
-
- onUpdateFinished() {
- if (--this.pendingCount == 0)
- do_test_finished();
- }
-};
-
-var requestHandler = {
- handle(metadata, response) {
- var expected = EXPECTED[metadata.path.substring(1)];
- var params = metadata.queryString.split("&");
- Assert.equal(params.length, 10);
- for (var k in params) {
- var pair = params[k].split("=");
- var name = decodeURIComponent(pair[0]);
- var value = decodeURIComponent(pair[1]);
- Assert.equal(expected[name], value);
- }
- response.setStatusLine(metadata.httpVersion, 404, "Not Found");
- }
-};
-
-function run_test() {
- do_test_pending();
- createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9");
-
- server = AddonTestUtils.createHttpServer({hosts: ["example.com"]});
- server.registerPathHandler("/0", requestHandler);
- server.registerPathHandler("/1", requestHandler);
- server.registerPathHandler("/2", requestHandler);
- server.registerPathHandler("/3", requestHandler);
-
- Services.locale.setRequestedLocales(["en-US"]);
-
- startupManager();
- installAllFiles(ADDONS.map(a => a.addon), function() {
-
- restartManager();
- AddonManager.getAddonByID(ADDONS[1].id, callback_soon(function(addon) {
- Assert.ok(!(!addon));
- addon.userDisabled = true;
- restartManager();
-
- AddonManager.getAddonsByIDs(ADDONS.map(a => a.id), function(installedItems) {
- installedItems.forEach(function(item) {
- updateListener.pendingCount++;
- item.findUpdates(updateListener, AddonManager.UPDATE_WHEN_USER_REQUESTED);
- });
- });
- }));
- });
-}
--- a/toolkit/mozapps/extensions/test/xpcshell/test_update.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_update.js
@@ -552,22 +552,80 @@ const PARAM_ADDONS = {
item_version: "1.0",
item_maxappversion: "1",
item_status: "userEnabled",
app_version: "1",
update_type: "99",
},
updateType: [AddonManager.UPDATE_WHEN_NEW_APP_INSTALLED],
},
+
+ "blocklist1@tests.mozilla.org": {
+ "install.rdf": {
+ id: "blocklist1@tests.mozilla.org",
+ version: "5.0",
+ bootstrap: true,
+ updateURL: "http://example.com/data/param_test.json" + PARAMS,
+ targetApplications: [{
+ id: appId,
+ minVersion: "1",
+ maxVersion: "2"
+ }],
+ name: "Test Addon 1",
+ },
+ params: {
+ item_version: "5.0",
+ item_maxappversion: "2",
+ item_status: "userDisabled,softblocked",
+ app_version: "1",
+ update_type: "97",
+ },
+ updateType: [AddonManager.UPDATE_WHEN_USER_REQUESTED],
+ blocklistState: "STATE_SOFTBLOCKED",
+ },
+
+ "blocklist2@tests.mozilla.org": {
+ "install.rdf": {
+ id: "blocklist2@tests.mozilla.org",
+ version: "5.0",
+ bootstrap: true,
+ updateURL: "http://example.com/data/param_test.json" + PARAMS,
+ targetApplications: [{
+ id: appId,
+ minVersion: "1",
+ maxVersion: "2"
+ }],
+ name: "Test Addon 1",
+ },
+ params: {
+ item_version: "5.0",
+ item_maxappversion: "2",
+ item_status: "userEnabled,blocklisted",
+ app_version: "1",
+ update_type: "97",
+ },
+ updateType: [AddonManager.UPDATE_WHEN_USER_REQUESTED],
+ blocklistState: "STATE_BLOCKED",
+ },
};
const PARAM_IDS = Object.keys(PARAM_ADDONS);
// Verify the parameter escaping in update urls.
add_task(async function test_8() {
+ let blocklistAddons = new Map();
+ for (let [id, options] of Object.entries(PARAM_ADDONS)) {
+ if (options.blocklistState) {
+ blocklistAddons.set(id, Ci.nsIBlocklistService[options.blocklistState]);
+ }
+ }
+ let mockBlocklist = await AddonTestUtils.overrideBlocklist(blocklistAddons);
+
+ await promiseRestartManager();
+
for (let [id, options] of Object.entries(PARAM_ADDONS)) {
await promiseInstallXPI(options["install.rdf"], profileDir);
if (options.initialState) {
let addon = await AddonManager.getAddonByID(id);
Object.assign(addon, options.initialState);
}
}
@@ -618,16 +676,18 @@ add_task(async function test_8() {
for (let [prop, value] of Object.entries(expected)) {
equal(params.get(prop), value, `Expected value for ${prop}`);
}
}
for (let [, addon] of await getAddons(PARAM_IDS)) {
addon.uninstall();
}
+
+ await mockBlocklist.unregister();
});
// Tests that if an install.rdf claims compatibility then the add-on will be
// seen as compatible regardless of what the update.rdf says.
add_task(async function test_9() {
await promiseInstallXPI({
id: "addon4@tests.mozilla.org",
version: "5.0",
--- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
+++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
@@ -38,20 +38,16 @@ tags = blocklist
requesttimeoutfactor = 2
tags = blocklist
[test_bootstrap.js]
skip-if = true # Bug 1358846 Bug 1365021 Bug 676992
[test_bootstrap_const.js]
[test_bootstrap_globals.js]
[test_bug1180901_2.js]
skip-if = os != "win"
-[test_bug335238.js]
-# Bug 676992: test consistently hangs on Android
-skip-if = os == "android"
-tags = blocklist
[test_bug371495.js]
# Bug 676992: test consistently hangs on Android
skip-if = os == "android"
[test_bug384052.js]
# Bug 676992: test consistently hangs on Android
skip-if = os == "android"
[test_bug393285.js]
# Bug 676992: test consistently hangs on Android