diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /devtools/client/framework/browser-toolbox/test/browser_browser_toolbox_debugger.js | |
parent | Initial commit. (diff) | |
download | firefox-esr-upstream.tar.xz firefox-esr-upstream.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'devtools/client/framework/browser-toolbox/test/browser_browser_toolbox_debugger.js')
-rw-r--r-- | devtools/client/framework/browser-toolbox/test/browser_browser_toolbox_debugger.js | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/devtools/client/framework/browser-toolbox/test/browser_browser_toolbox_debugger.js b/devtools/client/framework/browser-toolbox/test/browser_browser_toolbox_debugger.js new file mode 100644 index 0000000000..edcba359e2 --- /dev/null +++ b/devtools/client/framework/browser-toolbox/test/browser_browser_toolbox_debugger.js @@ -0,0 +1,222 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// This test asserts that the new debugger works from the browser toolbox process + +// There are shutdown issues for which multiple rejections are left uncaught. +// See bug 1018184 for resolving these issues. +const { PromiseTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/PromiseTestUtils.sys.mjs" +); +PromiseTestUtils.allowMatchingRejectionsGlobally(/File closed/); + +// On debug test runner, it takes about 50s to run the test. +requestLongerTimeout(4); + +/* eslint-disable mozilla/no-arbitrary-setTimeout */ + +const { fetch } = require("resource://devtools/shared/DevToolsUtils.js"); + +const debuggerHeadURL = + CHROME_URL_ROOT + "../../../debugger/test/mochitest/shared-head.js"; + +add_task(async function runTest() { + let { content: debuggerHead } = await fetch(debuggerHeadURL); + + // We remove its import of shared-head, which isn't available in browser toolbox process + // And isn't needed thanks to testHead's symbols + debuggerHead = debuggerHead.replace( + /Services.scriptloader.loadSubScript[^\)]*\);/g, + "" + ); + + await pushPref("devtools.browsertoolbox.scope", "everything"); + + const ToolboxTask = await initBrowserToolboxTask(); + await ToolboxTask.importFunctions({ + // head.js uses this method + registerCleanupFunction: () => {}, + waitForDispatch, + waitUntil, + }); + await ToolboxTask.importScript(debuggerHead); + + info("### First test breakpoint in the parent process script"); + const s = Cu.Sandbox("http://mozilla.org"); + + // Use a unique id for the fake script name in order to be able to run + // this test more than once. That's because the Sandbox is not immediately + // destroyed and so the debugger would display only one file but not necessarily + // connected to the latest sandbox. + const id = new Date().getTime(); + + // Pass a fake URL to evalInSandbox. If we just pass a filename, + // Debugger is going to fail and only display root folder (`/`) listing. + // But it won't try to fetch this url and use sandbox content as expected. + const testUrl = `http://mozilla.org/browser-toolbox-test-${id}.js`; + Cu.evalInSandbox( + `this.plop = function plop() { + const foo = 1; + return foo; +};`, + s, + "1.8", + testUrl, + 0 + ); + + // Execute the function every second in order to trigger the breakpoint + const interval = setInterval(s.plop, 1000); + + await ToolboxTask.spawn(testUrl, async _testUrl => { + /* global gToolbox, createDebuggerContext, waitForSources, waitForPaused, + addBreakpoint, assertPausedAtSourceAndLine, stepIn, findSource, + removeBreakpoint, resume, selectSource, assertNotPaused, assertBreakpoint, + assertTextContentOnLine, waitForResumed */ + Services.prefs.clearUserPref("devtools.debugger.tabs"); + Services.prefs.clearUserPref("devtools.debugger.pending-selected-location"); + + info("Waiting for debugger load"); + await gToolbox.selectTool("jsdebugger"); + const dbg = createDebuggerContext(gToolbox); + + await waitForSources(dbg, _testUrl); + + info("Loaded, selecting the test script to debug"); + const fileName = _testUrl.match(/browser-toolbox-test.*\.js/)[0]; + await selectSource(dbg, fileName); + + info("Add a breakpoint and wait to be paused"); + const onPaused = waitForPaused(dbg); + await addBreakpoint(dbg, fileName, 2); + await onPaused; + + const source = findSource(dbg, fileName); + assertPausedAtSourceAndLine(dbg, source.id, 2); + assertTextContentOnLine(dbg, 2, "const foo = 1;"); + is( + dbg.selectors.getBreakpointCount(), + 1, + "There is exactly one breakpoint" + ); + + await stepIn(dbg); + + assertPausedAtSourceAndLine(dbg, source.id, 3); + assertTextContentOnLine(dbg, 3, "return foo;"); + is( + dbg.selectors.getBreakpointCount(), + 1, + "We still have only one breakpoint after step-in" + ); + + // Remove the breakpoint before resuming in order to prevent hitting the breakpoint + // again during test closing. + await removeBreakpoint(dbg, source.id, 2); + + await resume(dbg); + + // Let a change for the interval to re-execute + await new Promise(r => setTimeout(r, 1000)); + + is(dbg.selectors.getBreakpointCount(), 0, "There is no more breakpoints"); + + assertNotPaused(dbg); + }); + + clearInterval(interval); + + info("### Now test breakpoint in a privileged content process script"); + const testUrl2 = `http://mozilla.org/content-process-test-${id}.js`; + await SpecialPowers.spawn(gBrowser.selectedBrowser, [testUrl2], testUrl => { + // Use a sandbox in order to have a URL to set a breakpoint + const s = Cu.Sandbox("http://mozilla.org"); + Cu.evalInSandbox( + `this.foo = function foo() { + const plop = 1; + return plop; +};`, + s, + "1.8", + testUrl, + 0 + ); + content.interval = content.setInterval(s.foo, 1000); + }); + await ToolboxTask.spawn(testUrl2, async _testUrl => { + const dbg = createDebuggerContext(gToolbox); + + const fileName = _testUrl.match(/content-process-test.*\.js/)[0]; + await waitForSources(dbg, _testUrl); + + await selectSource(dbg, fileName); + + const onPaused = waitForPaused(dbg); + await addBreakpoint(dbg, fileName, 2); + await onPaused; + + const source = findSource(dbg, fileName); + assertPausedAtSourceAndLine(dbg, source.id, 2); + assertTextContentOnLine(dbg, 2, "const plop = 1;"); + await assertBreakpoint(dbg, 2); + is(dbg.selectors.getBreakpointCount(), 1, "We have exactly one breakpoint"); + + await stepIn(dbg); + + assertPausedAtSourceAndLine(dbg, source.id, 3); + assertTextContentOnLine(dbg, 3, "return plop;"); + is( + dbg.selectors.getBreakpointCount(), + 1, + "We still have only one breakpoint after step-in" + ); + + // Remove the breakpoint before resuming in order to prevent hitting the breakpoint + // again during test closing. + await removeBreakpoint(dbg, source.id, 2); + + await resume(dbg); + + // Let a change for the interval to re-execute + await new Promise(r => setTimeout(r, 1000)); + + is(dbg.selectors.getBreakpointCount(), 0, "There is no more breakpoints"); + + assertNotPaused(dbg); + }); + + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => { + content.clearInterval(content.interval); + }); + + info("Trying pausing in a content process that crashes"); + + const crashingUrl = + "data:text/html,<script>setTimeout(()=>{debugger;})</script>"; + const crashingTab = await addTab(crashingUrl); + await ToolboxTask.spawn(crashingUrl, async url => { + const dbg = createDebuggerContext(gToolbox); + await waitForPaused(dbg); + const source = findSource(dbg, url); + assertPausedAtSourceAndLine(dbg, source.id, 1); + const thread = dbg.selectors.getThread(dbg.selectors.getCurrentThread()); + is(thread.isTopLevel, false, "The current thread is not the top level one"); + is(thread.targetType, "process", "The current thread is the tab one"); + }); + + info( + "Crash the tab and ensure the debugger resumes and switch to the main thread" + ); + await BrowserTestUtils.crashFrame(crashingTab.linkedBrowser); + + await ToolboxTask.spawn(null, async () => { + const dbg = createDebuggerContext(gToolbox); + await waitForResumed(dbg); + const thread = dbg.selectors.getThread(dbg.selectors.getCurrentThread()); + is(thread.isTopLevel, true, "The current thread is the top level one"); + }); + + await removeTab(crashingTab); + + await ToolboxTask.destroy(); +}); |