Bug 792867 - Debugger mochitests leak when run separately. r=rcampbell
--- a/browser/devtools/debugger/DebuggerUI.jsm
+++ b/browser/devtools/debugger/DebuggerUI.jsm
@@ -197,18 +197,26 @@ DebuggerUI.prototype = {
targetWindow.gBrowser.selectedTab = scriptDebugger.ownerTab;
targetWindow.focus();
}.bind(this)
}, {
id: "debugger.confirmTabSwitch.buttonOpen",
label: L10N.getStr("confirmTabSwitch.buttonOpen"),
accessKey: L10N.getStr("confirmTabSwitch.buttonOpen.accessKey"),
callback: function DUI_notificationButtonOpen() {
- this.findDebugger().close();
- this.toggleDebugger();
+ let scriptDebugger = this.findDebugger();
+ let targetWindow = scriptDebugger.globalUI.chromeWindow;
+ scriptDebugger.close();
+ let self = this;
+ targetWindow.addEventListener("Debugger:Shutdown", function toggle() {
+ targetWindow.removeEventListener("Debugger:Shutdown", toggle, false);
+ Services.tm.currentThread.dispatch({ run: function() {
+ self.toggleDebugger();
+ }}, 0);
+ }, false);
}.bind(this)
}];
let message = L10N.getStr("confirmTabSwitch.message");
let imageURL = "chrome://browser/skin/Info.png";
notification = nbox.appendNotification(
message, TAB_SWITCH_NOTIFICATION,
--- a/toolkit/devtools/debugger/server/dbg-server.js
+++ b/toolkit/devtools/debugger/server/dbg-server.js
@@ -67,21 +67,29 @@ var DebuggerServer = {
globalActorFactories: null,
// Map of tab actor names to actor constructors provided by extensions.
tabActorFactories: null,
LONG_STRING_LENGTH: 10000,
LONG_STRING_INITIAL_LENGTH: 1000,
/**
- * Prompt the user to accept or decline the incoming connection.
+ * A handler function that prompts the user to accept or decline the incoming
+ * connection.
+ */
+ _allowConnection: null,
+
+ /**
+ * Prompt the user to accept or decline the incoming connection. This is the
+ * default implementation that products embedding the debugger server may
+ * choose to override.
*
* @return true if the connection should be permitted, false otherwise
*/
- _allowConnection: function DH__allowConnection() {
+ _defaultAllowConnection: function DH__defaultAllowConnection() {
let title = L10N.getStr("remoteIncomingPromptTitle");
let msg = L10N.getStr("remoteIncomingPromptMessage");
let disableButton = L10N.getStr("remoteIncomingPromptDisable");
let prompt = Services.prompt;
let flags = prompt.BUTTON_POS_0 * prompt.BUTTON_TITLE_OK +
prompt.BUTTON_POS_1 * prompt.BUTTON_TITLE_CANCEL +
prompt.BUTTON_POS_2 * prompt.BUTTON_TITLE_IS_STRING +
prompt.BUTTON_POS_1_DEFAULT;
@@ -128,35 +136,38 @@ var DebuggerServer = {
initTransport: function DH_initTransport(aAllowConnectionCallback) {
if (this._transportInitialized) {
return;
}
this._connections = {};
this._nextConnID = 0;
this._transportInitialized = true;
- if (aAllowConnectionCallback) {
- this._allowConnection = aAllowConnectionCallback;
- }
+ this._allowConnection = aAllowConnectionCallback ?
+ aAllowConnectionCallback :
+ this._defaultAllowConnection;
},
get initialized() { return !!this.globalActorFactories; },
/**
* Performs cleanup tasks before shutting down the debugger server, if no
* connections are currently open. Such tasks include clearing any actor
* constructors added at runtime. This method should be called whenever a
* debugger server is no longer useful, to avoid memory leaks. After this
* method returns, the debugger server must be initialized again before use.
*/
destroy: function DH_destroy() {
if (Object.keys(this._connections).length == 0) {
- dumpn("Shutting down debugger server.");
+ this.closeListener();
delete this.globalActorFactories;
delete this.tabActorFactories;
+ delete this._allowConnection;
+ this._transportInitialized = false;
+ dumpn("Debugger server is shut down.");
}
},
/**
* Load a subscript into the debugging global.
*
* @param aURL string A url that will be loaded as a subscript into the
* debugging global. The user must load at least one script
@@ -215,18 +226,16 @@ var DebuggerServer = {
/**
* Close a previously-opened TCP listener.
*
* @param aForce boolean [optional]
* If set to true, then the socket will be closed, regardless of the
* number of open connections.
*/
closeListener: function DH_closeListener(aForce) {
- this._checkInit();
-
if (!this._listener || this._socketConnections == 0) {
return false;
}
// Only close the listener when the last connection is closed, or if the
// aForce flag is passed.
if (--this._socketConnections == 0 || aForce) {
this._listener.close();
--- a/toolkit/devtools/debugger/tests/unit/test_dbgsocket.js
+++ b/toolkit/devtools/debugger/tests/unit/test_dbgsocket.js
@@ -2,17 +2,17 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
Cu.import("resource:///modules/devtools/dbg-server.jsm");
Cu.import("resource:///modules/devtools/dbg-client.jsm");
function run_test()
{
// Allow incoming connections.
- DebuggerServer.init(function () { return true; });
+ DebuggerServer.init(function () true);
DebuggerServer.addActors("resource://test/testactors.js");
add_test(test_socket_conn);
add_test(test_socket_shutdown);
add_test(test_pipe_conn);
run_next_test();
}
@@ -54,20 +54,45 @@ function test_socket_conn()
run_next_test();
},
};
transport.ready();
}
function test_socket_shutdown()
{
- do_check_eq(DebuggerServer._socketConnections, 1);
- do_check_true(DebuggerServer.closeListener());
+ let count = 0;
+ wait_for_server_shutdown(count);
+}
+
+function wait_for_server_shutdown(aCount)
+{
+ do_timeout(100, function() {
+ dump("count: "+aCount+" ");
+ if (++aCount > 20) {
+ do_throw("Timed out waiting for the server to shut down.");
+ return;
+ }
+ if (DebuggerServer.initialized) {
+ wait_for_server_shutdown(aCount);
+ return;
+ }
+ real_test_socket_shutdown(aCount);
+ });
+}
+
+function real_test_socket_shutdown()
+{
+ // After the last conection was closed, the server must be initialized again.
+ // Allow incoming connections.
+ DebuggerServer.init(function () true);
+ DebuggerServer.addActors("resource://test/testactors.js");
+
do_check_eq(DebuggerServer._socketConnections, 0);
- // Make sure closing the listener twice does nothing.
+ // Make sure closing a non-started listener does nothing.
do_check_false(DebuggerServer.closeListener());
do_check_eq(DebuggerServer._socketConnections, 0);
let transport = debuggerSocketConnect("127.0.0.1", 2929);
transport.hooks = {
onPacket: function(aPacket) {
// Shouldn't reach this, should never connect.
do_check_true(false);