Bug 772484 - Allow user to cancel add-on update check and clean up correctly when they do. r=Unfocused

This commit is contained in:
Irving Reid 2014-03-14 08:52:55 -04:00
Родитель e14fb8212b
Коммит 9f4c400488
12 изменённых файлов: 855 добавлений и 163 удалений

Просмотреть файл

@ -1074,34 +1074,30 @@ var AddonManagerInternal = {
// are up to date before checking for addon updates.
AddonRepository.backgroundUpdateCheck(
ids, function BUC_backgroundUpdateCheckCallback() {
AddonManagerInternal.updateAddonRepositoryData(
function BUC_updateAddonCallback() {
pendingUpdates += aAddons.length;
aAddons.forEach(function BUC_forEachCallback(aAddon) {
if (aAddon.id == hotfixID) {
notifyComplete();
return;
}
pendingUpdates += aAddons.length;
aAddons.forEach(function BUC_forEachCallback(aAddon) {
if (aAddon.id == hotfixID) {
notifyComplete();
return;
}
// Check all add-ons for updates so that any compatibility updates will
// be applied
aAddon.findUpdates({
onUpdateAvailable: function BUC_onUpdateAvailable(aAddon, aInstall) {
// Start installing updates when the add-on can be updated and
// background updates should be applied.
if (aAddon.permissions & AddonManager.PERM_CAN_UPGRADE &&
AddonManager.shouldAutoUpdate(aAddon)) {
aInstall.install();
}
},
// Check all add-ons for updates so that any compatibility updates will
// be applied
aAddon.findUpdates({
onUpdateAvailable: function BUC_onUpdateAvailable(aAddon, aInstall) {
// Start installing updates when the add-on can be updated and
// background updates should be applied.
if (aAddon.permissions & AddonManager.PERM_CAN_UPGRADE &&
AddonManager.shouldAutoUpdate(aAddon)) {
aInstall.install();
}
},
onUpdateFinished: notifyComplete
}, AddonManager.UPDATE_WHEN_PERIODIC_UPDATE);
});
notifyComplete();
onUpdateFinished: notifyComplete
}, AddonManager.UPDATE_WHEN_PERIODIC_UPDATE);
});
notifyComplete();
});
});
}
@ -1425,6 +1421,8 @@ var AddonManagerInternal = {
},
noMoreObjects: function updateAddonRepositoryData_noMoreObjects(aCaller) {
safeCall(aCallback);
// only tests should care about this
Services.obs.notifyObservers(null, "TEST:addon-repository-data-updated", null);
}
});
},

Просмотреть файл

@ -98,21 +98,18 @@ var gChecking = {
// individual addon updates.
let ids = [addon.id for each (addon in aAddons)];
AddonRepository.repopulateCache(ids, function gChecking_repopulateCache() {
AddonManagerPrivate.updateAddonRepositoryData(function gChecking_updateAddonRepositoryData() {
for (let addonItem of aAddons) {
// Ignore disabled themes
if (addonItem.type != "theme" || !addonItem.userDisabled) {
gAddons[addonItem.id] = {
addon: addonItem,
install: null,
wasActive: addonItem.isActive
}
for (let addonItem of aAddons) {
// Ignore disabled themes
if (addonItem.type != "theme" || !addonItem.userDisabled) {
gAddons[addonItem.id] = {
addon: addonItem,
install: null,
wasActive: addonItem.isActive
}
addonItem.findUpdates(self, AddonManager.UPDATE_WHEN_NEW_APP_INSTALLED);
}
});
addonItem.findUpdates(self, AddonManager.UPDATE_WHEN_NEW_APP_INSTALLED);
}
});
});
},

Просмотреть файл

