diff options
Diffstat (limited to 'devtools/client/framework/test/browser_toolbox_tool_remote_reopen.js')
-rw-r--r-- | devtools/client/framework/test/browser_toolbox_tool_remote_reopen.js | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/devtools/client/framework/test/browser_toolbox_tool_remote_reopen.js b/devtools/client/framework/test/browser_toolbox_tool_remote_reopen.js new file mode 100644 index 0000000000..52a6ea0655 --- /dev/null +++ b/devtools/client/framework/test/browser_toolbox_tool_remote_reopen.js @@ -0,0 +1,100 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { + DevToolsServer, +} = require("resource://devtools/server/devtools-server.js"); + +// Bug 1277805: Too slow for debug runs +requestLongerTimeout(2); + +/** + * Bug 979536: Ensure fronts are destroyed after toolbox close. + * + * The fronts need to be destroyed manually to unbind their onPacket handlers. + * + * When you initialize a front and call |this.manage|, it adds a client actor + * pool that the DevToolsClient uses to route packet replies to that actor. + * + * Most (all?) tools create a new front when they are opened. When the destroy + * step is skipped and the tool is reopened, a second front is created and also + * added to the client actor pool. When a packet reply is received, is ends up + * being routed to the first (now unwanted) front that is still in the client + * actor pool. Since this is not the same front that was used to make the + * request, an error occurs. + * + * This problem does not occur with the toolbox for a local tab because the + * toolbox target creates its own DevToolsClient for the local tab, and the + * client is destroyed when the toolbox is closed, which removes the client + * actor pools, and avoids this issue. + * + * In remote debugging, we do not destroy the DevToolsClient on toolbox close + * because it can still used for other targets. + * Thus, the same client gets reused across multiple toolboxes, + * which leads to the tools failing if they don't destroy their fronts. + */ + +function runTools(tab) { + return (async function () { + let toolbox; + const toolIds = await getSupportedToolIds(tab); + for (const toolId of toolIds) { + info("About to open " + toolId); + toolbox = await gDevTools.showToolboxForTab(tab, { + toolId, + hostType: "window", + }); + ok(toolbox, "toolbox exists for " + toolId); + is(toolbox.currentToolId, toolId, "currentToolId should be " + toolId); + + const panel = toolbox.getCurrentPanel(); + ok(panel, toolId + " panel has been registered in the toolbox"); + } + + const client = toolbox.commands.client; + await toolbox.destroy(); + + // We need to check the client after the toolbox destruction. + return client; + })(); +} + +function test() { + (async function () { + toggleAllTools(true); + const tab = await addTab("about:blank"); + + const client = await runTools(tab); + + const rootFronts = [...client.mainRoot.fronts.values()]; + + // Actor fronts should be destroyed now that the toolbox has closed, but + // look for any that remain. + for (const pool of client.__pools) { + if (!pool.__poolMap) { + continue; + } + + // Ignore the root fronts, which are top-level pools and aren't released + // on toolbox destroy, but on client close. + if (rootFronts.includes(pool)) { + continue; + } + + for (const actor of pool.__poolMap.keys()) { + // Ignore the root front as it is only release on client close + if (actor == "root") { + continue; + } + ok(false, "Front for " + actor + " still held in pool!"); + } + } + + gBrowser.removeCurrentTab(); + DevToolsServer.destroy(); + toggleAllTools(false); + finish(); + })(); +} |