Bug 760752 - Frequent browser_dbg_debugger-tab-switch.js | leaked window property: _scriptDebugger and 87 more test failures; r=past
authorDave Camp <dcamp@mozilla.com>
Sat, 02 Jun 2012 18:43:19 +0300
changeset 95631 8caca2dc3ec199b60eef2266f11363edf69afd6d
parent 95630 c9b7a566ff056cf34913f482c0ec65b2aa804046
child 95632 8ac2a0abc2c928e60ad4956f99f9fb48ff6de220
push id22822
push userdcamp@campd.org
push dateSat, 02 Jun 2012 23:57:38 +0000
treeherdermozilla-central@d0ebcaa7efb5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspast
bugs760752
milestone15.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 760752 - Frequent browser_dbg_debugger-tab-switch.js | leaked window property: _scriptDebugger and 87 more test failures; r=past
browser/devtools/debugger/DebuggerUI.jsm
browser/devtools/debugger/test/browser_dbg_debugger-tab-switch.js
browser/devtools/debugger/test/head.js
--- a/browser/devtools/debugger/DebuggerUI.jsm
+++ b/browser/devtools/debugger/DebuggerUI.jsm
@@ -242,29 +242,43 @@ DebuggerPane.prototype = {
     }, true);
 
     this._frame.setAttribute("src", DBG_XUL);
     this._globalUI.refreshCommand();
   },
 
   /**
    * Closes the debugger, removing child nodes and event listeners.
+   *
+   * @param function aCloseCallback
+   *        Clients can pass a close callback to be notified when
+   *        the panel successfully closes.
    */
-  close: function DP_close() {
+  close: function DP_close(aCloseCallback) {
     if (!this._win) {
       return;
     }
     delete this._win._scriptDebugger;
     this._win = null;
     this._tab = null;
 
     DebuggerPreferences.height = this._frame.height;
     this._frame.removeEventListener("Debugger:Close", this.close, true);
     this._frame.removeEventListener("unload", this.close, true);
 
+    // This method is also used as an event handler, so only
+    // use aCloseCallback if it's a function.
+    if (typeof(aCloseCallback) == "function") {
+      let frame = this._frame;
+      frame.addEventListener("unload", function onUnload() {
+        frame.removeEventListener("unload", onUnload, true);
+        aCloseCallback();
+      }, true)
+    }
+
     this._nbox.removeChild(this._splitter);
     this._nbox.removeChild(this._frame);
 
     this._splitter = null;
     this._frame = null;
     this._nbox = null;
 
     this._globalUI.refreshCommand();
--- a/browser/devtools/debugger/test/browser_dbg_debugger-tab-switch.js
+++ b/browser/devtools/debugger/test/browser_dbg_debugger-tab-switch.js
@@ -40,19 +40,17 @@ function testTab1(callback) {
 
     gPane1 = DebuggerUI.toggleDebugger();
     ok(gPane1, "toggleDebugger() should return a pane.");
     is(gPane1.ownerTab, gTab1, "Incorrect tab owner.");
 
     is(DebuggerUI.getDebugger(), gPane1,
       "getDebugger() should return the same pane as toggleDebugger().");
 
-    gPane1._frame.addEventListener("Debugger:Loaded", function dbgLoaded() {
-      gPane1._frame.removeEventListener("Debugger:Loaded", dbgLoaded, true);
-
+    wait_for_connect_and_resume(function dbgLoaded() {
       info("First debugger has finished loading correctly.");
       executeSoon(function() {
         callback();
       });
     }, true);
   });
 }
 
@@ -175,17 +173,17 @@ function testTab4(callback) {
         ok(gNbox.currentNotification, "Should have a tab switch notification.");
         is(gNbox.currentNotification, notification, "Incorrect current notification.");
 
         let buttonOpen = notification.querySelectorAll("button")[1];
         buttonOpen.focus();
         EventUtils.sendKey("SPACE");
         info("The open button on the notification was pressed.");
 
-        executeSoon(function() {
+        wait_for_connect_and_resume(function() {
           callback();
         });
       });
     }, true);
 
     info("Toggling a debugger (4).");
 
     gPane2 = DebuggerUI.toggleDebugger();
@@ -206,23 +204,26 @@ function lastTest(callback) {
   info("Second debugger has loaded.");
 
   executeSoon(function() {
     callback();
   });
 }
 
 function cleanup(callback) {
-  removeTab(gTab1);
-  removeTab(gTab2);
-  removeTab(gTab3);
-  removeTab(gTab4);
 
-  gTab1 = null;
-  gTab2 = null;
-  gTab3 = null;
-  gTab4 = null;
   gPane1 = null;
   gPane2 = null;
   gNbox = null;
 
-  callback();
+  closeDebuggerAndFinish(false, function() {
+    removeTab(gTab1);
+    removeTab(gTab2);
+    removeTab(gTab3);
+    removeTab(gTab4);
+    gTab1 = null;
+    gTab2 = null;
+    gTab3 = null;
+    gTab4 = null;
+
+    callback();
+  });
 }
--- a/browser/devtools/debugger/test/head.js
+++ b/browser/devtools/debugger/test/head.js
@@ -50,24 +50,40 @@ function addTab(aURL, aOnload)
 
   return tab;
 }
 
 function removeTab(aTab) {
   gBrowser.removeTab(aTab);
 }
 