@ -19,10 +19,8 @@ Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/AddonManager.jsm");
Components.utils.import("resource://gre/modules/addons/AddonRepository.jsm");
var gInteruptable = true;
var gPendingClose = false;
Components.utils.import("resource://gre/modules/Log.jsm");
let logger = Log.repository.getLogger("addons.update-dialog");
var gUpdateWizard = {
// When synchronizing app compatibility info this contains all installed
@ -38,6 +36,10 @@ var gUpdateWizard = {
shouldAutoCheck: false,
xpinstallEnabled: true,
xpinstallLocked: false,
// cached AddonInstall entries for add-ons we might want to update,
// keyed by add-on ID
addonInstalls: new Map(),
shuttingDown: false,
init: function gUpdateWizard_init()
{
@ -110,17 +112,26 @@ var gUpdateWizard = {
onWizardCancel: function gUpdateWizard_onWizardCancel()
{
if (!gInteruptable) {
gPendingClose = true;
this._setUpButton("back", null, true);
this._setUpButton("next", null, true);
this._setUpButton("cancel", null, true);
return false;
gUpdateWizard.shuttingDown = true;
// Allow add-ons to continue downloading and installing
// in the background, though some may require a later restart
// Pages that are waiting for user input go into the background
// on cancel
if (gMismatchPage.waiting) {
logger.info("Dialog closed in mismatch page");
if (gUpdateWizard.addonInstalls.size > 0) {
gInstallingPage.startInstalls([i for ([, i] of gUpdateWizard.addonInstalls)]);
}
return true;
}
if (gInstallingPage.installing) {
gInstallingPage.cancelInstalls();
return false;
// Pages that do asynchronous things will just keep running and check
// gUpdateWizard.shuttingDown to trigger background behaviour
if (!gInstallingPage.installing) {
logger.info("Dialog closed while waiting for updated compatibility information");
}
else {
logger.info("Dialog closed while downloading and installing updates");
}
return true;
}
@ -143,6 +154,7 @@ var gOfflinePage = {
var gVersionInfoPage = {
_completeCount: 0,
_totalCount: 0,
_versionInfoDone: false,
onPageShow: function gVersionInfoPage_onPageShow()
{
gUpdateWizard.setButtonLabels(null, true,
@ -156,28 +168,29 @@ var gVersionInfoPage = {
// Retrieve all add-ons in order to sync their app compatibility information
AddonManager.getAllAddons(function gVersionInfoPage_getAllAddons(aAddons) {
gUpdateWizard.addons = aAddons.filter(function gVersionInfoPage_filterAddons(a) {
return a.type != "plugin" && a.id != hotfixID;
});
if (gUpdateWizard.shuttingDown) {
logger.debug("getAllAddons completed after dialog closed");
}
gUpdateWizard.addons = [a for (a of aAddons)
if (a.type != "plugin" && a.id != hotfixID)];
gVersionInfoPage._totalCount = gUpdateWizard.addons.length;
// Ensure compatibility overrides are up to date before checking for
// individual addon updates.
let ids = [addon.id for each (addon in gUpdateWizard.addons)];
let ids = [addon.id for (addon of gUpdateWizard.addons)];
gInteruptable = false;
AddonRepository.repopulateCache(ids, function gVersionInfoPage_repolulateCache() {
AddonManagerPrivate.updateAddonRepositoryData(function gVersionInfoPage_updateAddonRepoData() {
gInteruptable = true;
if (gPendingClose) {
window.close();
return;
}
AddonRepository.repopulateCache(ids, function gVersionInfoPage_repopulateCache() {
for (let addon of gUpdateWizard.addons)
addon.findUpdates(gVersionInfoPage, AddonManager.UPDATE_WHEN_NEW_APP_INSTALLED);
});
if (gUpdateWizard.shuttingDown) {
logger.debug("repopulateCache completed after dialog closed");
}
for (let addon of gUpdateWizard.addons) {
logger.debug("VersionInfo Finding updates for " + addon.id);
addon.findUpdates(gVersionInfoPage, AddonManager.UPDATE_WHEN_NEW_APP_INSTALLED);
}
}, METADATA_TIMEOUT);
});
},
@ -185,15 +198,39 @@ var gVersionInfoPage = {
onAllUpdatesFinished: function gVersionInfoPage_onAllUpdatesFinished() {
// Filter out any add-ons that were disabled before the application was
// upgraded or are already compatible
gUpdateWizard.addons = gUpdateWizard.addons.filter(function onAllUpdatesFinished_filterAddons(a) {
return a.appDisabled && gUpdateWizard.inactiveAddonIDs.indexOf(a.id) < 0;
});
logger.debug("VersionInfo updates finished: inactive " +
gUpdateWizard.inactiveAddonIDs.toSource() + " found " +
[addon.id + ":" + addon.appDisabled for (addon of gUpdateWizard.addons)].toSource());
let filteredAddons = [];
for (let a of gUpdateWizard.addons) {
if (a.appDisabled && gUpdateWizard.inactiveAddonIDs.indexOf(a.id) < 0) {
logger.debug("Continuing with add-on " + a.id);
filteredAddons.push(a);
}
else if (gUpdateWizard.addonInstalls.has(a.id)) {
gUpdateWizard.addonInstalls.get(a.id).cancel();
gUpdateWizard.addonInstalls.delete(a.id);
}
}
gUpdateWizard.addons = filteredAddons;
if (gUpdateWizard.addons.length > 0) {
// There are still incompatible addons, inform the user.
if (gUpdateWizard.shuttingDown) {
// jump directly to updating auto-update add-ons in the background
if (gUpdateWizard.addonInstalls.size > 0) {
gInstallingPage.startInstalls([i for ([, i] of gUpdateWizard.addonInstalls)]);
}
return;
}
if (filteredAddons.length > 0) {
if (!gUpdateWizard.xpinstallEnabled && gUpdateWizard.xpinstallLocked) {
document.documentElement.currentPage = document.getElementById("adminDisabled");
return;
}
document.documentElement.currentPage = document.getElementById("mismatch");
}
else {
logger.info("VersionInfo: No updates require further action");
// VersionInfo compatibility updates resolved all compatibility problems,
// close this window and continue starting the application...
//XXX Bug 314754 - We need to use setTimeout to close the window due to
@ -205,34 +242,54 @@ var gVersionInfoPage = {
/////////////////////////////////////////////////////////////////////////////
// UpdateListener
onUpdateFinished: function gVersionInfoPage_onUpdateFinished(aAddon, status) {
// If the add-on is now active then it won't have been disabled by startup
if (aAddon.active)
AddonManagerPrivate.removeStartupChange("disabled", aAddon.id);
if (status != AddonManager.UPDATE_STATUS_NO_ERROR)
gUpdateWizard.errorItems.push(aAddon);
++this._completeCount;
// Update the status text and progress bar
var updateStrings = document.getElementById("updateStrings");
var statusElt = document.getElementById("versioninfo.status");
var statusString = updateStrings.getFormattedString("statusPrefix", [aAddon.name]);
statusElt.setAttribute("value", statusString);
if (status != AddonManager.UPDATE_STATUS_NO_ERROR) {
logger.debug("VersionInfo update " + this._completeCount + " of " + this._totalCount +
" failed for " + aAddon.id + ": " + status);
gUpdateWizard.errorItems.push(aAddon);
}
else {
logger.debug("VersionInfo update " + this._completeCount + " of " + this._totalCount +
" finished for " + aAddon.id);
}
// Update the status text and progress bar
var progress = document.getElementById("versioninfo.progress");
progress.mode = "normal";
progress.value = Math.ceil((this._completeCount / this._totalCount) * 100);
// If we're not in the background, just make a list of add-ons that have
// updates available
if (!gUpdateWizard.shuttingDown) {
// If we're still in the update check window and the add-on is now active
// then it won't have been disabled by startup
if (aAddon.active)
AddonManagerPrivate.removeStartupChange("disabled", aAddon.id);
// Update the status text and progress bar
var updateStrings = document.getElementById("updateStrings");
var statusElt = document.getElementById("versioninfo.status");
var statusString = updateStrings.getFormattedString("statusPrefix", [aAddon.name]);
statusElt.setAttribute("value", statusString);
// Update the status text and progress bar
var progress = document.getElementById("versioninfo.progress");
progress.mode = "normal";
progress.value = Math.ceil((this._completeCount / this._totalCount) * 100);
}
if (this._completeCount == this._totalCount)
this.onAllUpdatesFinished();
},
onUpdateAvailable: function gVersionInfoPage_onUpdateAvailable(aAddon, aInstall) {
logger.debug("VersionInfo got an install for " + aAddon.id + ": " + aAddon.version);
gUpdateWizard.addonInstalls.set(aAddon.id, aInstall);
},
};
var gMismatchPage = {
waiting: false,
onPageShow: function gMismatchPage_onPageShow()
{
gMismatchPage.waiting = true;
gUpdateWizard.setButtonLabels(null, true,
"mismatchCheckNow", false,
"mismatchDontCheck", false);
@ -252,11 +309,7 @@ var gUpdatePage = {
_completeCount: 0,
onPageShow: function gUpdatePage_onPageShow()
{
if (!gUpdateWizard.xpinstallEnabled && gUpdateWizard.xpinstallLocked) {
document.documentElement.currentPage = document.getElementById("adminDisabled");
return;
}
gMismatchPage.waiting = false;
gUpdateWizard.setButtonLabels(null, true,
"nextButtonText", true,
"cancelButtonText", false);
@ -265,11 +318,18 @@ var gUpdatePage = {
gUpdateWizard.errorItems = [];
this._totalCount = gUpdateWizard.addons.length;
for (let addon of gUpdateWizard.addons)
for (let addon of gUpdateWizard.addons) {
logger.debug("UpdatePage requesting update for " + addon.id);
// Redundant call to find updates again here when we already got them
// in the VersionInfo page: https://bugzilla.mozilla.org/show_bug.cgi?id=960597
addon.findUpdates(this, AddonManager.UPDATE_WHEN_NEW_APP_INSTALLED);
}
},
onAllUpdatesFinished: function gUpdatePage_onAllUpdatesFinished() {
if (gUpdateWizard.shuttingDown)
return;
var nextPage = document.getElementById("noupdates");
if (gUpdateWizard.addonsToUpdate.length > 0)
nextPage = document.getElementById("found");
@ -279,6 +339,7 @@ var gUpdatePage = {
/////////////////////////////////////////////////////////////////////////////
// UpdateListener
onUpdateAvailable: function gUpdatePage_onUpdateAvailable(aAddon, aInstall) {
logger.debug("UpdatePage got an update for " + aAddon.id + ": " + aAddon.version);
gUpdateWizard.addonsToUpdate.push(aInstall);
},
@ -288,14 +349,16 @@ var gUpdatePage = {
++this._completeCount;
// Update the status text and progress bar
var updateStrings = document.getElementById("updateStrings");
var statusElt = document.getElementById("checking.status");
var statusString = updateStrings.getFormattedString("statusPrefix", [aAddon.name]);
statusElt.setAttribute("value", statusString);
if (!gUpdateWizard.shuttingDown) {
// Update the status text and progress bar
var updateStrings = document.getElementById("updateStrings");
var statusElt = document.getElementById("checking.status");
var statusString = updateStrings.getFormattedString("statusPrefix", [aAddon.name]);
statusElt.setAttribute("value", statusString);
var progress = document.getElementById("checking.progress");
progress.value = Math.ceil((this._completeCount / this._totalCount) * 100);
var progress = document.getElementById("checking.progress");
progress.value = Math.ceil((this._completeCount / this._totalCount) * 100);
}
if (this._completeCount == this._totalCount)
this.onAllUpdatesFinished()
@ -371,24 +434,41 @@ var gInstallingPage = {
_currentInstall : -1,
_installing : false,
// Initialize fields we need for installing and tracking progress,
// and start iterating through the installations
startInstalls: function gInstallingPage_startInstalls(aInstallList) {
if (!gUpdateWizard.xpinstallEnabled) {
return;
}
logger.debug("Start installs for "
+ [i.existingAddon.id for (i of aInstallList)].toSource());
this._errors = [];
this._installs = aInstallList;
this._installing = true;
this.startNextInstall();
},
onPageShow: function gInstallingPage_onPageShow()
{
gUpdateWizard.setButtonLabels(null, true,
"nextButtonText", true,
null, true);
this._errors = [];
var foundUpdates = document.getElementById("found.updates");
var updates = foundUpdates.getElementsByTagName("listitem");
let toInstall = [];
for (let update of updates) {
if (!update.checked)
if (!update.checked) {
logger.info("User chose to cancel update of " + update.label);
update.install.cancel();
continue;
this._installs.push(update.install);
}
toInstall.push(update.install);
}
this._strings = document.getElementById("updateStrings");
this._installing = true;
this.startNextInstall();
this.startInstalls(toInstall);
},
startNextInstall: function gInstallingPage_startNextInstall() {
@ -399,25 +479,35 @@ var gInstallingPage = {
this._currentInstall++;
if (this._installs.length == this._currentInstall) {
Services.obs.notifyObservers(null, "TEST:all-updates-done", null);
this._installing = false;
if (gUpdateWizard.shuttingDown) {
return;
}
var nextPage = this._errors.length > 0 ? "installerrors" : "finished";
document.getElementById("installing").setAttribute("next", nextPage);
document.documentElement.advance();
return;
}
this._installs[this._currentInstall].addListener(this);
this._installs[this._currentInstall].install();
},
let install = this._installs[this._currentInstall];
cancelInstalls: function gInstallingPage_cancelInstalls() {
this._installs[this._currentInstall].removeListener(this);
this._installs[this._currentInstall].cancel();
if (gUpdateWizard.shuttingDown && !AddonManager.shouldAutoUpdate(install.existingAddon)) {
logger.debug("Don't update " + install.existingAddon.id + " in background");
install.cancel();
this.startNextInstall();
return;
}
install.addListener(this);
install.install();
},
/////////////////////////////////////////////////////////////////////////////
// InstallListener
onDownloadStarted: function gInstallingPage_onDownloadStarted(aInstall) {
if (gUpdateWizard.shuttingDown) {
return;
}
var strings = document.getElementById("updateStrings");
var label = strings.getFormattedString("downloadingPrefix", [aInstall.name]);
var actionItem = document.getElementById("actionItem");
@ -425,6 +515,9 @@ var gInstallingPage = {
},
onDownloadProgress: function gInstallingPage_onDownloadProgress(aInstall) {
if (gUpdateWizard.shuttingDown) {
return;
}
var downloadProgress = document.getElementById("downloadProgress");
downloadProgress.value = Math.ceil(100 * aInstall.progress / aInstall.maxProgress);
},
@ -439,6 +532,9 @@ var gInstallingPage = {
},
onInstallStarted: function gInstallingPage_onInstallStarted(aInstall) {
if (gUpdateWizard.shuttingDown) {
return;
}
var strings = document.getElementById("updateStrings");
var label = strings.getFormattedString("installingPrefix", [aInstall.name]);
var actionItem = document.getElementById("actionItem");
@ -446,9 +542,11 @@ var gInstallingPage = {
},
onInstallEnded: function gInstallingPage_onInstallEnded(aInstall, aAddon) {
// Remember that this add-on was updated during startup
AddonManagerPrivate.addStartupChange(AddonManager.STARTUP_CHANGE_CHANGED,
aAddon.id);
if (!gUpdateWizard.shuttingDown) {
// Remember that this add-on was updated during startup
AddonManagerPrivate.addStartupChange(AddonManager.STARTUP_CHANGE_CHANGED,
aAddon.id);
}
this.startNextInstall();
},

Просмотреть файл

@ -474,8 +474,10 @@ this.AddonRepository = {
get cacheEnabled() {
// Act as though caching is disabled if there was an unrecoverable error
// openning the database.
if (!AddonDatabase.databaseOk)
if (!AddonDatabase.databaseOk) {
logger.warn("Cache is disabled because database is not OK");
return false;
}
let preference = PREF_GETADDONS_CACHE_ENABLED;
let enabled = false;
@ -611,12 +613,19 @@ this.AddonRepository = {
this._repopulateCacheInternal(aIds, aCallback, false, aTimeout);
},
_repopulateCacheInternal: function(aIds, aCallback, aSendPerformance, aTimeout) {
_repopulateCacheInternal: function (aIds, aCallback, aSendPerformance, aTimeout) {
// Always call AddonManager updateAddonRepositoryData after we refill the cache
function repopulateAddonManager() {
AddonManagerPrivate.updateAddonRepositoryData(aCallback);
}
logger.debug("Repopulate add-on cache with " + aIds.toSource());
// Completely remove cache if caching is not enabled
if (!this.cacheEnabled) {
logger.debug("Clearing cache because it is disabled");
this._addons = null;
this._pendingCallbacks = null;
AddonDatabase.delete(aCallback);
AddonDatabase.delete(repopulateAddonManager);
return;
}
@ -624,9 +633,10 @@ this.AddonRepository = {
getAddonsToCache(aIds, function repopulateCache_getAddonsToCache(aAddons) {
// Completely remove cache if there are no add-ons to cache
if (aAddons.length == 0) {
logger.debug("Clearing cache because 0 add-ons were requested");
self._addons = null;
self._pendingCallbacks = null;
AddonDatabase.delete(aCallback);
AddonDatabase.delete(repopulateAddonManager);
return;
}
@ -634,12 +644,11 @@ this.AddonRepository = {
searchSucceeded: function repopulateCacheInternal_searchSucceeded(aAddons) {
self._addons = {};
aAddons.forEach(function(aAddon) { self._addons[aAddon.id] = aAddon; });
AddonDatabase.repopulate(aAddons, aCallback);
AddonDatabase.repopulate(aAddons, repopulateAddonManager);
},
searchFailed: function repopulateCacheInternal_searchFailed() {
logger.warn("Search failed when repopulating cache");
if (aCallback)
aCallback();
repopulateAddonManager();
}
}, aSendPerformance, aTimeout);
});
@ -648,7 +657,7 @@ this.AddonRepository = {
/**
* Asynchronously add add-ons to the cache corresponding to the specified
* ids. If caching is disabled, the cache is unchanged and the callback is
* immediatly called if it is defined.
* immediately called if it is defined.
*
* @param aIds
* The array of add-on ids to add to the cache
@ -656,6 +665,7 @@ this.AddonRepository = {
* The optional callback to call once complete
*/
cacheAddons: function AddonRepo_cacheAddons(aIds, aCallback) {
logger.debug("cacheAddons: enabled " + this.cacheEnabled + " IDs " + aIds.toSource());
if (!this.cacheEnabled) {
if (aCallback)
aCallback();
@ -1397,6 +1407,8 @@ this.AddonRepository = {
// Begins a new search if one isn't currently executing
_beginSearch: function(aURI, aMaxResults, aCallback, aHandleResults, aTimeout) {
if (this._searching || aURI == null || aMaxResults <= 0) {
logger.warn("AddonRepository search failed: searching " + this._searching + " aURI " + aURI +
" aMaxResults " + aMaxResults);
aCallback.searchFailed();
return;
}

Просмотреть файл

@ -45,7 +45,7 @@ var gRDF = Cc["@mozilla.org/rdf/rdf-service;1"].
getService(Ci.nsIRDFService);
Cu.import("resource://gre/modules/Log.jsm");
const LOGGER_ID = "addons.updates";
const LOGGER_ID = "addons.update-checker";
// Create a new logger for use by the Addons Update Checker
// (Requires AddonManager.jsm)

Просмотреть файл

@ -3725,6 +3725,7 @@ var XPIProvider = {
let self = this;
XPIDatabase.getVisibleAddons(null, function UARD_getVisibleAddonsCallback(aAddons) {
let pending = aAddons.length;
logger.debug("updateAddonRepositoryData found " + pending + " visible add-ons");
if (pending == 0) {
aCallback();
return;
@ -3735,18 +3736,19 @@ var XPIProvider = {
aCallback();
}
aAddons.forEach(function UARD_forEachCallback(aAddon) {
AddonRepository.getCachedAddonByID(aAddon.id,
for (let addon of aAddons) {
AddonRepository.getCachedAddonByID(addon.id,
function UARD_getCachedAddonCallback(aRepoAddon) {
if (aRepoAddon) {
aAddon._repositoryAddon = aRepoAddon;
aAddon.compatibilityOverrides = aRepoAddon.compatibilityOverrides;
self.updateAddonDisabledState(aAddon);
logger.debug("updateAddonRepositoryData got info for " + addon.id);
addon._repositoryAddon = aRepoAddon;
addon.compatibilityOverrides = aRepoAddon.compatibilityOverrides;
self.updateAddonDisabledState(addon);
}
notifyComplete();
});
});
};
});
},
@ -4795,9 +4797,10 @@ AddonInstall.prototype = {
* be closed before this method returns.
* @param aCallback
* A function to call when all of the add-on manifests have been
* loaded.
* loaded. Because this loadMultipackageManifests is an internal API
* we don't exception-wrap this callback
*/
loadMultipackageManifests: function AI_loadMultipackageManifests(aZipReader,
_loadMultipackageManifests: function AI_loadMultipackageManifests(aZipReader,
aCallback) {
let files = [];
let entries = aZipReader.findEntries("(*.[Xx][Pp][Ii]|*.[Jj][Aa][Rr])");
@ -4842,7 +4845,7 @@ AddonInstall.prototype = {
if (!addon) {
// No valid add-on was found
makeSafe(aCallback)();
aCallback();
return;
}
@ -4891,7 +4894,7 @@ AddonInstall.prototype = {
}, this);
}
else {
makeSafe(aCallback)();
aCallback();
}
},
@ -4971,7 +4974,7 @@ AddonInstall.prototype = {
}
if (this.addon.type == "multipackage") {
this.loadMultipackageManifests(zipreader, function loadManifest_loadMultipackageManifests() {
this._loadMultipackageManifests(zipreader, function loadManifest_loadMultipackageManifests() {
addRepositoryData(self.addon);
});
return;
@ -5251,7 +5254,7 @@ AddonInstall.prototype = {
* The error code to pass to the listeners
*/
downloadFailed: function AI_downloadFailed(aReason, aError) {
logger.warn("Download failed", aError);
logger.warn("Download of " + this.sourceURI.spec + " failed", aError);
this.state = AddonManager.STATE_DOWNLOAD_FAILED;
this.error = aReason;
XPIProvider.removeActiveInstall(this);
@ -5327,18 +5330,20 @@ AddonInstall.prototype = {
// Find and cancel any pending installs for the same add-on in the same
// install location
XPIProvider.installs.forEach(function(aInstall) {
for (let aInstall of XPIProvider.installs) {
if (aInstall.state == AddonManager.STATE_INSTALLED &&
aInstall.installLocation == this.installLocation &&
aInstall.addon.id == this.addon.id)
aInstall.addon.id == this.addon.id) {
logger.debug("Cancelling previous pending install of " + aInstall.addon.id);
aInstall.cancel();
}, this);
}
}
let isUpgrade = this.existingAddon &&
this.existingAddon._installLocation == this.installLocation;
let requiresRestart = XPIProvider.installRequiresRestart(this.addon);
logger.debug("Starting install of " + this.sourceURI.spec);
logger.debug("Starting install of " + this.addon.id + " from " + this.sourceURI.spec);
AddonManagerPrivate.callAddonListeners("onInstalling",
createWrapper(this.addon),
requiresRestart);
@ -5394,7 +5399,7 @@ AddonInstall.prototype = {
stream.close();
}
logger.debug("Staged install of " + this.sourceURI.spec + " ready; waiting for restart.");
logger.debug("Staged install of " + this.addon.id + " from " + this.sourceURI.spec + " ready; waiting for restart.");
this.state = AddonManager.STATE_INSTALLED;
if (isUpgrade) {
delete this.existingAddon.pendingUpgrade;
@ -5856,8 +5861,10 @@ UpdateChecker.prototype = {
// If the existing install has not yet started downloading then send an
// available update notification. If it is already downloading then
// don't send any available update notification
if (currentInstall.state == AddonManager.STATE_AVAILABLE)
if (currentInstall.state == AddonManager.STATE_AVAILABLE) {
logger.debug("Found an existing AddonInstall for " + this.addon.id);
sendUpdateAvailableMessages(this, currentInstall);
}
else
sendUpdateAvailableMessages(this, null);
return;

Просмотреть файл

@ -1311,8 +1311,6 @@ this.XPIDatabase = {
*
* @param aAddon
* The DBAddonInternal to make visible
* @param callback
* A callback to pass the DBAddonInternal to
*/
makeAddonVisible: function XPIDB_makeAddonVisible(aAddon) {
logger.debug("Make addon " + aAddon._key + " visible");

Просмотреть файл

@ -2,6 +2,7 @@
support-files =
addon_about.xul
addon_prefs.xul
cancelCompatCheck.sjs
discovery.html
signed_hotfix.rdf
signed_hotfix.xpi
@ -35,6 +36,7 @@ support-files =
[browser_addonrepository_performance.js]
[browser_bug557956.js]
[browser_bug616841.js]
[browser_cancelCompatCheck.js]
[browser_checkAddonCompatibility.js]
[browser_hotfix.js]
[browser_installssl.js]

Просмотреть файл

@ -425,7 +425,7 @@ add_test(function() {
});
});
// Tests that compatibility overrides are retreived and affect addon
// Tests that compatibility overrides are retrieved and affect addon
// compatibility.
add_test(function() {
Services.prefs.setBoolPref(PREF_STRICT_COMPAT, false);

Просмотреть файл

@ -0,0 +1,536 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Test that we can cancel the add-on compatibility check while it is
// in progress (bug 772484).
// Test framework copied from browser_bug557956.js
const URI_EXTENSION_UPDATE_DIALOG = "chrome://mozapps/content/extensions/update.xul";
const PREF_GETADDONS_BYIDS = "extensions.getAddons.get.url";
const PREF_MIN_PLATFORM_COMPAT = "extensions.minCompatiblePlatformVersion";
let repo = {};
Components.utils.import("resource://gre/modules/addons/AddonRepository.jsm", repo);
/**
* Test add-ons:
*
* Addon minVersion maxVersion Notes
* addon1 0 *
* addon2 0 0
* addon3 0 0
* addon4 1 *
* addon5 0 0 Made compatible by update check
* addon6 0 0 Made compatible by update check
* addon7 0 0 Has a broken update available
* addon8 0 0 Has an update available
* addon9 0 0 Has an update available
* addon10 0 0 Made incompatible by override check
*/
// describe the addons
let ao1 = { file: "browser_bug557956_1", id: "addon1@tests.mozilla.org"};
let ao2 = { file: "browser_bug557956_2", id: "addon2@tests.mozilla.org"};
let ao3 = { file: "browser_bug557956_3", id: "addon3@tests.mozilla.org"};
let ao4 = { file: "browser_bug557956_4", id: "addon4@tests.mozilla.org"};
let ao5 = { file: "browser_bug557956_5", id: "addon5@tests.mozilla.org"};
let ao6 = { file: "browser_bug557956_6", id: "addon6@tests.mozilla.org"};
let ao7 = { file: "browser_bug557956_7", id: "addon7@tests.mozilla.org"};
let ao8 = { file: "browser_bug557956_8_1", id: "addon8@tests.mozilla.org"};
let ao9 = { file: "browser_bug557956_9_1", id: "addon9@tests.mozilla.org"};
let ao10 = { file: "browser_bug557956_10", id: "addon10@tests.mozilla.org"};
// Return a promise that resolves after the specified delay in MS
function delayMS(aDelay) {
let deferred = Promise.defer();
setTimeout(deferred.resolve, aDelay);
return deferred.promise;
}
// Return a promise that resolves when the specified observer topic is notified
function promise_observer(aTopic) {
let deferred = Promise.defer();
Services.obs.addObserver(function observe(aSubject, aObsTopic, aData) {
Services.obs.removeObserver(arguments.callee, aObsTopic);
deferred.resolve([aSubject, aData]);
}, aTopic, false);
return deferred.promise;
}
// Install a set of addons using a bogus update URL so that we can force
// the compatibility update to happen later
// @param aUpdateURL The real update URL to use after the add-ons are installed
function promise_install_test_addons(aAddonList, aUpdateURL) {
info("Starting add-on installs");
var installs = [];
let deferred = Promise.defer();
// Use a blank update URL
Services.prefs.setCharPref(PREF_UPDATEURL, TESTROOT + "missing.rdf");
for (let addon of aAddonList) {
AddonManager.getInstallForURL(TESTROOT + "addons/" + addon.file + ".xpi", function(aInstall) {
installs.push(aInstall);
}, "application/x-xpinstall");
}
var listener = {
installCount: 0,
onInstallEnded: function() {
this.installCount++;
if (this.installCount == installs.length) {
info("Done add-on installs");
// Switch to the test update URL
Services.prefs.setCharPref(PREF_UPDATEURL, aUpdateURL);
deferred.resolve();
}
}
};
for (let install of installs) {
install.addListener(listener);
install.install();
}
return deferred.promise;
}
function promise_addons_by_ids(aAddonIDs) {
info("promise_addons_by_ids " + aAddonIDs.toSource());
let deferred = Promise.defer();
AddonManager.getAddonsByIDs(aAddonIDs, deferred.resolve);
return deferred.promise;
}
function* promise_uninstall_test_addons() {
info("Starting add-on uninstalls");
let addons = yield promise_addons_by_ids([ao1.id, ao2.id, ao3.id, ao4.id, ao5.id,
ao6.id, ao7.id, ao8.id, ao9.id, ao10.id]);
let deferred = Promise.defer();
let uninstallCount = addons.length;
let listener = {
onUninstalled: function(aAddon) {
if (aAddon) {
info("Finished uninstalling " + aAddon.id);
}
if (--uninstallCount == 0) {
info("Done add-on uninstalls");
AddonManager.removeAddonListener(listener);
deferred.resolve();
}
}};
AddonManager.addAddonListener(listener);
for (let addon of addons) {
if (addon)
addon.uninstall();
else
listener.onUninstalled(null);
}
yield deferred.promise;
}
// Returns promise{window}, resolves with a handle to the compatibility
// check window
function promise_open_compatibility_window(aInactiveAddonIds) {
let deferred = Promise.defer();
// This will reset the longer timeout multiplier to 2 which will give each
// test that calls open_compatibility_window a minimum of 60 seconds to
// complete.
requestLongerTimeout(100 /* XXX was 2 */);
var variant = Cc["@mozilla.org/variant;1"].
createInstance(Ci.nsIWritableVariant);
variant.setFromVariant(aInactiveAddonIds);
// Cannot be modal as we want to interract with it, shouldn't cause problems
// with testing though.
var features = "chrome,centerscreen,dialog,titlebar";
var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);
var win = ww.openWindow(null, URI_EXTENSION_UPDATE_DIALOG, "", features, variant);
win.addEventListener("load", function() {
function page_shown(aEvent) {
if (aEvent.target.pageid)
info("Page " + aEvent.target.pageid + " shown");
}
win.removeEventListener("load", arguments.callee, false);
info("Compatibility dialog opened");
win.addEventListener("pageshow", page_shown, false);
win.addEventListener("unload", function() {
win.removeEventListener("unload", arguments.callee, false);
win.removeEventListener("pageshow", page_shown, false);
dump("Compatibility dialog closed\n");
}, false);
deferred.resolve(win);
}, false);
return deferred.promise;
}
function promise_window_close(aWindow) {
let deferred = Promise.defer();
aWindow.addEventListener("unload", function() {
aWindow.removeEventListener("unload", arguments.callee, false);
deferred.resolve(aWindow);
}, false);
return deferred.promise;
}
function promise_page(aWindow, aPageId) {
let deferred = Promise.defer();
var page = aWindow.document.getElementById(aPageId);
page.addEventListener("pageshow", function() {
page.removeEventListener("pageshow", arguments.callee, false);
executeSoon(function() {
deferred.resolve(aWindow);
});
}, false);
return deferred.promise;
}
function get_list_names(aList) {
var items = [];
for (let listItem of aList.childNodes)
items.push(listItem.label);
items.sort();
return items;
}
// These add-ons were inactive in the old application
let inactiveAddonIds = [
ao2.id,
ao4.id,
ao5.id,
ao10.id
];
// Make sure the addons in the list are not installed
function* check_addons_uninstalled(aAddonList) {
let foundList = yield promise_addons_by_ids([addon.id for (addon of aAddonList)]);
for (let i = 0; i < aAddonList.length; i++) {
ok(!foundList[i], "Addon " + aAddonList[i].id + " is not installed");
}
info("Add-on uninstall check complete");
yield true;
}
// Tests that the right add-ons show up in the mismatch dialog and updates can
// be installed
// This is a task-based rewrite of the first test in browser_bug557956.js
// kept here to show the whole process so that other tests in this file can
// pick and choose which steps to perform, but disabled since the logic is already
// tested in browser_bug557956.js.
// add_task(
function start_update() {
// Don't pull compatibility data during add-on install
Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, false);
let addonList = [ao3, ao5, ao6, ao7, ao8, ao9];
yield promise_install_test_addons(addonList, TESTROOT + "cancelCompatCheck.sjs");
// Check that the addons start out not compatible.
let [a5, a6, a8, a9] = yield promise_addons_by_ids([ao5.id, ao6.id, ao8.id, ao9.id]);
ok(!a5.isCompatible, "addon5 should not be compatible");
ok(!a6.isCompatible, "addon6 should not be compatible");
ok(!a8.isCompatible, "addon8 should not be compatible");
ok(!a9.isCompatible, "addon9 should not be compatible");
Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true);
// Check that opening the compatibility window loads and applies
// the compatibility update
let compatWindow = yield promise_open_compatibility_window(inactiveAddonIds);
var doc = compatWindow.document;
compatWindow = yield promise_page(compatWindow, "mismatch");
var items = get_list_names(doc.getElementById("mismatch.incompatible"));
is(items.length, 4, "Should have seen 4 still incompatible items");
is(items[0], "Addon3 1.0", "Should have seen addon3 still incompatible");
is(items[1], "Addon7 1.0", "Should have seen addon7 still incompatible");
is(items[2], "Addon8 1.0", "Should have seen addon8 still incompatible");
is(items[3], "Addon9 1.0", "Should have seen addon9 still incompatible");
ok(a5.isCompatible, "addon5 should be compatible");
ok(a6.isCompatible, "addon6 should be compatible");
// Click next to start finding updates for the addons that are still incompatible
var button = doc.documentElement.getButton("next");
EventUtils.synthesizeMouse(button, 2, 2, { }, compatWindow);
compatWindow = yield promise_page(compatWindow, "found");
ok(doc.getElementById("xpinstallDisabledAlert").hidden,
"Install should be allowed");
var list = doc.getElementById("found.updates");
var items = get_list_names(list);
is(items.length, 3, "Should have seen 3 updates available");
is(items[0], "Addon7 2.0", "Should have seen update for addon7");
is(items[1], "Addon8 2.0", "Should have seen update for addon8");
is(items[2], "Addon9 2.0", "Should have seen update for addon9");
ok(!doc.documentElement.getButton("next").disabled,
"Next button should be enabled");
// Uncheck all
for (let listItem of list.childNodes)
EventUtils.synthesizeMouse(listItem, 2, 2, { }, compatWindow);
ok(doc.documentElement.getButton("next").disabled,
"Next button should not be enabled");
// Check the ones we want to install
for (let listItem of list.childNodes) {
if (listItem.label != "Addon7 2.0")
EventUtils.synthesizeMouse(listItem, 2, 2, { }, compatWindow);
}
var button = doc.documentElement.getButton("next");
EventUtils.synthesizeMouse(button, 2, 2, { }, compatWindow);
compatWindow = yield promise_page(compatWindow, "finished");
var button = doc.documentElement.getButton("finish");
ok(!button.hidden, "Finish button should not be hidden");
ok(!button.disabled, "Finish button should not be disabled");
EventUtils.synthesizeMouse(button, 2, 2, { }, compatWindow);
compatWindow = yield promise_window_close(compatWindow);
// Check that the appropriate add-ons have been updated
let [a8, a9] = yield promise_addons_by_ids(["addon8@tests.mozilla.org",
"addon9@tests.mozilla.org"]);
is(a8.version, "2.0", "addon8 should have updated");
is(a9.version, "2.0", "addon9 should have updated");
yield promise_uninstall_test_addons();
}
// );
// Test what happens when the user cancels during AddonRepository.repopulateCache()
// Add-ons that have updates available should not update if they were disabled before
// For this test, addon8 became disabled during update and addon9 was previously disabled,
// so addon8 should update and addon9 should not
add_task(function cancel_during_repopulate() {
Services.prefs.setBoolPref(PREF_STRICT_COMPAT, true);
Services.prefs.setCharPref(PREF_MIN_PLATFORM_COMPAT, "0");
Services.prefs.setCharPref(PREF_UPDATEURL, TESTROOT + "missing.rdf");
let installsDone = promise_observer("TEST:all-updates-done");
// Don't pull compatibility data during add-on install
Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, false);
// Set up our test addons so that the server-side JS has a 500ms delay to make
// sure we cancel the dialog before we get the data we want to refill our
// AddonRepository cache
let addonList = [ao5, ao8, ao9, ao10];
yield promise_install_test_addons(addonList,
TESTROOT + "cancelCompatCheck.sjs?500");
Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true);
Services.prefs.setCharPref(PREF_GETADDONS_BYIDS, TESTROOT + "browser_bug557956.xml");
let [a5, a8, a9] = yield promise_addons_by_ids([ao5.id, ao8.id, ao9.id]);
ok(!a5.isCompatible, "addon5 should not be compatible");
ok(!a8.isCompatible, "addon8 should not be compatible");
ok(!a9.isCompatible, "addon9 should not be compatible");
let compatWindow = yield promise_open_compatibility_window([ao9.id, ...inactiveAddonIds]);
var doc = compatWindow.document;
yield promise_page(compatWindow, "versioninfo");
// Brief delay to let the update window finish requesting all add-ons and start
// reloading the addon repository
yield delayMS(50);
info("Cancel the compatibility check dialog");
var button = doc.documentElement.getButton("cancel");
EventUtils.synthesizeMouse(button, 2, 2, { }, compatWindow);
info("Waiting for installs to complete");
yield installsDone;
ok(!repo.AddonRepository.isSearching, "Background installs are done");
// There should be no active updates
let getInstalls = Promise.defer();
AddonManager.getAllInstalls(getInstalls.resolve);
let installs = yield getInstalls.promise;
is (installs.length, 0, "There should be no active installs after background installs are done");
// addon8 should have updated in the background,
// addon9 was listed as previously disabled so it should not have updated
let [a5, a8, a9, a10] = yield promise_addons_by_ids([ao5.id, ao8.id, ao9.id, ao10.id]);
ok(a5.isCompatible, "addon5 should be compatible");
ok(a8.isCompatible, "addon8 should have been upgraded");
ok(!a9.isCompatible, "addon9 should not have been upgraded");
ok(!a10.isCompatible, "addon10 should not be compatible");
info("Updates done");
yield promise_uninstall_test_addons();
info("done uninstalling add-ons");
});
// User cancels after repopulateCache, while we're waiting for the addon.findUpdates()
// calls in gVersionInfoPage_onPageShow() to complete
// For this test, both addon8 and addon9 were disabled by this update, but addon8
// is set to not auto-update, so only addon9 should update in the background
add_task(function cancel_during_findUpdates() {
Services.prefs.setBoolPref(PREF_STRICT_COMPAT, true);
Services.prefs.setCharPref(PREF_MIN_PLATFORM_COMPAT, "0");
let observeUpdateDone = promise_observer("TEST:addon-repository-data-updated");
let installsDone = promise_observer("TEST:all-updates-done");
// Don't pull compatibility data during add-on install
Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, false);
// No delay on the .sjs this time because we want the cache to repopulate
let addonList = [ao3, ao5, ao6, ao7, ao8, ao9];
yield promise_install_test_addons(addonList,
TESTROOT + "cancelCompatCheck.sjs");
let [a8] = yield promise_addons_by_ids([ao8.id]);
a8.applyBackgroundUpdates = AddonManager.AUTOUPDATE_DISABLE;
Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true);
let compatWindow = yield promise_open_compatibility_window(inactiveAddonIds);
var doc = compatWindow.document;
yield promise_page(compatWindow, "versioninfo");
info("Waiting for repository-data-updated");
yield observeUpdateDone;
// Quick wait to make sure the findUpdates calls get queued
yield delayMS(5);
info("Cancel the compatibility check dialog");
var button = doc.documentElement.getButton("cancel");
EventUtils.synthesizeMouse(button, 2, 2, { }, compatWindow);
info("Waiting for installs to complete 2");
yield installsDone;
ok(!repo.AddonRepository.isSearching, "Background installs are done 2");
// addon8 should have updated in the background,
// addon9 was listed as previously disabled so it should not have updated
let [a5, a8, a9] = yield promise_addons_by_ids([ao5.id, ao8.id, ao9.id]);
ok(a5.isCompatible, "addon5 should be compatible");
ok(!a8.isCompatible, "addon8 should not have been upgraded");
ok(a9.isCompatible, "addon9 should have been upgraded");
let getInstalls = Promise.defer();
AddonManager.getAllInstalls(getInstalls.resolve);
let installs = yield getInstalls.promise;
is (installs.length, 0, "There should be no active installs after the dialog is cancelled 2");
info("findUpdates done");
yield promise_uninstall_test_addons();
});
// Cancelling during the 'mismatch' screen allows add-ons that can auto-update
// to continue updating in the background and cancels any other updates
// Same conditions as the previous test - addon8 and addon9 have updates available,
// addon8 is set to not auto-update so only addon9 should become compatible
add_task(function cancel_mismatch() {
Services.prefs.setBoolPref(PREF_STRICT_COMPAT, true);
Services.prefs.setCharPref(PREF_MIN_PLATFORM_COMPAT, "0");
let observeUpdateDone = promise_observer("TEST:addon-repository-data-updated");
let installsDone = promise_observer("TEST:all-updates-done");
// Don't pull compatibility data during add-on install
Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, false);
// No delay on the .sjs this time because we want the cache to repopulate
let addonList = [ao3, ao5, ao6, ao7, ao8, ao9];
yield promise_install_test_addons(addonList,
TESTROOT + "cancelCompatCheck.sjs");
let [a8] = yield promise_addons_by_ids([ao8.id]);
a8.applyBackgroundUpdates = AddonManager.AUTOUPDATE_DISABLE;
// Check that the addons start out not compatible.
let [a3, a7, a8, a9] = yield promise_addons_by_ids([ao3.id, ao7.id, ao8.id, ao9.id]);
ok(!a3.isCompatible, "addon3 should not be compatible");
ok(!a7.isCompatible, "addon7 should not be compatible");
ok(!a8.isCompatible, "addon8 should not be compatible");
ok(!a9.isCompatible, "addon9 should not be compatible");
Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true);
let compatWindow = yield promise_open_compatibility_window(inactiveAddonIds);
var doc = compatWindow.document;
info("Wait for mismatch page");
yield promise_page(compatWindow, "mismatch");
info("Click the Don't Check button");
var button = doc.documentElement.getButton("cancel");
EventUtils.synthesizeMouse(button, 2, 2, { }, compatWindow);
yield promise_window_close(compatWindow);
info("Waiting for installs to complete in cancel_mismatch");
yield installsDone;
// addon8 should not have updated in the background,
// addon9 was listed as previously disabled so it should not have updated
let [a5, a8, a9] = yield promise_addons_by_ids([ao5.id, ao8.id, ao9.id]);
ok(a5.isCompatible, "addon5 should be compatible");
ok(!a8.isCompatible, "addon8 should not have been upgraded");
ok(a9.isCompatible, "addon9 should have been upgraded");
// Make sure there are no pending addon installs
let pInstalls = Promise.defer();
AddonManager.getAllInstalls(pInstalls.resolve);
let installs = yield pInstalls.promise;
ok(installs.length == 0, "No remaining add-on installs (" + installs.toSource() + ")");
yield promise_uninstall_test_addons();
yield check_addons_uninstalled(addonList);
});
// Cancelling during the 'mismatch' screen with only add-ons that have
// no updates available
add_task(function cancel_mismatch_no_updates() {
Services.prefs.setBoolPref(PREF_STRICT_COMPAT, true);
Services.prefs.setCharPref(PREF_MIN_PLATFORM_COMPAT, "0");
let observeUpdateDone = promise_observer("TEST:addon-repository-data-updated");
// Don't pull compatibility data during add-on install
Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, false);
// No delay on the .sjs this time because we want the cache to repopulate
let addonList = [ao3, ao5, ao6];
yield promise_install_test_addons(addonList,
TESTROOT + "cancelCompatCheck.sjs");
// Check that the addons start out not compatible.
let [a3, a5, a6] = yield promise_addons_by_ids([ao3.id, ao5.id, ao6.id]);
ok(!a3.isCompatible, "addon3 should not be compatible");
ok(!a5.isCompatible, "addon7 should not be compatible");
ok(!a6.isCompatible, "addon8 should not be compatible");
Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true);
let compatWindow = yield promise_open_compatibility_window(inactiveAddonIds);
var doc = compatWindow.document;
info("Wait for mismatch page");
yield promise_page(compatWindow, "mismatch");
info("Click the Don't Check button");
var button = doc.documentElement.getButton("cancel");
EventUtils.synthesizeMouse(button, 2, 2, { }, compatWindow);
yield promise_window_close(compatWindow);
let [a3, a5, a6] = yield promise_addons_by_ids([ao3.id, ao5.id, ao6.id]);
ok(!a3.isCompatible, "addon3 should not be compatible");
ok(a5.isCompatible, "addon5 should have become compatible");
ok(a6.isCompatible, "addon6 should have become compatible");
// Make sure there are no pending addon installs
let pInstalls = Promise.defer();
AddonManager.getAllInstalls(pInstalls.resolve);
let installs = yield pInstalls.promise;
ok(installs.length == 0, "No remaining add-on installs (" + installs.toSource() + ")");
yield promise_uninstall_test_addons();
yield check_addons_uninstalled(addonList);
});

Просмотреть файл

@ -0,0 +1,44 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Delay before responding to an HTTP call attempting to read
// an addon update RDF file
function handleRequest(req, resp) {
resp.processAsync();
resp.setHeader("Cache-Control", "no-cache, no-store", false);
resp.setHeader("Content-Type", "text/xml;charset=utf-8", false);
let file = null;
getObjectState("SERVER_ROOT", function(serverRoot)
{
file = serverRoot.getFile("browser/toolkit/mozapps/extensions/test/browser/browser_bug557956.rdf");
});
dump("*** cancelCompatCheck.sjs: " + file.path + "\n");
let fstream = Components.classes["@mozilla.org/network/file-input-stream;1"].
createInstance(Components.interfaces.nsIFileInputStream);
fstream.init(file, -1, 0, 0);
let cstream = null;
cstream = Components.classes["@mozilla.org/intl/converter-input-stream;1"].
createInstance(Components.interfaces.nsIConverterInputStream);
cstream.init(fstream, "UTF-8", 0, 0);
// The delay can be passed on the query string
let delay = req.queryString + 0;
timer = Components.classes["@mozilla.org/timer;1"].
createInstance(Components.interfaces.nsITimer);
timer.init(function sendFile() {
dump("cancelCompatCheck: starting to send file\n");
let (str = {}) {
let read = 0;
do {
// read as much as we can and put it in str.value
read = cstream.readString(0xffffffff, str);
resp.write(str.value);
} while (read != 0);
}
cstream.close();
resp.finish();
}, delay, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
}

Просмотреть файл

@ -89,6 +89,21 @@ for (let pref of gRestorePrefs) {
// Turn logging on for all tests
Services.prefs.setBoolPref(PREF_LOGGING_ENABLED, true);
// Helper to register test failures and close windows if any are left open
function checkOpenWindows(aWindowID) {
let windows = Services.wm.getEnumerator(aWindowID);
let found = false;
while (windows.hasMoreElements()) {
let win = windows.getNext().QueryInterface(Ci.nsIDOMWindow);
if (!win.closed) {
found = true;
win.close();
}
}
if (found)
ok(false, "Found unexpected " + aWindowID + " window still open");
}
registerCleanupFunction(function() {
// Restore prefs
for (let pref of gRestorePrefs) {
@ -103,24 +118,9 @@ registerCleanupFunction(function() {
}
// Throw an error if the add-ons manager window is open anywhere
var windows = Services.wm.getEnumerator("Addons:Manager");
if (windows.hasMoreElements())
ok(false, "Found unexpected add-ons manager window still open");
while (windows.hasMoreElements())
windows.getNext().QueryInterface(Ci.nsIDOMWindow).close();
windows = Services.wm.getEnumerator("Addons:Compatibility");
if (windows.hasMoreElements())
ok(false, "Found unexpected add-ons compatibility window still open");
while (windows.hasMoreElements())
windows.getNext().QueryInterface(Ci.nsIDOMWindow).close();
windows = Services.wm.getEnumerator("Addons:Install");
if (windows.hasMoreElements())
ok(false, "Found unexpected add-ons installation window still open");
while (windows.hasMoreElements())
windows.getNext().QueryInterface(Ci.nsIDOMWindow).close();
checkOpenWindows("Addons:Manager");
checkOpenWindows("Addons:Compatibility");
checkOpenWindows("Addons:Install");
// We can for now know that getAllInstalls actually calls its callback before
// it returns so this will complete before the next test start.