зеркало из https://github.com/mozilla/gecko-dev.git
Bug 772484 - Allow user to cancel add-on update check and clean up correctly when they do. r=Unfocused
This commit is contained in:
Родитель
e14fb8212b
Коммит
9f4c400488
|
@ -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.
|
||||
|
|
Загрузка…
Ссылка в новой задаче