-function closeDebuggerAndFinish(aRemoteFlag) {
+function closeDebuggerAndFinish(aRemoteFlag, aCallback) {
+  let debuggerClosed = false;
+  let debuggerDisconnected = false;
+
+  function _maybeFinish() {
+    if (debuggerClosed && debuggerDisconnected) {
+      if (!aCallback)
+        aCallback = finish;
+      aCallback();
+    }
+  }
+
   DebuggerUI.chromeWindow.addEventListener("Debugger:Shutdown", function cleanup() {
     DebuggerUI.chromeWindow.removeEventListener("Debugger:Shutdown", cleanup, false);
-    finish();
+    debuggerDisconnected = true;
+    _maybeFinish();
   }, false);
   if (!aRemoteFlag) {
-    DebuggerUI.getDebugger().close();
+    DebuggerUI.getDebugger().close(function() {
+      debuggerClosed = true;
+      _maybeFinish();
+    });
   } else {
+    debuggerClosed = true;
     DebuggerUI.getRemoteDebugger().close();
   }
 }
 
 function get_tab_actor_for_url(aClient, aURL, aCallback) {
   aClient.listTabs(function(aResponse) {
     for each (let tab in aResponse.tabs) {
       if (tab.url == aURL) {
@@ -111,16 +127,28 @@ function debug_tab_pane(aURL, aOnDebuggi
       // Wait for the initial resume...
       pane.contentWindow.gClient.addOneTimeListener("resumed", function() {
         aOnDebugging(tab, debuggee, pane);
       });
     }, true);
   });
 }
 
+function wait_for_connect_and_resume(aOnDebugging)
+{
+  window.document.addEventListener("Debugger:Connecting", function dbgConnected(aEvent) {
+    window.document.removeEventListener("Debugger:Connecting", dbgConnected, true);
+
+    // Wait for the initial resume...
+    aEvent.target.ownerDocument.defaultView.gClient.addOneTimeListener("resumed", function() {
+      aOnDebugging();
+    });
+  }, true);
+}
+
 function debug_remote(aURL, aOnDebugging, aBeforeTabAdded)
 {
   // Make any necessary preparations (start the debugger server etc.)
   aBeforeTabAdded();
 
   let tab = addTab(aURL, function() {
     gBrowser.selectedTab = gTab;
     let debuggee = tab.linkedBrowser.contentWindow.wrappedJSObject;