Bug 412819: Allow upgrading an add-on to an add-on with a different ID. r=robstrong, a=blocks-betaN

This commit is contained in:
Dave Townsend 2010-11-24 14:43:51 -08:00
parent a8abb4a458
commit cf9c75e24f
12 changed files with 783 additions and 30 deletions

View File

@ -1719,17 +1719,8 @@ var XPIProvider = {
}
}
LOG("Processing install of " + id + " in " + aLocation.name);
try {
var addonInstallLocation = aLocation.installAddon(id, stageDirEntry);
}
catch (e) {
ERROR("Failed to install staged add-on " + id + " in " + aLocation.name,
e);
continue;
}
aManifests[aLocation.name][id] = null;
let existingAddonID = null;
// Check for a cached AddonInternal for this add-on, it may contain
// updated compatibility information
@ -1746,7 +1737,7 @@ var XPIProvider = {
fis.init(jsonfile, -1, 0, 0);
aManifests[aLocation.name][id] = json.decodeFromStream(fis,
jsonfile.fileSize);
aManifests[aLocation.name][id]._sourceBundle = addonInstallLocation;
existingAddonID = aManifests[aLocation.name][id].existingAddonID;
}
catch (e) {
ERROR("Unable to read add-on manifest for " + id + " in " +
@ -1756,6 +1747,20 @@ var XPIProvider = {
fis.close();
}
}
LOG("Processing install of " + id + " in " + aLocation.name);
try {
var addonInstallLocation = aLocation.installAddon(id, stageDirEntry,
existingAddonID);
if (id in aManifests[aLocation.name])
aManifests[aLocation.name][id]._sourceBundle = addonInstallLocation;
}
catch (e) {
ERROR("Failed to install staged add-on " + id + " in " + aLocation.name,
e);
delete aManifests[aLocation.name][id];
continue;
}
}
entries.close();
@ -5464,12 +5469,21 @@ AddonInstall.prototype = {
downloadCompleted: function() {
let self = this;
XPIDatabase.getVisibleAddonForID(this.addon.id, function(aAddon) {
self.existingAddon = aAddon;
if (aAddon)
self.addon.userDisabled = aAddon.userDisabled;
self.addon.updateDate = Date.now();
self.addon.installDate = aAddon ? aAddon.installDate : self.addon.updateDate;
self.existingAddon = aAddon;
self.state = AddonManager.STATE_DOWNLOADED;
self.addon.updateDate = Date.now();
if (self.existingAddon) {
self.addon.existingAddonID = self.existingAddon.id;
self.addon.userDisabled = self.existingAddon.userDisabled;
self.addon.installDate = self.existingAddon.installDate;
}
else {
self.addon.installDate = self.addon.updateDate;
}
if (AddonManagerPrivate.callInstallListeners("onDownloadEnded",
self.listeners,
self.wrapper)) {
@ -5618,7 +5632,9 @@ AddonInstall.prototype = {
}
// Install the new add-on into its final location
let file = this.installLocation.installAddon(this.addon.id, stagedAddon);
let existingAddonID = this.existingAddon ? this.existingAddon.id : null;
let file = this.installLocation.installAddon(this.addon.id, stagedAddon,
existingAddonID);
cleanStagingDir(stagedAddon.parent, []);
// Update the metadata in the database
@ -6770,28 +6786,37 @@ DirectoryInstallLocation.prototype = {
* The ID of the add-on to install
* @param aSource
* The source nsIFile to install from
* @param aExistingAddonID
* The ID of an existing add-on to uninstall at the same time
* @return an nsIFile indicating where the add-on was installed to
*/
installAddon: function DirInstallLocation_installAddon(aId, aSource) {
installAddon: function DirInstallLocation_installAddon(aId, aSource, aExistingAddonID) {
let trashDir = this.getTrashDir();
let transaction = new SafeMoveOperation();
let file = this._directory.clone().QueryInterface(Ci.nsILocalFile);
file.append(aId);
let self = this;
function moveOldAddon(aId) {
let file = self._directory.clone().QueryInterface(Ci.nsILocalFile);
file.append(aId);
// If any of these operations fails the finally block will clean up the
// temporary directory
try {
if (file.exists())
transaction.move(file, trashDir);
file = this._directory.clone().QueryInterface(Ci.nsILocalFile);
file = self._directory.clone().QueryInterface(Ci.nsILocalFile);
file.append(aId + ".xpi");
if (file.exists()) {
Services.obs.notifyObservers(file, "flush-cache-entry", null);
transaction.move(file, trashDir);
}
}
// If any of these operations fails the finally block will clean up the
// temporary directory
try {
moveOldAddon(aId);
if (aExistingAddonID && aExistingAddonID != aId)
moveOldAddon(aExistingAddonID);
if (aSource.isFile())
Services.obs.notifyObservers(aSource, "flush-cache-entry", null);
@ -6815,6 +6840,12 @@ DirectoryInstallLocation.prototype = {
this._FileToIDMap[newFile.path] = aId;
this._IDToFileMap[aId] = newFile;
if (aExistingAddonID && aExistingAddonID != aId &&
aExistingAddonID in this._IDToFileMap) {
delete this._FileToIDMap[this._IDToFileMap[aExistingAddonID]];
delete this._IDToFileMap[aExistingAddonID];
}
return newFile;
},

View File

@ -0,0 +1,24 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>addon2@tests.mozilla.org</em:id>
<em:version>2.0</em:version>
<em:updateURL>http://localhost:4444/data/test_updateid.rdf</em:updateURL>
<!-- Front End MetaData -->
<em:name>Test 2</em:name>
<em:description>Test Description</em:description>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>1</em:minVersion>
<em:maxVersion>1</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>

View File

@ -0,0 +1,24 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>addon2@tests.mozilla.org</em:id>
<em:version>5.0</em:version>
<em:updateURL>http://localhost:4444/data/test_updateid.rdf</em:updateURL>
<!-- Front End MetaData -->
<em:name>Test 2</em:name>
<em:description>Test Description</em:description>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>1</em:minVersion>
<em:maxVersion>1</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>

View File

@ -0,0 +1,21 @@
Components.utils.import("resource://gre/modules/Services.jsm");
function install(data, reason) {
Services.prefs.setIntPref("bootstraptest.installed_version", 3);
Services.prefs.setIntPref("bootstraptest.install_reason", reason);
}
function startup(data, reason) {
Services.prefs.setIntPref("bootstraptest.active_version", 3);
Services.prefs.setIntPref("bootstraptest.startup_reason", reason);
}
function shutdown(data, reason) {
Services.prefs.setIntPref("bootstraptest.active_version", 0);
Services.prefs.setIntPref("bootstraptest.shutdown_reason", reason);
}
function uninstall(data, reason) {
Services.prefs.setIntPref("bootstraptest.installed_version", 0);
Services.prefs.setIntPref("bootstraptest.uninstall_reason", reason);
}

View File

@ -0,0 +1,25 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>addon3@tests.mozilla.org</em:id>
<em:version>3.0</em:version>
<em:updateURL>http://localhost:4444/data/test_updateid.rdf</em:updateURL>
<em:bootstrap>true</em:bootstrap>
<!-- Front End MetaData -->
<em:name>Test 3</em:name>
<em:description>Test Description</em:description>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>1</em:minVersion>
<em:maxVersion>1</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>

View File

@ -0,0 +1,21 @@
Components.utils.import("resource://gre/modules/Services.jsm");
function install(data, reason) {
Services.prefs.setIntPref("bootstraptest.installed_version", 4);
Services.prefs.setIntPref("bootstraptest.install_reason", reason);
}
function startup(data, reason) {
Services.prefs.setIntPref("bootstraptest.active_version", 4);
Services.prefs.setIntPref("bootstraptest.startup_reason", reason);
}
function shutdown(data, reason) {
Services.prefs.setIntPref("bootstraptest.active_version", 0);
Services.prefs.setIntPref("bootstraptest.shutdown_reason", reason);
}
function uninstall(data, reason) {
Services.prefs.setIntPref("bootstraptest.installed_version", 0);
Services.prefs.setIntPref("bootstraptest.uninstall_reason", reason);
}

View File

@ -0,0 +1,25 @@
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>addon4@tests.mozilla.org</em:id>
<em:version>4.0</em:version>
<em:updateURL>http://localhost:4444/data/test_updateid.rdf</em:updateURL>
<em:bootstrap>true</em:bootstrap>
<!-- Front End MetaData -->
<em:name>Test 4</em:name>
<em:description>Test Description</em:description>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>1</em:minVersion>
<em:maxVersion>1</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>

View File

@ -73,6 +73,7 @@ _MAIN_TEST_FILES = \
browser_manualupdates.js \
browser_globalwarnings.js \
browser_eula.js \
browser_updateid.js \
$(NULL)
_TEST_FILES = \

View File

@ -0,0 +1,80 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Tests that updates that change an add-on's ID show up correctly in the UI
var gProvider;
var gManagerWindow;
var gCategoryUtilities;
var gApp = document.getElementById("bundle_brand").getString("brandShortName");
function test() {
waitForExplicitFinish();
gProvider = new MockProvider();
gProvider.createAddons([{
id: "addon1@tests.mozilla.org",
name: "manually updating addon",
version: "1.0",
applyBackgroundUpdates: AddonManager.AUTOUPDATE_DISABLE
}]);
open_manager("addons://list/extension", function(aWindow) {
gManagerWindow = aWindow;
gCategoryUtilities = new CategoryUtilities(gManagerWindow);
run_next_test();
});
}
function end_test() {
close_manager(gManagerWindow, function() {
finish();
});
}
add_test(function() {
gCategoryUtilities.openType("extension", function() {
gProvider.createInstalls([{
name: "updated add-on",
existingAddon: gProvider.addons[0],
version: "2.0"
}]);
var newAddon = new MockAddon("addon2@tests.mozilla.org");
newAddon.name = "updated add-on";
newAddon.version = "2.0";
newAddon.pendingOperations = AddonManager.PENDING_INSTALL;
gProvider.installs[0]._addonToInstall = newAddon;
var item = get_addon_element(gManagerWindow, "addon1@tests.mozilla.org");
is(item._version.value, "1.0", "Should still show the old version in the normal list");
var name = gManagerWindow.document.getAnonymousElementByAttribute(item, "anonid", "name");
is(name.value, "manually updating addon", "Should show the old name in the list");
var update = gManagerWindow.document.getAnonymousElementByAttribute(item, "anonid", "update-btn");
is_element_visible(update, "Update button should be visible");
item = get_addon_element(gManagerWindow, "addon2@tests.mozilla.org");
is(item, null, "Should not show the new version in the list");
run_next_test();
});
});
add_test(function() {
var item = get_addon_element(gManagerWindow, "addon1@tests.mozilla.org");
var update = gManagerWindow.document.getAnonymousElementByAttribute(item, "anonid", "update-btn");
EventUtils.synthesizeMouseAtCenter(update, { }, gManagerWindow);
var pending = gManagerWindow.document.getAnonymousElementByAttribute(item, "anonid", "pending");
is_element_visible(pending, "Pending message should be visible");
is(pending.textContent,
get_string("notification.upgrade", "manually updating addon", gApp),
"Pending message should be correct");
item = get_addon_element(gManagerWindow, "addon2@tests.mozilla.org");
is(item, null, "Should not show the new version in the list");
run_next_test();
});

View File

@ -291,6 +291,14 @@ function wait_for_window_open(aCallback) {
});
}
function get_string(aName) {
var bundle = Services.strings.createBundle("chrome://mozapps/locale/extensions/extensions.properties");
if (arguments.length == 1)
return bundle.GetStringFromName(aName);
var args = Array.slice(arguments, 1);
return bundle.formatStringFromName(aName, args, args.length);
}
function is_hidden(aElement) {
var style = aElement.ownerDocument.defaultView.getComputedStyle(aElement, "");
if (style.display == "none")
@ -982,6 +990,22 @@ MockInstall.prototype = {
return;
}
// Adding addon to MockProvider to be implemented when needed
if (this._addonToInstall)
this.addon = this._addonToInstall;
else {
this.addon = new MockAddon("", this.name, this.type);
this.addon.version = this.version;
this.addon.pendingOperations = AddonManager.PENDING_INSTALL;
}
this.addon.install = this;
if (this.existingAddon) {
if (!this.addon.id)
this.addon.id = this.existingAddon.id;
this.existingAddon.pendingUpgrade = this.addon;
this.existingAddon.pendingOperations |= AddonManager.PENDING_UPGRADE;
}
this.state = AddonManager.STATE_DOWNLOADED;
this.callListeners("onDownloadEnded");
@ -993,13 +1017,7 @@ MockInstall.prototype = {
return;
}
// Adding addon to MockProvider to be implemented when needed
if (this._addonToInstall)
this.addon = this._addonToInstall;
else {
this.addon = new MockAddon("", this.name, this.type);
this.addon.pendingOperations = AddonManager.PENDING_INSTALL;
}
AddonManagerPrivate.callAddonListeners("onInstalling", this.addon);
this.state = AddonManager.STATE_INSTALLED;
this.callListeners("onInstallEnded");

View File

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:extension:addon1@tests.mozilla.org">
<em:updates>
<Seq>
<li>
<Description>
<em:version>2.0</em:version>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>1</em:minVersion>
<em:maxVersion>1</em:maxVersion>
<em:updateLink>http://localhost:4444/addons/test_updateid2_2.xpi</em:updateLink>
</Description>
</em:targetApplication>
</Description>
</li>
</Seq>
</em:updates>
</Description>
<Description about="urn:mozilla:extension:addon2@tests.mozilla.org">
<em:updates>
<Seq>
<li>
<Description>
<em:version>3.0</em:version>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>1</em:minVersion>
<em:maxVersion>1</em:maxVersion>
<em:updateLink>http://localhost:4444/addons/test_updateid3_3.xpi</em:updateLink>
</Description>
</em:targetApplication>
</Description>
</li>
</Seq>
</em:updates>
</Description>
<Description about="urn:mozilla:extension:addon3@tests.mozilla.org">
<em:updates>
<Seq>
<li>
<Description>
<em:version>4.0</em:version>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>1</em:minVersion>
<em:maxVersion>1</em:maxVersion>
<em:updateLink>http://localhost:4444/addons/test_updateid4_4.xpi</em:updateLink>
</Description>
</em:targetApplication>
</Description>
</li>
</Seq>
</em:updates>
</Description>
<Description about="urn:mozilla:extension:addon4@tests.mozilla.org">
<em:updates>
<Seq>
<li>
<Description>
<em:version>5.0</em:version>
<em:targetApplication>
<Description>
<em:id>xpcshell@tests.mozilla.org</em:id>
<em:minVersion>1</em:minVersion>
<em:maxVersion>1</em:maxVersion>
<em:updateLink>http://localhost:4444/addons/test_updateid2_5.xpi</em:updateLink>
</Description>
</em:targetApplication>
</Description>
</li>
</Seq>
</em:updates>
</Description>
</RDF>

View File

@ -0,0 +1,397 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// This verifies that updating an add-on to a new ID works
// The test extension uses an insecure update url.
Services.prefs.setBoolPref("extensions.checkUpdateSecurity", false);
do_load_httpd_js();
var testserver;
const profileDir = gProfD.clone();
profileDir.append("extensions");
function resetPrefs() {
Services.prefs.setIntPref("bootstraptest.active_version", -1);
Services.prefs.setIntPref("bootstraptest.installed_version", -1);
Services.prefs.setIntPref("bootstraptest.startup_reason", -1);
Services.prefs.setIntPref("bootstraptest.shutdown_reason", -1);
Services.prefs.setIntPref("bootstraptest.install_reason", -1);
Services.prefs.setIntPref("bootstraptest.uninstall_reason", -1);
}
function getActiveVersion() {
return Services.prefs.getIntPref("bootstraptest.active_version");
}
function getInstalledVersion() {
return Services.prefs.getIntPref("bootstraptest.installed_version");
}
function run_test() {
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
// Create and configure the HTTP server.
testserver = new nsHttpServer();
testserver.registerDirectory("/data/", do_get_file("data"));
testserver.registerDirectory("/addons/", do_get_file("addons"));
testserver.start(4444);
do_test_pending();
run_test_1();
}
function end_test() {
testserver.stop(do_test_finished);
}
function installUpdate(aInstall, aCallback) {
aInstall.addListener({
onInstallEnded: function(aInstall) {
aCallback(aInstall);
}
});
aInstall.install();
}
// Verify that an update to an add-on with a new ID uninstalls the old add-on
function run_test_1() {
writeInstallRDFForExtension({
id: "addon1@tests.mozilla.org",
version: "1.0",
updateURL: "http://localhost:4444/data/test_updateid.rdf",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}],
name: "Test Addon 1",
}, profileDir);
startupManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1) {
do_check_neq(a1, null);
do_check_eq(a1.version, "1.0");
a1.findUpdates({
onUpdateAvailable: function(addon, install) {
do_check_eq(install.name, addon.name);
do_check_eq(install.version, "2.0");
do_check_eq(install.state, AddonManager.STATE_AVAILABLE);
do_check_eq(install.existingAddon, a1);
installUpdate(install, check_test_1);
}
}, AddonManager.UPDATE_WHEN_USER_REQUESTED);
});
}
function check_test_1(install) {
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1) {
// Existing add-on should have a pending upgrade
do_check_neq(a1.pendingUpgrade, null);
do_check_eq(a1.pendingUpgrade.id, "addon2@tests.mozilla.org");
do_check_eq(a1.pendingUpgrade.install.existingAddon, a1);
restartManager();
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org"], function([a1, a2]) {
// Should have uninstalled the old and installed the new
do_check_eq(a1, null);
do_check_neq(a2, null);
a2.uninstall();
restartManager();
shutdownManager();
run_test_2();
});
});
}
// Test that when the new add-on already exists we just upgrade that
function run_test_2() {
writeInstallRDFForExtension({
id: "addon1@tests.mozilla.org",
version: "1.0",
updateURL: "http://localhost:4444/data/test_updateid.rdf",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}],
name: "Test Addon 1",
}, profileDir);
writeInstallRDFForExtension({
id: "addon2@tests.mozilla.org",
version: "1.0",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}],
name: "Test Addon 2",
}, profileDir);
startupManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1) {
do_check_neq(a1, null);
do_check_eq(a1.version, "1.0");
a1.findUpdates({
onUpdateAvailable: function(addon, install) {
installUpdate(install, check_test_2);
}
}, AddonManager.UPDATE_WHEN_USER_REQUESTED);
});
}
function check_test_2(install) {
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org"], function([a1, a2]) {
do_check_eq(a1.pendingUpgrade, null);
// Existing add-on should have a pending upgrade
do_check_neq(a2.pendingUpgrade, null);
do_check_eq(a2.pendingUpgrade.id, "addon2@tests.mozilla.org");
do_check_eq(a2.pendingUpgrade.install.existingAddon, a2);
restartManager();
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org"], function([a1, a2]) {
// Should have uninstalled the old and installed the new
do_check_neq(a1, null);
do_check_neq(a2, null);
a1.uninstall();
a2.uninstall();
restartManager();
shutdownManager();
run_test_3();
});
});
}
// Test that we rollback correctly when removing the old add-on fails
function run_test_3() {
// This test only works on Windows
if (!("nsIWindowsRegKey" in AM_Ci)) {
run_test_4();
return;
}
writeInstallRDFForExtension({
id: "addon1@tests.mozilla.org",
version: "1.0",
updateURL: "http://localhost:4444/data/test_updateid.rdf",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}],
name: "Test Addon 1",
}, profileDir);
startupManager();
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1) {
do_check_neq(a1, null);
do_check_eq(a1.version, "1.0");
a1.findUpdates({
onUpdateAvailable: function(addon, install) {
installUpdate(install, check_test_3);
}
}, AddonManager.UPDATE_WHEN_USER_REQUESTED);
});
}
function check_test_3(install) {
AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1) {
// Existing add-on should have a pending upgrade
do_check_neq(a1.pendingUpgrade, null);
do_check_eq(a1.pendingUpgrade.id, "addon2@tests.mozilla.org");
do_check_eq(a1.pendingUpgrade.install.existingAddon, a1);
// Lock the old add-on open so it can't be uninstalled
var file = profileDir.clone();
file.append("addon1@tests.mozilla.org");
if (!file.exists())
file.leafName += ".xpi";
else
file.append("install.rdf");
var fstream = AM_Cc["@mozilla.org/network/file-output-stream;1"].
createInstance(AM_Ci.nsIFileOutputStream);
fstream.init(file, FileUtils.MODE_APPEND | FileUtils.MODE_WRONLY, FileUtils.PERMS_FILE, 0);
restartManager();
fstream.close();
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org"], function([a1, a2]) {
// Should not have installed the new add-on
do_check_neq(a1, null);
do_check_eq(a2, null);
a1.uninstall();
restartManager();
shutdownManager();
run_test_4();
});
});
}
// Tests that upgrading to a bootstrapped add-on works but requires a restart
function run_test_4() {
writeInstallRDFForExtension({
id: "addon2@tests.mozilla.org",
version: "2.0",
updateURL: "http://localhost:4444/data/test_updateid.rdf",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}],
name: "Test Addon 2",
}, profileDir);
startupManager();
resetPrefs();
AddonManager.getAddonByID("addon2@tests.mozilla.org", function(a2) {
do_check_neq(a2, null);
do_check_eq(a2.version, "2.0");
a2.findUpdates({
onUpdateAvailable: function(addon, install) {
installUpdate(install, check_test_4);
}
}, AddonManager.UPDATE_WHEN_USER_REQUESTED);
});
}
function check_test_4() {
AddonManager.getAddonsByIDs(["addon2@tests.mozilla.org",
"addon3@tests.mozilla.org"], function([a2, a3]) {
// Should still be pending install even though the new add-on is restartless
do_check_neq(a2, null);
do_check_eq(a3, null);
do_check_neq(a2.pendingUpgrade, null);
do_check_eq(a2.pendingUpgrade.id, "addon3@tests.mozilla.org");
do_check_eq(getInstalledVersion(), -1);
do_check_eq(getActiveVersion(), -1);
restartManager();
AddonManager.getAddonsByIDs(["addon2@tests.mozilla.org",
"addon3@tests.mozilla.org"], function([a2, a3]) {
// Should have updated
do_check_eq(a2, null);
do_check_neq(a3, null);
do_check_eq(getInstalledVersion(), 3);
do_check_eq(getActiveVersion(), 3);
run_test_5();
});
});
}
// Tests that upgrading to another bootstrapped add-on works without a restart
function run_test_5() {
AddonManager.getAddonByID("addon3@tests.mozilla.org", function(a3) {
do_check_neq(a3, null);
do_check_eq(a3.version, "3.0");
a3.findUpdates({
onUpdateAvailable: function(addon, install) {
installUpdate(install, check_test_5);
}
}, AddonManager.UPDATE_WHEN_USER_REQUESTED);
});
}
function check_test_5() {
AddonManager.getAddonsByIDs(["addon3@tests.mozilla.org",
"addon4@tests.mozilla.org"], function([a3, a4]) {
// Should have updated
do_check_eq(a3, null);
do_check_neq(a4, null);
do_check_eq(getInstalledVersion(), 4);
do_check_eq(getActiveVersion(), 4);
restartManager();
AddonManager.getAddonsByIDs(["addon3@tests.mozilla.org",
"addon4@tests.mozilla.org"], function([a3, a4]) {
// Should still be gone
do_check_eq(a3, null);
do_check_neq(a4, null);
do_check_eq(getInstalledVersion(), 4);
do_check_eq(getActiveVersion(), 4);
run_test_6();
});
});
}
// Tests that upgrading to a non-bootstrapped add-on works but requires a restart
function run_test_6() {
AddonManager.getAddonByID("addon4@tests.mozilla.org", function(a4) {
do_check_neq(a4, null);
do_check_eq(a4.version, "4.0");
a4.findUpdates({
onUpdateAvailable: function(addon, install) {
installUpdate(install, check_test_6);
}
}, AddonManager.UPDATE_WHEN_USER_REQUESTED);
});
}
function check_test_6() {
AddonManager.getAddonsByIDs(["addon4@tests.mozilla.org",
"addon2@tests.mozilla.org"], function([a4, a2]) {
// Should still be pending install even though the old add-on is restartless
do_check_neq(a4, null);
do_check_eq(a2, null);
do_check_neq(a4.pendingUpgrade, null);
do_check_eq(a4.pendingUpgrade.id, "addon2@tests.mozilla.org");
do_check_eq(getInstalledVersion(), 4);
do_check_eq(getActiveVersion(), 4);
restartManager();
AddonManager.getAddonsByIDs(["addon4@tests.mozilla.org",
"addon2@tests.mozilla.org"], function([a4, a2]) {
// Should have updated
do_check_eq(a4, null);
do_check_neq(a2, null);
// TODO bug 613294, uninstall methods aren't called in this case at the moment
do_check_eq(getInstalledVersion(), 4);
do_check_eq(getActiveVersion(), 0);
end_test();
});
});
}