Bug 633571: Multiple entries in the doorhanger for aborted add-on installations. r=Unfocused, a=johnath
authorDave Townsend <dtownsend@oxymoronical.com>
Tue, 15 Feb 2011 15:10:17 -0800
changeset 62629 b5c09f0dce234a29095344a9201b92a69d5014bf
parent 62628 eeb1dd9e7028467342a2594f0ed2cf223cda3689
child 62630 2541eb698bc6014091065ce05536589be6055f55
push id1
push userroot
push dateTue, 10 Dec 2013 15:46:25 +0000
reviewersUnfocused, johnath
bugs633571
milestone2.0b12pre
Bug 633571: Multiple entries in the doorhanger for aborted add-on installations. r=Unfocused, a=johnath
browser/base/content/test/browser_bug553455.js
browser/base/content/urlbarBindings.xml
--- a/browser/base/content/test/browser_bug553455.js
+++ b/browser/base/content/test/browser_bug553455.js
@@ -1,15 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 const TESTROOT = "http://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/";
 const TESTROOT2 = "http://example.org/browser/toolkit/mozapps/extensions/test/xpinstall/";
+const SECUREROOT = "https://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/";
 const XPINSTALL_URL = "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul";
+const PREF_INSTALL_REQUIREBUILTINCERTS = "extensions.install.requireBuiltInCerts";
 
 var rootDir = getRootDirectory(gTestPath);
 var path = rootDir.split('/');
 var chromeName = path[0] + '//' + path[2];
 var croot = chromeName + "/content/browser/toolkit/mozapps/extensions/test/xpinstall/";
 var jar = getJar(croot);
 if (jar) {
   var tmpdir = extractJarToTmp(jar);
@@ -54,16 +56,27 @@ function wait_for_install_dialog(aCallba
     onCloseWindow: function(aXULWindow) {
     },
 
     onWindowTitleChange: function(aXULWindow, aNewTitle) {
     }
   });
 }
 
+function setup_redirect(aSettings) {
+  var url = "https://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/redirect.sjs?mode=setup";
+  for (var name in aSettings) {
+    url += "&" + name + "=" + aSettings[name];
+  }
+
+  var req = new XMLHttpRequest();
+  req.open("GET", url, false);
+  req.send(null);
+}
+
 var TESTS = [
 function test_disabled_install() {
   Services.prefs.setBoolPref("xpinstall.enabled", false);
 
   // Wait for the disabled notification
   wait_for_notification(function(aPanel) {
     let notification = aPanel.childNodes[0];
     is(notification.id, "xpinstall-disabled-notification", "Should have seen installs disabled");
@@ -544,16 +557,17 @@ function test_theme() {
           ok(aAddon.userDisabled, "Should be switching away from the default theme.");
           // Undo the pending theme switch
           aAddon.userDisabled = false;
 
           AddonManager.getAddonByID("theme-xpi@tests.mozilla.org", function(aAddon) {
             isnot(aAddon, null, "Test theme will have been installed");
             aAddon.uninstall();
 
+            Services.perms.remove("example.com", "install");
             runNextTest();
           });
         });
       });
 
       aWindow.document.documentElement.acceptDialog();
     });
   });
@@ -745,16 +759,65 @@ function test_cancel_restart() {
   var pm = Services.perms;
   pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
 
   var triggers = encodeURIComponent(JSON.stringify({
     "XPI": "unsigned.xpi"
   }));
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
+},
+
+function test_failed_security() {
+  Services.prefs.setBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, false);
+
+  setup_redirect({
+    "Location": TESTROOT + "unsigned.xpi"
+  });
+
+  // Wait for the blocked notification
+  wait_for_notification(function(aPanel) {
+    let notification = aPanel.childNodes[0];
+    is(notification.id, "addon-install-blocked-notification", "Should have seen the install blocked");
+
+    // Click on Allow
+    EventUtils.synthesizeMouse(notification.button, 20, 10, {});
+
+    // Notification should have changed to progress notification
+    ok(PopupNotifications.isPanelOpen, "Notification should still be open");
+    is(PopupNotifications.panel.childNodes.length, 1, "Should be only one notification");
+    notification = aPanel.childNodes[0];
+    is(notification.id, "addon-progress-notification", "Should have seen the progress notification");
+
+    // Wait for it to fail
+    Services.obs.addObserver(function() {
+      Services.obs.removeObserver(arguments.callee, "addon-install-failed");
+
+      // Wait for the browser code to add the failure notification
+      executeSoon(function() {
+        // Wait for the progress notification to dismiss itself
+        executeSoon(function() {
+          ok(PopupNotifications.isPanelOpen, "Notification should still be open");
+          is(PopupNotifications.panel.childNodes.length, 1, "Should be only one notification");
+          notification = aPanel.childNodes[0];
+          is(notification.id, "addon-install-failed-notification", "Should have seen the install fail");
+
+          gBrowser.removeTab(gBrowser.selectedTab);
+          Services.prefs.setBoolPref(PREF_INSTALL_REQUIREBUILTINCERTS, true);
+          runNextTest();
+        });
+      });
+    }, "addon-install-failed", false);
+  });
+
+  var triggers = encodeURIComponent(JSON.stringify({
+    "XPI": "redirect.sjs?mode=redirect"
+  }));
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.loadURI(SECUREROOT + "installtrigger.html?" + triggers);
 }
 ];
 
 var gTestStart = null;
 
 function runNextTest() {
   if (gTestStart)
     info("Test part took " + (Date.now() - gTestStart) + "ms");
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -897,18 +897,20 @@
 
         this.notification.options.installs.forEach(function(aInstall) {
           aInstall.addListener(this);
         }, this);
 
         // Calling updateProgress can sometimes cause this notification to be
         // removed in the middle of refreshing the notification panel which
         // makes the panel get refreshed again. Just initialise to the
-        // undetermined state.
+        // undetermined state and then schedule a proper check at the next
+        // opportunity
         this.setProgress(0, -1);
+        setTimeout(this.updateProgress.bind(this), 0);
       ]]></constructor>
 
       <destructor><![CDATA[
         this.destroy();
       ]]></destructor>
 
       <field name="progressmeter" readonly="true">
         document.getAnonymousElementByAttribute(this, "anonid", "progressmeter");