--- a/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
@@ -3,17 +3,16 @@
const {AddonManager, AddonManagerPrivate} = ChromeUtils.import("resource://gre/modules/AddonManager.jsm", {});
ChromeUtils.import("resource://gre/modules/TelemetryEnvironment.jsm", this);
ChromeUtils.import("resource://gre/modules/ObjectUtils.jsm");
ChromeUtils.import("resource://gre/modules/Preferences.jsm", this);
ChromeUtils.import("resource://gre/modules/PromiseUtils.jsm", this);
ChromeUtils.import("resource://gre/modules/Timer.jsm", this);
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm", this);
-ChromeUtils.import("resource://testing-common/AddonManagerTesting.jsm");
ChromeUtils.import("resource://testing-common/httpd.js");
ChromeUtils.import("resource://testing-common/MockRegistrar.jsm", this);
ChromeUtils.import("resource://gre/modules/FileUtils.jsm");
// AttributionCode is only needed for Firefox
ChromeUtils.defineModuleGetter(this, "AttributionCode",
"resource:///modules/AttributionCode.jsm");
@@ -22,16 +21,21 @@ ChromeUtils.defineModuleGetter(this, "Li
"resource://gre/modules/LightweightThemeManager.jsm");
ChromeUtils.defineModuleGetter(this, "ProfileAge",
"resource://gre/modules/ProfileAge.jsm");
ChromeUtils.defineModuleGetter(this, "ExtensionTestUtils",
"resource://testing-common/ExtensionXPCShellUtils.jsm");
+async function installXPIFromURL(url) {
+ let install = await AddonManager.getInstallForURL(url, "application/x-xpinstall");
+ return install.install();
+}
+
// The webserver hosting the addons.
var gHttpServer = null;
// The URL of the webserver root.
var gHttpRoot = null;
// The URL of the data directory, on the webserver.
var gDataRoot = null;
const PLATFORM_VERSION = "1.9.2";
@@ -1085,38 +1089,38 @@ add_task(async function test_addonsWatch
let assertCheckpoint = (aExpected) => {
Assert.equal(receivedNotifications, aExpected);
TelemetryEnvironment.unregisterChangeListener("testWatchAddons_Changes" + aExpected);
};
// Test for receiving one notification after each change.
let checkpointPromise = registerCheckpointPromise(1);
- await AddonManagerTesting.installXPIFromURL(ADDON_INSTALL_URL);
+ await installXPIFromURL(ADDON_INSTALL_URL);
await checkpointPromise;
assertCheckpoint(1);
Assert.ok(ADDON_ID in TelemetryEnvironment.currentEnvironment.addons.activeAddons);
checkpointPromise = registerCheckpointPromise(2);
- let addon = await AddonManagerTesting.getAddonById(ADDON_ID);
+ let addon = await AddonManager.getAddonByID(ADDON_ID);
addon.userDisabled = true;
await checkpointPromise;
assertCheckpoint(2);
Assert.ok(!(ADDON_ID in TelemetryEnvironment.currentEnvironment.addons.activeAddons));
checkpointPromise = registerCheckpointPromise(3);
let startupPromise = AddonTestUtils.promiseWebExtensionStartup(ADDON_ID);
addon.userDisabled = false;
await checkpointPromise;
assertCheckpoint(3);
Assert.ok(ADDON_ID in TelemetryEnvironment.currentEnvironment.addons.activeAddons);
await startupPromise;
checkpointPromise = registerCheckpointPromise(4);
- await AddonManagerTesting.uninstallAddonByID(ADDON_ID);
+ (await AddonManager.getAddonByID(ADDON_ID)).uninstall();
await checkpointPromise;
assertCheckpoint(4);
Assert.ok(!(ADDON_ID in TelemetryEnvironment.currentEnvironment.addons.activeAddons));
Assert.equal(receivedNotifications, EXPECTED_NOTIFICATIONS,
"We must only receive the notifications we expect.");
});
@@ -1188,26 +1192,28 @@ add_task(async function test_addonsWatch
let deferred = PromiseUtils.defer();
TelemetryEnvironment.registerChangeListener("testNotInteresting",
() => {
Assert.ok(!receivedNotification, "Should not receive multiple notifications");
receivedNotification = true;
deferred.resolve();
});
- let dictionaryAddon = await AddonManagerTesting.installXPIFromURL(DICTIONARY_ADDON_INSTALL_URL);
- let interestingAddon = await AddonManagerTesting.installXPIFromURL(INTERESTING_ADDON_INSTALL_URL);
+ let dictionaryAddon = await installXPIFromURL(DICTIONARY_ADDON_INSTALL_URL);
+ let interestingAddon = await installXPIFromURL(INTERESTING_ADDON_INSTALL_URL);
await deferred.promise;
Assert.ok(!("telemetry-dictionary@tests.mozilla.org" in
TelemetryEnvironment.currentEnvironment.addons.activeAddons),
"Dictionaries should not appear in active addons.");
TelemetryEnvironment.unregisterChangeListener("testNotInteresting");
+ dump(`DICTIONARY ADDON ${dictionaryAddon}\n`);
+ dump(` ADDON ${uneval(dictionaryAddon)}\n`);
dictionaryAddon.uninstall();
await interestingAddon.startupPromise;
interestingAddon.uninstall();
});
add_task(async function test_addonsAndPlugins() {
const ADDON_INSTALL_URL = gDataRoot + "restartless.xpi";
const ADDON_ID = "tel-restartless-webext@tests.mozilla.org";
@@ -1284,17 +1290,17 @@ add_task(async function test_addonsAndPl
TelemetryEnvironment.registerChangeListener("test_WebExtension",
(reason, data) => {
Assert.equal(reason, "addons-changed");
deferred.resolve();
}
);
// Install an add-on so we have some data.
- let addon = await AddonManagerTesting.installXPIFromURL(ADDON_INSTALL_URL);
+ let addon = await installXPIFromURL(ADDON_INSTALL_URL);
// Install a webextension as well.
ExtensionTestUtils.init(this);
let webextension = ExtensionTestUtils.loadExtension({
useAddonManager: "permanent",
manifest: {
"name": "XPI Telemetry WebExtension Add-on Test",
@@ -1384,17 +1390,17 @@ add_task(async function test_signedAddon
updateDay: ADDON_INSTALL_DATE,
signedState: mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED,
};
let deferred = PromiseUtils.defer();
TelemetryEnvironment.registerChangeListener("test_signedAddon", deferred.resolve);
// Install the addon.
- let addon = await AddonManagerTesting.installXPIFromURL(ADDON_INSTALL_URL);
+ let addon = await installXPIFromURL(ADDON_INSTALL_URL);
await deferred.promise;
// Unregister the listener.
TelemetryEnvironment.unregisterChangeListener("test_signedAddon");
let data = TelemetryEnvironment.currentEnvironment;
checkEnvironmentData(data);
@@ -1412,17 +1418,17 @@ add_task(async function test_signedAddon
add_task(async function test_addonsFieldsLimit() {
const ADDON_INSTALL_URL = gDataRoot + "long-fields.xpi";
const ADDON_ID = "tel-longfields-webext@tests.mozilla.org";
// Install the addon and wait for the TelemetryEnvironment to pick it up.
let deferred = PromiseUtils.defer();
TelemetryEnvironment.registerChangeListener("test_longFieldsAddon", deferred.resolve);
- let addon = await AddonManagerTesting.installXPIFromURL(ADDON_INSTALL_URL);
+ let addon = await installXPIFromURL(ADDON_INSTALL_URL);
await deferred.promise;
TelemetryEnvironment.unregisterChangeListener("test_longFieldsAddon");
let data = TelemetryEnvironment.currentEnvironment;
checkEnvironmentData(data);
// Check that the addon is available and that the string fields are limited.
Assert.ok(ADDON_ID in data.addons.activeAddons, "Add-on should be in the environment.");
@@ -1492,17 +1498,17 @@ add_task(async function test_collectionW
let brokenAddonProvider = createMockAddonProvider("Broken Extensions Provider");
AddonManagerPrivate.registerProvider(brokenAddonProvider);
brokenAddonProvider.addAddon(BROKEN_MANIFEST);
await checkpointPromise;
assertCheckpoint(1);
// Now install an addon which returns the correct information.
checkpointPromise = registerCheckpointPromise(2);
- let addon = await AddonManagerTesting.installXPIFromURL(ADDON_INSTALL_URL);
+ let addon = await installXPIFromURL(ADDON_INSTALL_URL);
await checkpointPromise;
assertCheckpoint(2);
// Check that the new environment contains the Social addon installed with the broken
// manifest and the rest of the data.
let data = TelemetryEnvironment.currentEnvironment;
checkEnvironmentData(data, {expectBrokenAddons: true});
--- a/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
+++ b/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
@@ -1267,34 +1267,19 @@ var AddonTestUtils = {
* A helper method to install AddonInstall and wait for completion.
*
* @param {AddonInstall} install
* The add-on to install.
* @returns {Promise<AddonInstall>}
* Resolves when the install completes, either successfully or
* in failure.
*/
- promiseCompleteInstall(install) {
- let listener;
- return new Promise(resolve => {
- listener = {
- onDownloadFailed: resolve,
- onDownloadCancelled: resolve,
- onInstallFailed: resolve,
- onInstallCancelled: resolve,
- onInstallEnded: resolve,
- onInstallPostponed: resolve,
- };
-
- install.addListener(listener);
- install.install();
- }).then(() => {
- install.removeListener(listener);
- return install;
- });
+ async promiseCompleteInstall(install) {
+ await install.install().catch(() => {});
+ return install;
},
/**
* A helper method to install a file.
*
* @param {nsIFile} file
* The file to install
* @param {boolean} [ignoreIncompatible = false]
--- a/toolkit/mozapps/extensions/internal/XPIInstall.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIInstall.jsm
@@ -1227,16 +1227,23 @@ class AddonInstall {
data: hashSplit[1]
};
}
this.hash = this.originalHash;
this.existingAddon = options.existingAddon || null;
this.promptHandler = options.promptHandler || (() => Promise.resolve());
this.releaseNotesURI = null;
+ this._installPromise = new Promise(resolve => {
+ this._resolveInstallPromise = resolve;
+ });
+ // Ignore uncaught rejections for this promise, since they're
+ // handled by install listeners.
+ this._installPromise.catch(() => {});
+
this.listeners = [];
this.icons = options.icons || {};
this.error = 0;
this.progress = 0;
this.maxProgress = -1;
// Giving each instance of AddonInstall a reference to the logger.
@@ -1277,20 +1284,21 @@ class AddonInstall {
break;
case AddonManager.STATE_POSTPONED:
logger.debug(`Postponing install of ${this.addon.id}`);
break;
case AddonManager.STATE_DOWNLOADING:
case AddonManager.STATE_CHECKING:
case AddonManager.STATE_INSTALLING:
// Installation is already running
- return;
+ break;
default:
throw new Error("Cannot start installing from this state");
}
+ return this._installPromise;
}
/**
* Called during XPIProvider shutdown so that we can do any necessary
* pre-shutdown cleanup.
*/
onShutdown() {
switch (this.state) {
@@ -1310,18 +1318,17 @@ class AddonInstall {
*/
cancel() {
switch (this.state) {
case AddonManager.STATE_AVAILABLE:
case AddonManager.STATE_DOWNLOADED:
logger.debug("Cancelling download of " + this.sourceURI.spec);
this.state = AddonManager.STATE_CANCELLED;
XPIProvider.removeActiveInstall(this);
- AddonManagerPrivate.callInstallListeners("onDownloadCancelled",
- this.listeners, this.wrapper);
+ this._callInstallListeners("onDownloadCancelled");
this.removeTemporaryFile();
break;
case AddonManager.STATE_INSTALLED:
logger.debug("Cancelling install of " + this.addon.id);
let xpi = getFile(`${this.addon.id}.xpi`, this.installLocation.getStagingDir());
flushJarCache(xpi);
this.installLocation.cleanStagingDir([this.addon.id, this.addon.id + ".xpi"]);
this.state = AddonManager.STATE_CANCELLED;
@@ -1329,25 +1336,23 @@ class AddonInstall {
if (this.existingAddon) {
delete this.existingAddon.pendingUpgrade;
this.existingAddon.pendingUpgrade = null;
}
AddonManagerPrivate.callAddonListeners("onOperationCancelled", this.addon.wrapper);
- AddonManagerPrivate.callInstallListeners("onInstallCancelled",
- this.listeners, this.wrapper);
+ this._callInstallListeners("onInstallCancelled");
break;
case AddonManager.STATE_POSTPONED:
logger.debug(`Cancelling postponed install of ${this.addon.id}`);
this.state = AddonManager.STATE_CANCELLED;
XPIProvider.removeActiveInstall(this);
- AddonManagerPrivate.callInstallListeners("onInstallCancelled",
- this.listeners, this.wrapper);
+ this._callInstallListeners("onInstallCancelled");
this.removeTemporaryFile();
let stagingDir = this.installLocation.getStagingDir();
let stagedAddon = stagingDir.clone();
this.unstageInstall(stagedAddon);
default:
throw new Error("Cannot cancel install of " + this.sourceURI.spec +
@@ -1529,18 +1534,17 @@ class AddonInstall {
};
try {
await this.promptHandler(info);
} catch (err) {
logger.info(`Install of ${this.addon.id} cancelled by user`);
this.state = AddonManager.STATE_CANCELLED;
XPIProvider.removeActiveInstall(this);
- AddonManagerPrivate.callInstallListeners("onInstallCancelled",
- this.listeners, this.wrapper);
+ this._callInstallListeners("onInstallCancelled");
return;
}
}
this.state = AddonManager.STATE_PROMPTS_DONE;
this.install();
})();
}
@@ -1571,23 +1575,21 @@ class AddonInstall {
// TODO This relies on the assumption that we are always installing into the
// highest priority install location so the resulting add-on will be visible
// overriding any existing copy in another install location (bug 557710).
/**
* Installs the add-on into the install location.
*/
startInstall() {
this.state = AddonManager.STATE_INSTALLING;
- if (!AddonManagerPrivate.callInstallListeners("onInstallStarted",
- this.listeners, this.wrapper)) {
+ if (!this._callInstallListeners("onInstallStarted")) {
this.state = AddonManager.STATE_DOWNLOADED;
this.removeTemporaryFile();
XPIProvider.removeActiveInstall(this);
- AddonManagerPrivate.callInstallListeners("onInstallCancelled",
- this.listeners, this.wrapper);
+ this._callInstallListeners("onInstallCancelled");
return;
}
// Find and cancel any pending installs for the same add-on in the same
// install location
for (let aInstall of XPIProvider.installs) {
if (aInstall.state == AddonManager.STATE_INSTALLED &&
aInstall.installLocation == this.installLocation &&
@@ -1694,19 +1696,17 @@ class AddonInstall {
reason, extraParams);
}
AddonManagerPrivate.callAddonListeners("onInstalled",
this.addon.wrapper);
logger.debug("Install of " + this.sourceURI.spec + " completed.");
this.state = AddonManager.STATE_INSTALLED;
- AddonManagerPrivate.callInstallListeners("onInstallEnded",
- this.listeners, this.wrapper,
- this.addon.wrapper);
+ this._callInstallListeners("onInstallEnded", this.addon.wrapper);
if (this.addon.bootstrap) {
if (this.addon.active) {
XPIProvider.callBootstrapMethod(this.addon, file, "startup",
reason, extraParams);
} else {
// XXX this makes it dangerous to do some things in onInstallEnded
// listeners because important cleanup hasn't been done yet
@@ -1723,19 +1723,17 @@ class AddonInstall {
if (stagedAddon.exists())
recursiveRemove(stagedAddon);
this.state = AddonManager.STATE_INSTALL_FAILED;
this.error = AddonManager.ERROR_FILE_ACCESS;
XPIProvider.removeActiveInstall(this);
AddonManagerPrivate.callAddonListeners("onOperationCancelled",
this.addon.wrapper);
- AddonManagerPrivate.callInstallListeners("onInstallFailed",
- this.listeners,
- this.wrapper);
+ this._callInstallListeners("onInstallFailed");
}).then(() => {
this.removeTemporaryFile();
return this.installLocation.releaseStagingDir();
});
}
/**
* Stages an upgrade for next application restart.
@@ -1795,18 +1793,17 @@ class AddonInstall {
await this.installLocation.requestStagingDir();
await this.unstageInstall(stagingDir);
let stagedAddon = getFile(`${this.addon.id}.xpi`, stagingDir);
await this.stageInstall(true, stagedAddon, true);
- AddonManagerPrivate.callInstallListeners("onInstallPostponed",
- this.listeners, this.wrapper);
+ this._callInstallListeners("onInstallPostponed");
// upgrade has been staged for restart, provide a way for it to call the
// resume function.
let callback = AddonManagerPrivate.getUpgradeListener(this.addon.id);
if (callback) {
callback({
version: this.version,
install: () => {
@@ -1823,16 +1820,34 @@ class AddonInstall {
},
});
}
// Release the staging directory lock, but since the staging dir is populated
// it will not be removed until resumed or installed by restart.
// See also cleanStagingDir()
this.installLocation.releaseStagingDir();
}
+
+ _callInstallListeners(event, ...args) {
+ switch (event) {
+ case "onDownloadCancelled":
+ case "onDownloadFailed":
+ case "onInstallCancelled":
+ case "onInstallFailed":
+ let rej = Promise.reject(new Error(`Install failed: ${event}`));
+ rej.catch(() => {});
+ this._resolveInstallPromise(rej);
+ break;
+ case "onInstallEnded":
+ this._resolveInstallPromise(args[0]);
+ break;
+ }
+ return AddonManagerPrivate.callInstallListeners(event, this.listeners, this.wrapper,
+ ...args);
+ }
}
var LocalAddonInstall = class extends AddonInstall {
/**
* Initialises this install to be an install from a local file.
*
* @returns Promise
* A Promise that resolves when the object is ready to use.
@@ -1881,19 +1896,17 @@ var LocalAddonInstall = class extends Ad
try {
await this.loadManifest(this.file);
} catch ([error, message]) {
logger.warn("Invalid XPI", message);
this.state = AddonManager.STATE_DOWNLOAD_FAILED;
this.error = error;
XPIProvider.removeActiveInstall(this);
- AddonManagerPrivate.callInstallListeners("onNewInstall",
- this.listeners,
- this.wrapper);
+ this._callInstallListeners("onNewInstall");
flushJarCache(this.file);
return;
}
let addon = await XPIDatabase.getVisibleAddonForID(this.addon.id);
this.existingAddon = addon;
this.addon.updateBlocklistState({oldAddon: this.existingAddon});
@@ -1902,43 +1915,38 @@ var LocalAddonInstall = class extends Ad
if (!this.addon.isCompatible) {
this.state = AddonManager.STATE_CHECKING;
await new Promise(resolve => {
new UpdateChecker(this.addon, {
onUpdateFinished: aAddon => {
this.state = AddonManager.STATE_DOWNLOADED;
- AddonManagerPrivate.callInstallListeners("onNewInstall",
- this.listeners,
- this.wrapper);
+ this._callInstallListeners("onNewInstall");
resolve();
}
}, AddonManager.UPDATE_WHEN_ADDON_INSTALLED);
});
} else {
- AddonManagerPrivate.callInstallListeners("onNewInstall",
- this.listeners,
- this.wrapper);
+ this._callInstallListeners("onNewInstall");
}
}
install() {
if (this.state == AddonManager.STATE_DOWNLOAD_FAILED) {
// For a local install, this state means that verification of the
// file failed (e.g., the hash or signature or manifest contents
// were invalid). It doesn't make sense to retry anything in this
// case but we have callers who don't know if their AddonInstall
// object is a local file or a download so accommodate them here.
- AddonManagerPrivate.callInstallListeners("onDownloadFailed",
- this.listeners, this.wrapper);
- return;
+ this._callInstallListeners("onDownloadFailed");
+ return this._installPromise;
}
- super.install();
+ return super.install();
}
};
var DownloadAddonInstall = class extends AddonInstall {
/**
* Instantiates a DownloadAddonInstall
*
* @param installLocation
@@ -1972,18 +1980,17 @@ var DownloadAddonInstall = class extends
this.state = AddonManager.STATE_AVAILABLE;
this.stream = null;
this.crypto = null;
this.badCertHandler = null;
this.restartDownload = false;
- AddonManagerPrivate.callInstallListeners("onNewInstall", this.listeners,
- this.wrapper);
+ this._callInstallListeners("onNewInstall", this.listeners, this.wrapper);
}
install() {
switch (this.state) {
case AddonManager.STATE_AVAILABLE:
this.startDownload();
break;
case AddonManager.STATE_DOWNLOAD_FAILED:
@@ -1993,18 +2000,19 @@ var DownloadAddonInstall = class extends
this.state = AddonManager.STATE_AVAILABLE;
this.error = 0;
this.progress = 0;
this.maxProgress = -1;
this.hash = this.originalHash;
this.startDownload();
break;
default:
- super.install();
+ return super.install();
}
+ return this._installPromise;
}
cancel() {
if (this.state == AddonManager.STATE_DOWNLOADING) {
if (this.channel) {
logger.debug("Cancelling download of " + this.sourceURI.spec);
this.channel.cancel(Cr.NS_BINDING_ABORTED);
}
@@ -2018,23 +2026,21 @@ var DownloadAddonInstall = class extends
this.cancel();
}
/**
* Starts downloading the add-on's XPI file.
*/
startDownload() {
this.state = AddonManager.STATE_DOWNLOADING;
- if (!AddonManagerPrivate.callInstallListeners("onDownloadStarted",
- this.listeners, this.wrapper)) {
+ if (!this._callInstallListeners("onDownloadStarted")) {
logger.debug("onDownloadStarted listeners cancelled installation of addon " + this.sourceURI.spec);
this.state = AddonManager.STATE_CANCELLED;
XPIProvider.removeActiveInstall(this);
- AddonManagerPrivate.callInstallListeners("onDownloadCancelled",
- this.listeners, this.wrapper);
+ this._callInstallListeners("onDownloadCancelled");
return;
}
// If a listener changed our state then do not proceed with the download
if (this.state != AddonManager.STATE_DOWNLOADING)
return;
if (this.channel) {
@@ -2058,18 +2064,17 @@ var DownloadAddonInstall = class extends
createInstance(Ci.nsIFileOutputStream);
this.stream.init(this.file, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE |
FileUtils.MODE_TRUNCATE, FileUtils.PERMS_FILE, 0);
} catch (e) {
logger.warn("Failed to start download for addon " + this.sourceURI.spec, e);
this.state = AddonManager.STATE_DOWNLOAD_FAILED;
this.error = AddonManager.ERROR_FILE_ACCESS;
XPIProvider.removeActiveInstall(this);
- AddonManagerPrivate.callInstallListeners("onDownloadFailed",
- this.listeners, this.wrapper);
+ this._callInstallListeners("onDownloadFailed");
return;
}
let listener = Cc["@mozilla.org/network/stream-listener-tee;1"].
createInstance(Ci.nsIStreamListenerTee);
listener.init(this, this.stream);
try {
let requireBuiltIn = Services.prefs.getBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, true);
@@ -2088,31 +2093,29 @@ var DownloadAddonInstall = class extends
this.channel.asyncOpen2(listener);
Services.obs.addObserver(this, "network:offline-about-to-go-offline");
} catch (e) {
logger.warn("Failed to start download for addon " + this.sourceURI.spec, e);
this.state = AddonManager.STATE_DOWNLOAD_FAILED;
this.error = AddonManager.ERROR_NETWORK_FAILURE;
XPIProvider.removeActiveInstall(this);
- AddonManagerPrivate.callInstallListeners("onDownloadFailed",
- this.listeners, this.wrapper);
+ this._callInstallListeners("onDownloadFailed");
}
}
/**
* Update the crypto hasher with the new data and call the progress listeners.
*
* @see nsIStreamListener
*/
onDataAvailable(aRequest, aContext, aInputstream, aOffset, aCount) {
this.crypto.updateFromStream(aInputstream, aCount);
this.progress += aCount;
- if (!AddonManagerPrivate.callInstallListeners("onDownloadProgress",
- this.listeners, this.wrapper)) {
+ if (!this._callInstallListeners("onDownloadProgress")) {
// TODO cancel the download and make it available again (bug 553024)
}
}
/**
* Check the redirect response for a hash of the target XPI and verify that
* we don't end up on an insecure channel.
*
@@ -2151,18 +2154,17 @@ var DownloadAddonInstall = class extends
if (this.hash) {
try {
this.crypto = CryptoHash(this.hash.algorithm);
} catch (e) {
logger.warn("Unknown hash algorithm '" + this.hash.algorithm + "' for addon " + this.sourceURI.spec, e);
this.state = AddonManager.STATE_DOWNLOAD_FAILED;
this.error = AddonManager.ERROR_INCORRECT_HASH;
XPIProvider.removeActiveInstall(this);
- AddonManagerPrivate.callInstallListeners("onDownloadFailed",
- this.listeners, this.wrapper);
+ this._callInstallListeners("onDownloadFailed");
aRequest.cancel(Cr.NS_BINDING_ABORTED);
return;
}
} else {
// We always need something to consume data from the inputstream passed
// to onDataAvailable so just create a dummy cryptohasher to do that.
this.crypto = CryptoHash("sha1");
}
@@ -2190,18 +2192,17 @@ var DownloadAddonInstall = class extends
Services.obs.removeObserver(this, "network:offline-about-to-go-offline");
// If the download was cancelled then update the state and send events
if (aStatus == Cr.NS_BINDING_ABORTED) {
if (this.state == AddonManager.STATE_DOWNLOADING) {
logger.debug("Cancelled download of " + this.sourceURI.spec);
this.state = AddonManager.STATE_CANCELLED;
XPIProvider.removeActiveInstall(this);
- AddonManagerPrivate.callInstallListeners("onDownloadCancelled",
- this.listeners, this.wrapper);
+ this._callInstallListeners("onDownloadCancelled");
// If a listener restarted the download then there is no need to
// remove the temporary file
if (this.state != AddonManager.STATE_CANCELLED)
return;
}
this.removeTemporaryFile();
if (this.restartDownload)
@@ -2267,18 +2268,17 @@ var DownloadAddonInstall = class extends
* @param error
* The error code to pass to the listeners
*/
downloadFailed(aReason, aError) {
logger.warn("Download of " + this.sourceURI.spec + " failed", aError);
this.state = AddonManager.STATE_DOWNLOAD_FAILED;
this.error = aReason;
XPIProvider.removeActiveInstall(this);
- AddonManagerPrivate.callInstallListeners("onDownloadFailed", this.listeners,
- this.wrapper);
+ this._callInstallListeners("onDownloadFailed");
// If the listener hasn't restarted the download then remove any temporary
// file
if (this.state == AddonManager.STATE_DOWNLOAD_FAILED) {
logger.debug("downloadFailed: removing temp file for " + this.sourceURI.spec);
this.removeTemporaryFile();
} else
logger.debug("downloadFailed: listener changed AddonInstall state for " +
@@ -2299,19 +2299,17 @@ var DownloadAddonInstall = class extends
if (this.existingAddon) {
this.addon.existingAddonID = this.existingAddon.id;
this.addon.installDate = this.existingAddon.installDate;
} else {
this.addon.installDate = this.addon.updateDate;
}
this.addon.updateBlocklistState({oldAddon: this.existingAddon});
- if (AddonManagerPrivate.callInstallListeners("onDownloadEnded",
- this.listeners,
- this.wrapper)) {
+ if (this._callInstallListeners("onDownloadEnded")) {
// If a listener changed our state then do not proceed with the install
if (this.state != AddonManager.STATE_DOWNLOADED)
return;
// proceed with the install state machine.
this.install();
}
}
@@ -2420,17 +2418,17 @@ AddonInstallWrapper.prototype = {
return installFor(this).sourceURI;
},
set promptHandler(handler) {
installFor(this).promptHandler = handler;
},
install() {
- installFor(this).install();
+ return installFor(this).install();
},
cancel() {
installFor(this).cancel();
},
addListener(listener) {
installFor(this).addListener(listener);
deleted file mode 100644
--- a/toolkit/mozapps/extensions/test/AddonManagerTesting.jsm
+++ /dev/null
@@ -1,110 +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/. */
-
-// This file is a test-only JSM containing utility methods for
-// interacting with the add-ons manager.
-
-"use strict";
-
-var EXPORTED_SYMBOLS = [
- "AddonManagerTesting",
-];
-
-ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
-
-ChromeUtils.defineModuleGetter(this, "AddonManager",
- "resource://gre/modules/AddonManager.jsm");
-
-var AddonManagerTesting = {
- /**
- * Get the add-on that is specified by its ID.
- *
- * @return {Promise<Object>} A promise that resolves returning the found addon or null
- * if it is not found.
- */
- getAddonById(id) {
- return AddonManager.getAddonByID(id);
- },
-
- /**
- * Uninstall an add-on that is specified by its ID.
- *
- * The returned promise resolves on successful uninstall and rejects
- * if the add-on is not unknown.
- *
- * @return Promise<restartRequired>
- */
- uninstallAddonByID(id) {
- return new Promise(async (resolve, reject) => {
-
- let addon = await AddonManager.getAddonByID(id);
- if (!addon) {
- reject(new Error("Add-on is not known: " + id));
- return;
- }
-
- let listener = {
- onUninstalling(addon, needsRestart) {
- if (addon.id != id) {
- return;
- }
-
- if (needsRestart) {
- AddonManager.removeAddonListener(listener);
- resolve(true);
- }
- },
-
- onUninstalled(addon) {
- if (addon.id != id) {
- return;
- }
-
- AddonManager.removeAddonListener(listener);
- resolve(false);
- },
-
- onOperationCancelled(addon) {
- if (addon.id != id) {
- return;
- }
-
- AddonManager.removeAddonListener(listener);
- reject(new Error("Uninstall cancelled."));
- },
- };
-
- AddonManager.addAddonListener(listener);
- addon.uninstall();
-
- });
- },
-
- /**
- * Install an XPI add-on from a URL.
- *
- * @return Promise<addon>
- */
- installXPIFromURL(url, hash, name, iconURL, version) {
- return new Promise(async (resolve, reject) => {
-
- let install = await AddonManager.getInstallForURL(url, "application/x-xpinstall", hash, name, iconURL, version);
- let fail = () => { reject(new Error("Add-on install failed.")); };
-
- let listener = {
- onDownloadCancelled: fail,
- onDownloadFailed: fail,
- onInstallCancelled: fail,
- onInstallFailed: fail,
- onInstallEnded(install, addon) {
- resolve(addon);
- },
- };
-
- install.addListener(listener);
- install.install();
-
- });
- },
-};
--- a/toolkit/mozapps/extensions/test/moz.build
+++ b/toolkit/mozapps/extensions/test/moz.build
@@ -4,16 +4,12 @@
# 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/.
DIRS += ['browser']
BROWSER_CHROME_MANIFESTS += ['xpinstall/browser.ini']
MOCHITEST_MANIFESTS += ['mochitest/mochitest.ini']
-TESTING_JS_MODULES += [
- 'AddonManagerTesting.jsm',
-]
-
XPCSHELL_TESTS_MANIFESTS += [
'xpcshell/xpcshell-unpack.ini',
'xpcshell/xpcshell.ini',
]