Bug 1592584 - [devtools] Accept worker targets in console. r=ochameau.

The `dom.worker.console.dispatch_events_to_main_thread` pref is used by platform
code to check if console API messages in the worker thread should be dispatched
to the main thread. If so, the message parameters are cloned, or stringified if
they can't be. This is currently the default behavior.

The pref is checked on the server side and added as a trait to the root actor.
On the client, if the pref isn't true, then we accept messages coming from
worker targets in the console. We can't accept them without condition, otherwise
we would get duplicated message (from the main thread AND the worker thread).

The browser_webconsole_console_logging_workers_api.js test is repurposed for
worker logging since it was disabled on e10s anyway. We add a few test case
to check we can get cached and live message, and that non-clonable object, like
worker scope, are displayed like regular objects when the pref is false.

Differential Revision: https://phabricator.services.mozilla.com/D85397
This commit is contained in:
Nicolas Chevobbe 2020-11-05 10:17:36 +00:00
Родитель 274d1a5dde
Коммит 4bad3995de
8 изменённых файлов: 133 добавлений и 27 удалений

Просмотреть файл

@ -206,7 +206,6 @@ skip-if = true # Bug 1405250
[browser_webconsole_console_group_open_no_scroll.js]
[browser_webconsole_console_group.js]
[browser_webconsole_console_logging_workers_api.js]
skip-if = e10s # SharedWorkers console events are not received on the current process because they could run on any process.
[browser_webconsole_console_table_post_alterations.js]
[browser_webconsole_console_table.js]
[browser_webconsole_console_timeStamp.js]

Просмотреть файл

@ -1,8 +1,7 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that the basic console.log()-style APIs and filtering work for
// sharedWorkers
// Tests that the basic console.log() works for workers
"use strict";
@ -11,17 +10,77 @@ const TEST_URI =
"test/browser/test-console-workers.html";
add_task(async function() {
info("Run the test with worker events dispatched to main thread");
await pushPref("dom.worker.console.dispatch_events_to_main_thread", true);
await testWorkerMessage();
info("Run the test with worker events NOT dispatched to main thread");
await pushPref("dom.worker.console.dispatch_events_to_main_thread", false);
await testWorkerMessage(true);
});
async function testWorkerMessage(directConnectionToWorkerThread = false) {
const hud = await openNewTabAndConsole(TEST_URI);
const message = await waitFor(() =>
findMessage(hud, "foo-bar-shared-worker")
const cachedMessage = await waitFor(() =>
findMessage(hud, "initial-message-from-worker")
);
is(
message.querySelector(".message-body").textContent,
`foo-bar-shared-worker Object { foo: "bar" }`,
"log from SharedWorker is displayed as expected"
ok(true, "We get the cached message from the worker");
ok(
cachedMessage
.querySelector(".message-body")
.textContent.includes(`Object { foo: "bar" }`),
"The simple object is logged as expected"
);
if (directConnectionToWorkerThread) {
const scopeOi = cachedMessage.querySelector(
".object-inspector:last-of-type"
);
ok(
scopeOi.textContent.includes(
`DedicatedWorkerGlobalScope {`,
`The worker scope is logged as expected: ${scopeOi.textContent}`
)
);
}
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
content.wrappedJSObject.logFromWorker("live-message");
});
const liveMessage = await waitFor(() => findMessage(hud, "log-from-worker"));
ok(true, "We get the cached message from the worker");
ok(
liveMessage
.querySelector(".message-body")
.textContent.includes(`live-message`),
"The message is logged as expected"
);
if (directConnectionToWorkerThread) {
const scopeOi = liveMessage.querySelector(".object-inspector:last-of-type");
ok(
scopeOi.textContent.includes(
`DedicatedWorkerGlobalScope {`,
`The worker scope is logged as expected: ${scopeOi.textContent}`
)
);
info("Check that Symbol are properly logged");
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
content.wrappedJSObject.logFromWorker("live-message");
});
const symbolMessage = await waitFor(() =>
findMessage(hud, "Symbol(logged-symbol-from-worker)")
);
ok(symbolMessage, "Symbol logged from worker is visible in the console");
}
const onMessagesCleared = hud.ui.once("messages-cleared");
await clearOutput(hud);
await onMessagesCleared;
});
}

Просмотреть файл

