Bug 672485 - Ensure window watcher is defined. r=dtownsend,jst
authorBlair McBride <bmcbride@mozilla.com>
Sat, 27 Aug 2011 09:24:20 +1200
changeset 77261 b379d2c614d0ce551c5228f05a3f415c938ea8b5
parent 77260 6eb75a6f3c1dc44e1b7f2f0764a635e279a9a1c9
child 77262 906413a7ae6b6894e0f5f67cceaebe84008c940f
push id78
push userclegnitto@mozilla.com
push dateFri, 16 Dec 2011 17:32:24 +0000
treeherdermozilla-release@79d24e644fdd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdtownsend, jst
bugs672485
milestone9.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 672485 - Ensure window watcher is defined. r=dtownsend,jst
toolkit/mozapps/extensions/amWebInstallListener.js
toolkit/mozapps/extensions/test/xpinstall/Makefile.in
toolkit/mozapps/extensions/test/xpinstall/browser_bug672485.js
toolkit/mozapps/extensions/test/xpinstall/head.js
--- a/toolkit/mozapps/extensions/amWebInstallListener.js
+++ b/toolkit/mozapps/extensions/amWebInstallListener.js
@@ -49,16 +49,18 @@
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/AddonManager.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
+const URI_XPINSTALL_DIALOG = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul";
+
 // Installation can begin from any of these states
 const READY_STATES = [
   AddonManager.STATE_AVAILABLE,
   AddonManager.STATE_DOWNLOAD_FAILED,
   AddonManager.STATE_INSTALL_FAILED,
   AddonManager.STATE_CANCELLED
 ];
 
@@ -199,18 +201,29 @@ Installer.prototype = {
       catch (e) {}
     }
 
     let args = {};
     args.url = this.url;
     args.installs = this.downloads;
     args.wrappedJSObject = args;
 
-    Services.ww.openWindow(this.window, "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul",
-                           null, "chrome,modal,centerscreen", args);
+    try {
+      Services.ww.openWindow(this.window, URI_XPINSTALL_DIALOG,
+                             null, "chrome,modal,centerscreen", args);
+    } catch (e) {
+      this.downloads.forEach(function(aInstall) {
+        aInstall.removeListener(this);
+        // Cancel the installs, as currently there is no way to make them fail
+        // from here.
+        aInstall.cancel();
+      }, this);
+      notifyObservers("addon-install-cancelled", this.window, this.url,
+                      this.downloads);
+    }
   },
 
   /**
    * Checks if all installs are now complete and if so notifies observers.
    */
   checkAllInstalled: function() {
     var failed = [];
 
--- a/toolkit/mozapps/extensions/test/xpinstall/Makefile.in
+++ b/toolkit/mozapps/extensions/test/xpinstall/Makefile.in
@@ -38,16 +38,19 @@ DEPTH		= ../../../../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = toolkit/mozapps/extensions/test/xpinstall
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
+
+# browser_bug672485.js is disabled due to a leak. See bug 682410.
+
 _BROWSER_FILES = head.js \
                  browser_unsigned_url.js \
                  browser_unsigned_trigger.js \
                  browser_unsigned_trigger_iframe.js \
                  browser_whitelist.js \
                  browser_whitelist2.js \
                  browser_whitelist3.js \
                  browser_whitelist4.js \
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_bug672485.js
@@ -0,0 +1,52 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+gWindowWatcher = null;
+
+function test() {
+  Harness.installConfirmCallback = confirm_install;
+  Harness.installCancelledCallback = cancelled_install;
+  Harness.installEndedCallback = complete_install;
+  Harness.installsCompletedCallback = finish_test;
+  Harness.setup();
+
+  gWindowWatcher = Services.ww;
+  delete Services.ww;
+  is(Services.ww, undefined, "Services.ww should now be undefined");
+
+  var pm = Services.perms;
+  pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
+
+  var triggers = encodeURIComponent(JSON.stringify({
+    "Unsigned XPI": TESTROOT + "unsigned.xpi"
+  }));
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
+}
+
+function confirm_install(window) {
+  ok(false, "Should not see the install dialog");
+  return false;
+}
+
+function cancelled_install() {
+  ok(true, "Install should b cancelled");
+}
+
+function complete_install() {
+  ok(false, "Install should not have completed");
+  return false;
+}
+
+function finish_test(count) {
+  is(count, 0, "0 Add-ons should have been successfully installed");
+
+  gBrowser.removeCurrentTab();
+
+  Services.ww = gWindowWatcher;
+
+  Services.perms.remove("example.com", "install");
+
+  Harness.finish();
+}
--- a/toolkit/mozapps/extensions/test/xpinstall/head.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/head.js
@@ -31,16 +31,19 @@ function extractChromeRoot(path) {
  * of installing an XPI. A test can set callbacks to hear about specific parts
  * of the sequence.
  * Before use setup must be called and finish must be called afterwards.
  */
 var Harness = {
   // If set then the callback is called when an install is attempted and
   // software installation is disabled.
   installDisabledCallback: null,
+  // If set then the callback is called when an install is attempted and
+  // then canceled.
+  installCancelledCallback: null,
   // If set then the callback will be called when an install is blocked by the
   // whitelist. The callback should return true to continue with the install
   // anyway.
   installBlockedCallback: null,
   // If set will be called in the event of authentication being needed to get
   // the xpi. Should return a 2 element array of username and password, or
   // null to not authenticate.
   authenticationCallback: null,
@@ -211,32 +214,46 @@ var Harness = {
   },
 
   // Install blocked handling
 
   installDisabled: function(installInfo) {
     ok(!!this.installDisabledCallback, "Installation shouldn't have been disabled");
     if (this.installDisabledCallback)
       this.installDisabledCallback(installInfo);
+    this.expectingCancelled = true;
     installInfo.installs.forEach(function(install) {
       install.cancel();
     });
+    this.expectingCancelled = false;
+    this.endTest();
+  },
+
+  installCancelled: function(installInfo) {
+    if (this.expectingCancelled)
+      return;
+
+    ok(!!this.installCancelledCallback, "Installation shouldn't have been cancelled");
+    if (this.installCancelledCallback)
+      this.installCancelledCallback(installInfo);
     this.endTest();
   },
 
   installBlocked: function(installInfo) {
     ok(!!this.installBlockedCallback, "Shouldn't have been blocked by the whitelist");
     if (this.installBlockedCallback && this.installBlockedCallback(installInfo)) {
       this.installBlockedCallback = null;
       installInfo.install();
     }
     else {
+      this.expectingCancelled = true;
       installInfo.installs.forEach(function(install) {
         install.cancel();
       });
+      this.expectingCancelled = false;
       this.endTest();
     }
   },
 
   // nsIWindowMediatorListener
 
   onWindowTitleChange: function(window, title) {
   },
@@ -321,16 +338,19 @@ var Harness = {
     switch (topic) {
     case "addon-install-started":
       is(this.runningInstalls.length, installInfo.installs.length,
          "Should have seen the expected number of installs started");
       break;
     case "addon-install-disabled":
       this.installDisabled(installInfo);
       break;
+    case "addon-install-cancelled":
+      this.installCancelled(installInfo);
+      break;
     case "addon-install-blocked":
       this.installBlocked(installInfo);
       break;
     case "addon-install-failed":
       installInfo.installs.forEach(function(aInstall) {
         isnot(this.runningInstalls.indexOf(aInstall), -1,
               "Should only see failures for started installs");