From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../framework/test/browser_target_parents.js | 189 +++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 devtools/client/framework/test/browser_target_parents.js (limited to 'devtools/client/framework/test/browser_target_parents.js') diff --git a/devtools/client/framework/test/browser_target_parents.js b/devtools/client/framework/test/browser_target_parents.js new file mode 100644 index 0000000000..795219abef --- /dev/null +++ b/devtools/client/framework/test/browser_target_parents.js @@ -0,0 +1,189 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test a given Target's parentFront attribute returns the correct parent front. + +const { + DevToolsClient, +} = require("resource://devtools/client/devtools-client.js"); +const { + DevToolsServer, +} = require("resource://devtools/server/devtools-server.js"); +const { + createCommandsDictionary, +} = require("resource://devtools/shared/commands/index.js"); + +const TEST_URL = `data:text/html;charset=utf-8,
`; + +// Test against Tab targets +add_task(async function () { + const tab = await addTab(TEST_URL); + + const client = await setupDebuggerClient(); + const mainRoot = client.mainRoot; + + const tabDescriptors = await mainRoot.listTabs(); + + const concurrentCommands = []; + for (const descriptor of tabDescriptors) { + concurrentCommands.push( + (async () => { + const commands = await createCommandsDictionary(descriptor); + // Descriptor's getTarget will only work if the TargetCommand watches for the first top target + await commands.targetCommand.startListening(); + })() + ); + } + info("Instantiate all tab's commands and initialize their TargetCommand"); + await Promise.all(concurrentCommands); + + await testGetTargetWithConcurrentCalls(tabDescriptors, tabTarget => { + // We only call BrowsingContextTargetFront.attach and not TargetMixin.attachAndInitThread. + // So very few things are done. + return !!tabTarget.targetForm?.traits; + }); + + await client.close(); + await removeTab(tab); +}); + +// Test against Process targets +add_task(async function () { + const client = await setupDebuggerClient(); + const mainRoot = client.mainRoot; + + const processes = await mainRoot.listProcesses(); + + // Assert that concurrent calls to getTarget resolves the same target and that it is already attached + // With that, we were chasing a precise race, where a second call to ProcessDescriptor.getTarget() + // happens between the instantiation of ContentProcessTarget and its call to attach() from getTarget + // function. + await testGetTargetWithConcurrentCalls(processes, processTarget => { + // We only call ContentProcessTargetFront.attach and not TargetMixin.attachAndInitThread. + // So nothing is done for content process targets. + return true; + }); + + await client.close(); +}); + +// Test against Webextension targets +add_task(async function () { + const client = await setupDebuggerClient(); + + const mainRoot = client.mainRoot; + + const addons = await mainRoot.listAddons(); + await Promise.all( + // some extensions, such as themes, are not debuggable. Filter those out + // before trying to connect. + addons + .filter(a => a.debuggable) + .map(async addonDescriptorFront => { + const addonFront = await addonDescriptorFront.getTarget(); + ok(addonFront, "Got the addon target"); + }) + ); + + await client.close(); +}); + +// Test against worker targets on parent process +add_task(async function () { + const client = await setupDebuggerClient(); + + const mainRoot = client.mainRoot; + + const { workers } = await mainRoot.listWorkers(); + + ok(!!workers.length, "list workers returned a non-empty list of workers"); + + for (const workerDescriptorFront of workers) { + let targetFront; + try { + targetFront = await workerDescriptorFront.getTarget(); + } catch (e) { + // Ignore race condition where we are trying to connect to a worker + // related to a previous test which is being destroyed. + if ( + e.message.includes("nsIWorkerDebugger.initialize") || + workerDescriptorFront.isDestroyed() || + !workerDescriptorFront.name + ) { + info("Failed to connect to " + workerDescriptorFront.url); + continue; + } + throw e; + } + // Bug 1767760: name might be null on some worker which are probably initializing or destroying. + if (!workerDescriptorFront.name) { + info("Failed to connect to " + workerDescriptorFront.url); + continue; + } + + is( + workerDescriptorFront, + targetFront, + "For now, worker descriptors and targets are the same object (see bug 1667404)" + ); + // Check that accessing descriptor#name getter doesn't throw (See Bug 1714974). + ok( + workerDescriptorFront.name.includes(".js") || + workerDescriptorFront.name.includes(".mjs"), + `worker descriptor front holds the worker file name (${workerDescriptorFront.name})` + ); + is( + workerDescriptorFront.isWorkerDescriptor, + true, + "isWorkerDescriptor is true" + ); + } + + await client.close(); +}); + +async function setupDebuggerClient() { + // Instantiate a minimal server + DevToolsServer.init(); + DevToolsServer.allowChromeProcess = true; + if (!DevToolsServer.createRootActor) { + DevToolsServer.registerAllActors(); + } + const transport = DevToolsServer.connectPipe(); + const client = new DevToolsClient(transport); + await client.connect(); + return client; +} + +async function testGetTargetWithConcurrentCalls(descriptors, isTargetAttached) { + // Assert that concurrent calls to getTarget resolves the same target and that it is already attached + await Promise.all( + descriptors.map(async descriptor => { + const promises = []; + const concurrentCalls = 10; + for (let i = 0; i < concurrentCalls; i++) { + const targetPromise = descriptor.getTarget(); + // Every odd runs, wait for a tick to introduce some more randomness + if (i % 2 == 0) { + await wait(0); + } + promises.push( + targetPromise.then(target => { + ok(isTargetAttached(target), "The target is attached"); + return target; + }) + ); + } + const targets = await Promise.all(promises); + for (let i = 1; i < concurrentCalls; i++) { + is( + targets[0], + targets[i], + "All the targets returned by concurrent calls to getTarget are the same" + ); + } + }) + ); +} -- cgit v1.2.3