Bug 1717724 - [devtools] Remove attachConsole sequence. r=nchevobbe

This is one step forward removing target attach sequence on the client side.
So that we can notify about target front immediately from TargetCommand.

I had to tweak TargetMixin destroy to avoid failures in browser_dbg_listtabs-01.js
a call to targetFront.reconfigure was never resolving, because the target destroy
was stuck on this call to detach().
We were trying to call detach() while the descriptor was destroyed (from a server side notification).
The target being a child of descriptor it ends up destroy itself, but the request is meant to fail.

Depends on D118585

Differential Revision: https://phabricator.services.mozilla.com/D118586
This commit is contained in:
Alexandre Poirot 2021-10-19 12:28:00 +00:00
parent 716014661a
commit 971e021dba
6 changed files with 62 additions and 116 deletions

View File

@ -20,8 +20,9 @@ add_task(async function() {
const tabDescriptors = await mainRoot.listTabs();
await testGetTargetWithConcurrentCalls(tabDescriptors, tabTarget => {
// Tab Target is attached when it has a console front.
return !!tabTarget.getCachedFront("console");
// We only call BrowsingContextTargetFront.attach and not TargetMixin.attachAndInitThread.
// So very few things are done.
return !!tabTarget.traits;
});
await client.close();
@ -40,8 +41,9 @@ add_task(async function() {
// happens between the instantiation of ContentProcessTarget and its call to attach() from getTarget
// function.
await testGetTargetWithConcurrentCalls(processes, processTarget => {
// Content Process Target is attached when it has a console front.
return !!processTarget.getCachedFront("console");
// We only call ContentProcessTargetFront.attach and not TargetMixin.attachAndInitThread.
// So nothing is done for content process targets.
return true;
});
await client.close();

View File

@ -95,8 +95,7 @@ class WorkerDescriptorFront extends DescriptorMixin(
const workerTargetForm = await super.getTarget();
// Set the console actor ID on the form to expose it to Target.attachConsole
// Set the ThreadActor on the target form so it is accessible by getFront
// Set the console and thread actor IDs on the form so it is accessible by TargetMixin.getFront
this.targetForm.consoleActor = workerTargetForm.consoleActor;
this.targetForm.threadActor = workerTargetForm.threadActor;
@ -104,7 +103,6 @@ class WorkerDescriptorFront extends DescriptorMixin(
return this;
}
await this.attachConsole();
return this;
})();
return this._attach;

View File

@ -44,11 +44,6 @@ class ContentProcessTargetFront extends TargetMixin(
}
attach() {
// All target actors have a console actor to attach.
// All but xpcshell test actors... which is using a ContentProcessTargetActor
if (this.targetForm.consoleActor) {
return this.attachConsole();
}
return Promise.resolve();
}

View File

@ -468,19 +468,6 @@ function TargetMixin(parentClass) {
}
}
// Attach the console actor
async attachConsole() {
const consoleFront = await this.getFront("console");
if (this.isDestroyedOrBeingDestroyed()) {
return;
}
// Calling startListeners will populate the traits as it's the first request we
// make to the front.
await consoleFront.startListeners([]);
}
/**
* This method attaches the target and then attaches its related thread, sending it
* the options it needs (e.g. breakpoints, pause on exception setting, ).

View File

@ -125,12 +125,6 @@ class WindowGlobalTargetFront extends TargetMixin(
// @backward-compat { version 93 } Remove this. All the traits are on form and can be accessed
// using getTraits.
this.traits = response.traits || {};
// xpcshell tests from devtools/server/tests/xpcshell/ are implementing
// fake WindowGlobalTargetActor which do not expose any console actor.
if (this.targetForm.consoleActor) {
await this.attachConsole();
}
})();
return this._attach;
}

View File

@ -13,98 +13,68 @@ var { DevToolsClient } = require("devtools/client/devtools-client");
const TAB1_URL = EXAMPLE_URL + "doc_empty-tab-01.html";
const TAB2_URL = EXAMPLE_URL + "doc_empty-tab-02.html";
var gTab1, gTab1Front, gTab2, gTab2Front, gClient;
function test() {
add_task(async function test() {
DevToolsServer.init();
DevToolsServer.registerAllActors();
const transport = DevToolsServer.connectPipe();
gClient = new DevToolsClient(transport);
gClient.connect().then(([aType, aTraits]) => {
is(aType, "browser", "Root actor should identify itself as a browser.");
const client = new DevToolsClient(transport);
const [aType] = await client.connect();
is(aType, "browser", "Root actor should identify itself as a browser.");
Promise.resolve(null)
.then(testFirstTab)
.then(testSecondTab)
.then(testRemoveTab)
.then(testAttachRemovedTab)
.then(() => gClient.close())
.then(finish)
.catch(error => {
ok(false, "Got an error: " + error.message + "\n" + error.stack);
});
});
}
function testFirstTab() {
return addTab(TAB1_URL).then(tab => {
gTab1 = tab;
return getTargetActorForUrl(gClient, TAB1_URL).then(front => {
ok(front, "Should find a target actor for the first tab.");
gTab1Front = front;
});
});
}
function testSecondTab() {
return addTab(TAB2_URL).then(tab => {
gTab2 = tab;
return getTargetActorForUrl(gClient, TAB1_URL).then(firstFront => {
return getTargetActorForUrl(gClient, TAB2_URL).then(secondFront => {
is(firstFront, gTab1Front, "First tab's actor shouldn't have changed.");
ok(secondFront, "Should find a target actor for the second tab.");
gTab2Front = secondFront;
});
});
});
}
function testRemoveTab() {
return removeTab(gTab1).then(() => {
return getTargetActorForUrl(gClient, TAB1_URL).then(front => {
ok(!front, "Shouldn't find a target actor for the first tab anymore.");
});
});
}
function testAttachRemovedTab() {
return removeTab(gTab2).then(() => {
return new Promise((resolve, reject) => {
gClient.on("paused", () => {
ok(
false,
"Attaching to an exited target actor shouldn't generate a pause."
);
reject();
});
const { actorID } = gTab2Front;
gTab2Front.reconfigure({}).then(null, error => {
ok(
error.message.includes(
`Connection closed, pending request to ${actorID}, type reconfigure failed`
),
"Actor is gone since the tab was removed."
);
resolve();
});
});
});
}
registerCleanupFunction(function() {
gTab1 = null;
gTab1Front = null;
gTab2 = null;
gTab2Front = null;
gClient = null;
const firstTab = await testFirstTab(client);
const secondTab = await testSecondTab(client, firstTab.front);
await testRemoveTab(client, firstTab.tab);
await testAttachRemovedTab(secondTab.tab, secondTab.front);
await client.close();
});
async function getTargetActorForUrl(client, url) {
async function testFirstTab(client) {
const tab = await addTab(TAB1_URL);
const front = await getDescriptorActorForUrl(client, TAB1_URL);
ok(front, "Should find a target actor for the first tab.");
return { tab, front };
}
async function testSecondTab(client, firstTabFront) {
const tab = await addTab(TAB2_URL);
const firstFront = await getDescriptorActorForUrl(client, TAB1_URL);
const secondFront = await getDescriptorActorForUrl(client, TAB2_URL);
is(firstFront, firstTabFront, "First tab's actor shouldn't have changed.");
ok(secondFront, "Should find a target actor for the second tab.");
return { tab, front: secondFront };
}
async function testRemoveTab(client, firstTab) {
await removeTab(firstTab);
const front = await getDescriptorActorForUrl(client, TAB1_URL);
ok(!front, "Shouldn't find a target actor for the first tab anymore.");
}
async function testAttachRemovedTab(secondTab, secondTabFront) {
await removeTab(secondTab);
const { actorID } = secondTabFront;
try {
await secondTabFront.getFavicon({});
ok(
false,
"any request made to the descriptor for a closed tab should have failed"
);
} catch (error) {
ok(
error.message.includes(
`Connection closed, pending request to ${actorID}, type getFavicon failed`
),
"Actor is gone since the tab was removed."
);
}
}
async function getDescriptorActorForUrl(client, url) {
const tabDescriptors = await client.mainRoot.listTabs();
const tabDescriptor = tabDescriptors.find(front => front.url == url);
return tabDescriptor?.getTarget();
return tabDescriptor;
}