@ -7,11 +7,22 @@
</head>
<body>
<script type="text/javascript">
/* eslint-disable */
new SharedWorker(`data:application/javascript,
console.log("foo-bar-shared-worker", {foo: "bar"});
self.close();
"use strict";
/* exported logFromWorker */
const worker = new Worker(`data:application/javascript,
console.log("initial-message-from-worker", {foo: "bar"}, globalThis);
onmessage = function (e) {
console.log("log-from-worker", e.data.msg, globalThis);
console.log(Symbol("logged-symbol-from-worker"));
};
`);
function logFromWorker(msg) {
worker.postMessage({type: "log", msg});
}
</script>
</body>
</html>

Просмотреть файл

@ -490,17 +490,30 @@ class WebConsoleUI {
}
// Allow frame, but only in content toolbox, i.e. still ignore them in
// the context of the browser toolbox as we inspect messages via the process
// targets
// Also ignore workers as they are not supported yet. (see bug 1592584)
// the context of the browser toolbox as we inspect messages via the process targets
const listenForFrames = this.hud.targetList.targetFront.isLocalTab;
if (
targetFront.targetType != this.hud.targetList.TYPES.PROCESS &&
(targetFront.targetType != this.hud.targetList.TYPES.FRAME ||
!listenForFrames)
) {
const { TYPES } = this.hud.targetList;
const isWorkerTarget =
targetFront.targetType == TYPES.WORKER ||
targetFront.targetType == TYPES.SHARED_WORKER ||
targetFront.targetType == TYPES.SERVICE_WORKER;
const acceptTarget =
// Unconditionally accept all process targets, this should only happens in the
// multiprocess browser toolbox/console
targetFront.targetType == TYPES.PROCESS ||
(targetFront.targetType == TYPES.FRAME && listenForFrames) ||
// Accept worker targets if the platform dispatching of worker messages to the main
// thread is disabled (e.g. we get them directly from the worker target).
(isWorkerTarget &&
!this.hud.targetList.rootFront.traits
.workerConsoleApiMessagesDispatchedToMainThread);
if (!acceptTarget) {
return;
}
const proxy = new WebConsoleConnectionProxy(this, targetFront);
this.additionalProxies.set(targetFront, proxy);
await proxy.connect();

Просмотреть файл

@ -153,6 +153,13 @@ exports.RootActor = protocol.ActorClassWithSpec(rootSpec, {
perfActorVersion: 1,
// Supports watchpoints in the server for Fx71+
watchpoints: true,
// Added in Fx84 to expose the pref value to the client. Services.prefs is undefined
// in xpcshell tests.
workerConsoleApiMessagesDispatchedToMainThread: Services.prefs
? Services.prefs.getBoolPref(
"dom.worker.console.dispatch_events_to_main_thread"
)
: true,
};
},

Просмотреть файл

@ -1436,9 +1436,19 @@ const WebConsoleActor = ActorClassWithSpec(webconsoleSpec, {
* The "clearMessagesCache" request handler.
*/
clearMessagesCache: function() {
if (isWorker) {
// At the moment there is no mechanism available to clear the Console API cache for
// a given worker target (See https://bugzilla.mozilla.org/show_bug.cgi?id=1674336).
// Worker messages from the console service (e.g. error) are emitted from the main
// thread, so this cache will be cleared when the associated document target cache
// is cleared.
return;
}
const windowId = !this.parentActor.isRootActor
? WebConsoleUtils.getInnerWindowId(this.global)
: null;
const ConsoleAPIStorage = Cc[
"@mozilla.org/consoleAPI-storage;1"
].getService(Ci.nsIConsoleAPIStorage);

Просмотреть файл

@ -13,14 +13,19 @@ module.exports = async function({ targetList, targetFront, onAvailable }) {
// Also allow frame, but only in content toolbox, i.e. still ignore them in
// the context of the browser toolbox as we inspect messages via the process
// targets
// Also ignore workers as they are not supported yet. (see bug 1592584)
const listenForFrames = targetList.targetFront.isLocalTab;
const isAllowed =
// Allow workers when messages aren't dispatched to the main thread.
const listenForWorkers = !targetList.rootFront.traits
.workerConsoleApiMessagesDispatchedToMainThread;
const acceptTarget =
targetFront.isTopLevel ||
targetFront.targetType === targetList.TYPES.PROCESS ||
(targetFront.targetType === targetList.TYPES.FRAME && listenForFrames);
(targetFront.targetType === targetList.TYPES.FRAME && listenForFrames) ||
(targetFront.targetType === targetList.TYPES.WORKER && listenForWorkers);
if (!isAllowed) {
if (!acceptTarget) {
return;
}

Просмотреть файл

@ -127,7 +127,9 @@ class TargetList extends EventEmitter {
// Public flag to allow listening for workers even if the fission pref is off
// This allows listening for workers in the content toolbox outside of fission contexts
// For now, this is only toggled by tests.
this.listenForWorkers = false;
this.listenForWorkers =
this.rootFront.traits.workerConsoleApiMessagesDispatchedToMainThread ===
false;
this.listenForServiceWorkers = false;
this.destroyServiceWorkersOnNavigation = false;
}