Several tests introspect workers through the nsIWorkerDebuggerManager -- by
enumerating it, matching a worker by its (relative) script URL, or checking
process placement. With the parent-process RemoteWorkerDebugger on by default a
worker registers its debugger in the parent process, which reports the absolute
script URL, registers asynchronously over IPC, and (for content workers) is no
longer visible in the content-process manager. These tests assume the local
WorkerDebugger's synchronous, content-process, relative-URL behaviour and fail.
Pin dom.worker.remoteDebugger.enabled to false in these tests so they keep using
the local WorkerDebugger. These checks are debugger-location-dependent: the
legacy worker-introspection path still needs to be modernized to the
RemoteWorkerDebugger model, and each pin (or test) should be removed once the
local WorkerDebugger mechanism is removed:
- devtools/client/shared/test/browser_dbg_listworkers.js
- devtools/shared/webconsole/test/chrome/test_console_worker.html
- devtools/shared/webconsole/test/chrome/test_jsterm_autocomplete.html
- dom/workers/test/test_shutdownCheck.xhtml
- dom/workers/test/browser_privilegedmozilla_remoteworker.js
- dom/workers/test/browser_serviceworker_fetch_new_process.js
- dom/base/crashtests/eventSource_invalid_scheme_worker_shutdown.html
- toolkit/components/extensions/test/browser/browser_ext_background_serviceworker.js
The extension service-worker xpcshell helper (head_service_worker.js) is instead
updated to watch the parent-process WorkerDebuggerManager when the pref is on, so
test_ext_background_service_worker keeps working through the remote debugger
rather than being pinned.
dom_worker_helper.js matches a debugger by absolute or relative script URL (the
parent reports the absolute URL), and test_WorkerDebugger.xhtml only asserts
nsIWorkerDebugger.window for the local debugger, since a remote worker has no
window in the parent process.
Run the worker tests that exercise worker debugging under both pref values, so
both the local WorkerDebugger and the parent-process RemoteWorkerDebugger stay
covered on CI regardless of the channel default. dom_worker_helper.js gains an
addTaskWithBothWorkerDebuggers helper, and each of the following runs once with
dom.worker.remoteDebugger.enabled=false and once with it true:
- the WorkerDebugger* / WorkerDebuggerGlobalScope* chrome mochitests (except
test_WorkerDebugger_frozen.xhtml)
- dom/workers/test/browser_WorkerDebugger{,_waiting}.initialize.js
- devtools browser_worker_tracer.js and browser_target_command_tab_workers.js
- the WebDriver BiDi browser_WorkerListener_{chromeWorker,serviceWorker,
sharedWorker}.js tests
A few worker tests keep global state that does not reset cleanly between the two
runs -- browser_target_command_browser_workers.js enumerates every worker in the
browser and its parent-process workers linger, test_WorkerDebugger_frozen.xhtml
manipulates frozen/suspended state, and browser_WorkerListener.js drives multiple
tabs -- so they keep running at the channel default rather than twice.
Add tests covering the parent-process worker debugging that the
RemoteWorkerDebugger enables:
- browser_parent_worker_nested.js: a chrome worker and the nested worker it
spawns both register through the parent-process RemoteWorkerDebugger, and the
nested worker's debugger URL is resolved to an absolute URL.
- browser_resources_thread_states_parent_worker.js: THREAD_STATE resources let
DevTools interactively pause and resume a chrome worker via main-process
(Browser Toolbox) commands.
Differential Revision: https://phabricator.services.mozilla.com/D306652
Commands
Commands are singletons, which can be easily used by any frontend code. They are meant to be exposed widely to the frontend so that any code can easily call any of their methods.
Commands classes expose static methods, which:
- route to the right Front/Actor's method
- handle backward compatibility
- map to many target's actor if needed
These classes are instantiated once per descriptor and may have inner state, emit events, fire callbacks,...
A transient backward compat need, required by Fission refactorings will be to have some code checking a trait, and either:
- call a single method on a parent process actor (like BreakpointListActor.setBreakpoint)
- otherwise, call a method on each target's scoped actor (like ThreadActor.setBreakpoint, that, for each available target)
Without such layer, we would have to put such code here and there in the frontend code. This will be harder to remove later, once we get rid of old pre-fission-refactoring codepaths.
This layer already exists in some panels, but we are using slightly different names and practices:
- Debugger uses "client" (devtools/client/debugger/src/client/) and "commands" (devtools/client/debugger/src/client/firefox/commands.js)
Debugger's commands already bundle the code to dispatch an action to many target's actor.
They also contain some backward compat code.
Today, we pass around a
clientobject via thunkArgs, which is mapped to commands.js, instead we could pass a debugger command object. - Network Monitor uses "connector" (devtools/client/netmonitor/src/connector)
Connectors also bundles backward compat and dispatch to many target's actor.
Today, we pass the
connectorto all middlewares from configureStore, we could instead pass the netmonitor command object. - Web Console has:
- devtools/client/webconsole/actions/input.js:handleHelperResult(), where we have to put some code, which is a duplicate of Netmonitor Connector, and could be shared via a netmonitor command class.
- Inspector is probably the panel doing the most dispatch to many target's actor. Codes using getAllInspectorFronts could all be migrated to an inspector command class: https://searchfox.org/mozilla-central/search?q=symbol:%23getAllInspectorFronts&redirect=false and simplify a bit the frontend. It is also one panel, which still register listener to each target's inspector/walker fronts. Because inspector isn't using resources. But this work, registering listeners for each target might be done by such layer and translate the many actor's event into a unified one.
Last, but not least, this layer may allow us to slowly get rid of protocol.js. Command classes aren't Fronts, nor are they particularly connected to protocol.js. If we make it so that all the Frontend code using Fronts uses Commands instead, we might more easily get away from protocol.js.
If you want to create a new command, you can use a bash script to help your bootstrap all basic required files:
$ ./create-command.sh command-file-name CommandName
Where the first argument will be the name used for folder and files, using lower case and dash as separator. And the second argument will be the class name in code, using camlcase.