Bug 1303418 - Don't allow upgrades that change the addon ID. r=mossop, a=ritu
authorAndrew Swan <aswan@mozilla.com>
Fri, 16 Sep 2016 15:00:18 -0700
changeset 357987 3a82ff00dbb82a18dc3eb000a9df86177e640323
parent 357986 c0c615ba525b599947e497f31874caf75fda9998
child 357988 9911bd94e79f7ac61ba01aed3cc159c0fa1fc38f
push id1324
push usermtabara@mozilla.com
push dateMon, 16 Jan 2017 13:07:44 +0000
treeherdermozilla-release@a01c49833940 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmossop, ritu
bugs1303418
milestone51.0a2
Bug 1303418 - Don't allow upgrades that change the addon ID. r=mossop, a=ritu MozReview-Commit-ID: JHINo8ShmeI
toolkit/mozapps/extensions/AddonManager.jsm
toolkit/mozapps/extensions/internal/XPIProvider.jsm
toolkit/mozapps/extensions/test/addons/test_update_multi1/bootstrap.js
toolkit/mozapps/extensions/test/addons/test_update_multi1/install.rdf
toolkit/mozapps/extensions/test/addons/test_update_multi2/addon.xpi
toolkit/mozapps/extensions/test/addons/test_update_multi2/install.rdf
toolkit/mozapps/extensions/test/addons/test_updateid1/bootstrap.js
toolkit/mozapps/extensions/test/addons/test_updateid1/install.rdf
toolkit/mozapps/extensions/test/addons/test_updateid2/bootstrap.js
toolkit/mozapps/extensions/test/addons/test_updateid2/install.rdf
toolkit/mozapps/extensions/test/addons/test_updateid2_2/install.rdf
toolkit/mozapps/extensions/test/addons/test_updateid2_5/install.rdf
toolkit/mozapps/extensions/test/addons/test_updateid3_3/bootstrap.js
toolkit/mozapps/extensions/test/addons/test_updateid3_3/install.rdf
toolkit/mozapps/extensions/test/addons/test_updateid4_4/bootstrap.js
toolkit/mozapps/extensions/test/addons/test_updateid4_4/install.rdf
toolkit/mozapps/extensions/test/xpcshell/data/test_update_multi.rdf
toolkit/mozapps/extensions/test/xpcshell/data/test_updateid.rdf
toolkit/mozapps/extensions/test/xpcshell/test_updateid.js
--- a/toolkit/mozapps/extensions/AddonManager.jsm
+++ b/toolkit/mozapps/extensions/AddonManager.jsm
@@ -3206,16 +3206,18 @@ this.AddonManager = {
     // The downloaded file seems to be corrupted in some way.
     ["ERROR_CORRUPT_FILE", -3],
     // An error occured trying to write to the filesystem.
     ["ERROR_FILE_ACCESS", -4],
     // The add-on must be signed and isn't.
     ["ERROR_SIGNEDSTATE_REQUIRED", -5],
     // The downloaded add-on had a different type than expected.
     ["ERROR_UNEXPECTED_ADDON_TYPE", -6],
+    // The addon did not have the expected ID
+    ["ERROR_INCORRECT_ID", -7],
   ]),
 
   // These must be kept in sync with AddonUpdateChecker.
   // No error was encountered.
   UPDATE_STATUS_NO_ERROR: 0,
   // The update check timed out
   UPDATE_STATUS_TIMEOUT: -1,
   // There was an error while downloading the update information.
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -5813,16 +5813,37 @@ AddonInstall.prototype = {
 
     // A multi-package XPI is a container, the add-ons it holds each
     // have their own id.  Everything else had better have an id here.
     if (!this.addon.id && this.addon.type != "multipackage") {
       let err = new Error(`Cannot find id for addon ${file.path}`);
       return Promise.reject([AddonManager.ERROR_CORRUPT_FILE, err]);
     }
 
+    if (this.existingAddon) {
+      // Check various conditions related to upgrades
+      if (this.addon.id != this.existingAddon.id) {
+        zipreader.close();
+        return Promise.reject([AddonManager.ERROR_INCORRECT_ID,
+                               `Refusing to upgrade addon ${this.existingAddon.id} to different ID {this.addon.id}`]);
+      }
+
+      if (this.addon.type == "multipackage") {
+        zipreader.close();
+        return Promise.reject([AddonManager.ERROR_UNEXPECTED_ADDON_TYPE,
+                               `Refusing to upgrade addon ${this.existingAddon.id} to a multi-package xpi`]);
+      }
+
+      if (this.existingAddon.type == "webextension" && this.addon.type != "webextension") {
+        zipreader.close();
+        return Promise.reject([AddonManager.ERROR_UNEXPECTED_ADDON_TYPE,
+                               "WebExtensions may not be upated to other extension types"]);
+      }
+    }
+
     if (mustSign(this.addon.type)) {
       if (this.addon.signedState <= AddonManager.SIGNEDSTATE_MISSING) {
         // This add-on isn't properly signed by a signature that chains to the
         // trusted root.
         let state = this.addon.signedState;
         this.addon = null;
         zipreader.close();
 
@@ -5850,23 +5871,16 @@ AddonInstall.prototype = {
         } else {
           zipreader.close();
           return Promise.reject([AddonManager.ERROR_CORRUPT_FILE,
                                  "XPI is incorrectly signed"]);
         }
       }
     }
 
-    if (this.existingAddon && this.existingAddon.type == "webextension" &&
-        this.addon.type != "webextension") {
-      zipreader.close();
-      return Promise.reject([AddonManager.ERROR_UNEXPECTED_ADDON_TYPE,
-                             "WebExtensions may not be upated to other extension types"]);
-    }
-
     if (this.addon.type == "multipackage")
       return this._loadMultipackageManifests(zipreader);
 
     zipreader.close();
 
     this.updateAddonURIs();
 
     this.addon._install = this;
@@ -6132,16 +6146,17 @@ AddonInstall.prototype = {
           else {
             // TODO Should we send some event here (bug 557716)?
             this.state = AddonManager.STATE_CHECKING;
             new UpdateChecker(this.addon, {
               onUpdateFinished: aAddon => this.downloadCompleted(),
             }, AddonManager.UPDATE_WHEN_ADDON_INSTALLED);
           }
         }, ([error, message]) => {
+          this.removeTemporaryFile();
           this.downloadFailed(error, message);
         });
       }
       else if (aRequest instanceof Ci.nsIHttpChannel) {
         this.downloadFailed(AddonManager.ERROR_NETWORK_FAILURE,
                             aRequest.responseStatus + " " +
                             aRequest.responseStatusText);
       }
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/addons/test_update_multi1/bootstrap.js
@@ -0,0 +1,5 @@
+
+function install(data, reason) {}
+function startup(data, reason) {}
+function shutdown(data, reason) {}
+function uninstall(data, reason) {}
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/addons/test_update_multi1/install.rdf
@@ -0,0 +1,16 @@
+<?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>updatemulti@tests.mozilla.org</em:id>
+  <em:version>1.0</em:version>
+  <em:updateURL>http://localhost:4444/data/test_update_multi.rdf</em:updateURL>
+  <em:bootstrap>true</em:bootstrap>
+  <em:name>Test Addon 1</em:name>
+<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>
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..febff06fa276ce3d66bf091c2e5a4f9a357287a2
GIT binary patch
literal 693
zc$^FHW@Zs#U|`^2IF@Pb`H;7l(Ug&aA(x4Pftx{wAv3SIBrzvPuP7xgG=!6ZS;YN8
zI0%<ka5FHnd<CimYi<p)&Oc-zaPPDB8UuAcP3}MgSEspF3%6+-buxO_o!n=VSzjxA
zykiRA*Rt<>-}$ZE-YoKBa^&%?x0amV<FQ?3CI4^nCyY<cUWy(Fk@#La|GWRrZQ^@k
z)?eSDQ5c!F%{Kj=H>0f4Q?bmZW8y8MllN~4sxMZ|Fwp2uYMm)_wfoBQw==VK%pbTr
zd|6_BW69jm&?zA?mJ6IxCTZ2B@$F$*IO}BB_9e!;tZLSbe<W?5J##dj=P^-kyGm*t
z%abtoicMAadnQ?IyTB_N{&qps&vsj{k24DA%s4(_)^F9O+p%(g{i2$gy?GgLZ#=Mb
zyOMk0$rH1`yX@Zf^|n5<Zpmap_AGs#vSS?gE_}30satbXmhJKmZQ)1vl|9zkJ-Qcs
zV@=`W3lAHM@>NXd@e4fI?`*fB=B2%eXB|TTJmfb6L;m%Yd4Fwyylx=o0fu~1ett=D
zNl{{fURE(U=s&tW2>;}U5%iC}w9k6$ojh|s_{14)J<l^IFM4?DcwPzA@bc9;cm8t7
zigiz$Rx_LupE^bCLGZ-Ds7aIJ=e4_gX3FVx16{z#B*%;^_9YlV0LW!%XauoP(gG_a
nEuc9D*+5KBAsbi)q)@%c3h^R_iL7iOT}(i@7)bvCX=eZcG)nT-
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/addons/test_update_multi2/install.rdf
@@ -0,0 +1,9 @@
+<?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>updatemulti@tests.mozilla.org</em:id>
+  <em:type>32</em:type>
+  <em:version>2.0</em:version>
+</Description>
+</RDF>
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/addons/test_updateid1/bootstrap.js
@@ -0,0 +1,5 @@
+
+function install(data, reason) {}
+function startup(data, reason) {}
+function shutdown(data, reason) {}
+function uninstall(data, reason) {}
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/addons/test_updateid1/install.rdf
@@ -0,0 +1,16 @@
+<?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>addon1@tests.mozilla.org</em:id>
+  <em:version>1.0</em:version>
+  <em:updateURL>http://localhost:4444/data/test_updateid.rdf</em:updateURL>
+  <em:bootstrap>true</em:bootstrap>
+  <em:name>Test Addon 1</em:name>
+<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>
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/addons/test_updateid2/bootstrap.js
@@ -0,0 +1,5 @@
+
+function install(data, reason) {}
+function startup(data, reason) {}
+function shutdown(data, reason) {}
+function uninstall(data, reason) {}
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/addons/test_updateid2/install.rdf
@@ -0,0 +1,16 @@
+<?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>addon1.changed@tests.mozilla.org</em:id>
+  <em:version>2.0</em:version>
+  <em:updateURL>http://localhost:4444/data/test_updateid.rdf</em:updateURL>
+  <em:bootstrap>true</em:bootstrap>
+  <em:name>Test Addon 1</em:name>
+<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>
deleted file mode 100644
--- a/toolkit/mozapps/extensions/test/addons/test_updateid2_2/install.rdf
+++ /dev/null
@@ -1,24 +0,0 @@
-<?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>
deleted file mode 100644
--- a/toolkit/mozapps/extensions/test/addons/test_updateid2_5/install.rdf
+++ /dev/null
@@ -1,24 +0,0 @@
-<?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>
deleted file mode 100644
--- a/toolkit/mozapps/extensions/test/addons/test_updateid3_3/bootstrap.js
+++ /dev/null
@@ -1,21 +0,0 @@
-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);
-}
deleted file mode 100644
--- a/toolkit/mozapps/extensions/test/addons/test_updateid3_3/install.rdf
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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>
deleted file mode 100644
--- a/toolkit/mozapps/extensions/test/addons/test_updateid4_4/bootstrap.js
+++ /dev/null
@@ -1,21 +0,0 @@
-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);
-}
deleted file mode 100644
--- a/toolkit/mozapps/extensions/test/addons/test_updateid4_4/install.rdf
+++ /dev/null
@@ -1,25 +0,0 @@
-<?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>
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/xpcshell/data/test_update_multi.rdf
@@ -0,0 +1,26 @@
+<?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:updatemulti@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_update_multi2.xpi</em:updateLink>
+              </Description>
+            </em:targetApplication>
+          </Description>
+        </li>
+      </Seq>
+    </em:updates>
+  </Description>
+
+</RDF>
--- a/toolkit/mozapps/extensions/test/xpcshell/data/test_updateid.rdf
+++ b/toolkit/mozapps/extensions/test/xpcshell/data/test_updateid.rdf
@@ -9,77 +9,17 @@
         <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>
+                <em:updateLink>http://localhost:4444/addons/test_updateid2.xpi</em:updateLink>
               </Description>
             </em:targetApplication>
           </Description>
         </li>
       </Seq>
     </em:updates>
   </Description>
 
--- a/toolkit/mozapps/extensions/test/xpcshell/test_updateid.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_updateid.js
@@ -2,421 +2,85 @@
  * 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);
 
-Components.utils.import("resource://testing-common/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 HttpServer();
-  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) {
-      // give the startup time to run
-      do_execute_soon(function() {
-        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);
+function promiseInstallUpdate(install) {
+  return new Promise((resolve, reject) => {
+    install.addListener({
+      onDownloadFailed: () => {
+        let err = new Error("download error");
+        err.code = install.error;
+        reject(err);
+      },
+      onInstallFailed: () => {
+        let err = new Error("install error");
+        err.code = install.error;
+        reject(err);
+      },
+      onInstallEnded: resolve,
+    });
 
-        installUpdate(install, check_test_1);
-      }
-    }, AddonManager.UPDATE_WHEN_USER_REQUESTED);
-  });
-}
-
-function check_test_1(install) {
-  AddonManager.getAddonByID("addon1@tests.mozilla.org", callback_soon(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);
-    do_check_neq(a1.syncGUID);
-
-    let a1SyncGUID = a1.syncGUID;
-
-    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);
-      do_check_neq(a2.syncGUID, null);
-
-      // The Sync GUID should change when the ID changes
-      do_check_neq(a1SyncGUID, a2.syncGUID);
-
-      a2.uninstall();
-
-      do_execute_soon(run_test_2);
-    });
-  }));
-}
-
-// Test that when the new add-on already exists we just upgrade that
-function run_test_2() {
-  restartManager();
-  shutdownManager();
-
-  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);
+    install.install();
   });
 }
 
-function check_test_2(install) {
-  AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
-                               "addon2@tests.mozilla.org"],
-                               callback_soon(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();
-
-      do_execute_soon(run_test_3);
-    });
-  }));
-}
-
-// Test that we rollback correctly when removing the old add-on fails
-function run_test_3() {
-  restartManager();
-  shutdownManager();
-
-  // 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();
+// Create and configure the HTTP server.
+let testserver = createHttpServer(4444);
+testserver.registerDirectory("/data/", do_get_file("data"));
+testserver.registerDirectory("/addons/", do_get_file("addons"));
 
-  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", callback_soon(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"],
-                                 callback_soon(function([a1, a2]) {
-      // Should not have installed the new add-on but it should still be
-      // pending install
-      do_check_neq(a1, null);
-      do_check_eq(a2, null);
-
-      restartManager();
-
-      AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
-                                   "addon2@tests.mozilla.org"], function([a1, a2]) {
-        // Should have installed the new add-on
-        do_check_eq(a1, null);
-        do_check_neq(a2, null);
-
-        a2.uninstall();
-
-        do_execute_soon(run_test_4);
-      });
-    }));
-  }));
+function run_test() {
+  createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
+  startupManager();
+  run_next_test();
 }
 
-// Tests that upgrading to a bootstrapped add-on works but requires a restart
-function run_test_4() {
-  restartManager();
-  shutdownManager();
-
-  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);
+// Verify that an update to an add-on with a new ID fails
+add_task(function* test_update_new_id() {
+  yield promiseInstallFile(do_get_addon("test_updateid1"));
 
-  startupManager();
-
-  resetPrefs();
-
-  AddonManager.getAddonByID("addon2@tests.mozilla.org", function(a2) {
-    do_check_neq(a2, null);
-    do_check_neq(a2.syncGUID, null);
-    do_check_eq(a2.version, "2.0");
-
-    a2.findUpdates({
-      onUpdateAvailable: function(addon, install) {
-        installUpdate(install, check_test_4);
-      }
-    }, AddonManager.UPDATE_WHEN_USER_REQUESTED);
-  });
-}
+  let addon = yield promiseAddonByID("addon1@tests.mozilla.org");
+  do_check_neq(addon, null);
+  do_check_eq(addon.version, "1.0");
 
-function check_test_4() {
-  AddonManager.getAddonsByIDs(["addon2@tests.mozilla.org",
-                               "addon3@tests.mozilla.org"],
-                               callback_soon(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();
+  let update = yield promiseFindAddonUpdates(addon, AddonManager.UPDATE_WHEN_USER_REQUESTED);
+  let install = update.updateAvailable;
+  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, addon);
 
-    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);
+  yield Assert.rejects(promiseInstallUpdate(install),
+                       function(err) { return err.code == AddonManager.ERROR_INCORRECT_ID },
+                       "Upgrade to a different ID fails");
 
-      do_execute_soon(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");
+  addon.uninstall();
+});
 
-    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"],
-                               callback_soon(function([a3, a4]) {
-    // Should have updated
-    do_check_eq(a3, null);
-    do_check_neq(a4, null);
+// Verify that an update to a multi-package xpi fails
+add_task(function* test_update_new_id() {
+  yield promiseInstallFile(do_get_addon("test_update_multi1"));
 
-    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();
-    });
-  }));
-}
+  let addon = yield promiseAddonByID("updatemulti@tests.mozilla.org");
+  do_check_neq(addon, null);
+  do_check_eq(addon.version, "1.0");
 
-// 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"],
-                               callback_soon(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);
+  let update = yield promiseFindAddonUpdates(addon, AddonManager.UPDATE_WHEN_USER_REQUESTED);
+  let install = update.updateAvailable;
+  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, addon);
 
-    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();
+  yield Assert.rejects(promiseInstallUpdate(install),
+                       function(err) { return err.code == AddonManager.ERROR_UNEXPECTED_ADDON_TYPE },
+                       "Upgrade to a multipackage xpi fails");
 
-    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);
-
-      do_check_eq(getInstalledVersion(), 0);
-      do_check_eq(getActiveVersion(), 0);
-
-      end_test();
-    });
-  }));
-}
+  addon.uninstall();
+});