Bug 1707556 - [devtools] Add a thread configuration command r=ochameau,devtools-backward-compat-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D113751
This commit is contained in:
Hubert Boma Manilla 2021-05-17 11:55:39 +00:00
Родитель 50a85d3429
Коммит 2077c29048
17 изменённых файлов: 191 добавлений и 93 удалений

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

@ -318,22 +318,10 @@ async function pauseOnExceptions(
shouldPauseOnExceptions,
shouldPauseOnCaughtExceptions
) {
if (commands.targetCommand.hasTargetWatcherSupport()) {
const threadConfigurationActor = await commands.targetCommand.watcherFront.getThreadConfigurationActor();
await threadConfigurationActor.updateConfiguration({
pauseOnExceptions: shouldPauseOnExceptions,
ignoreCaughtExceptions: !shouldPauseOnCaughtExceptions,
});
} else {
return forEachThread(thread =>
thread.pauseOnExceptions(
shouldPauseOnExceptions,
// Providing opposite value because server
// uses "shouldIgnoreCaughtExceptions"
!shouldPauseOnCaughtExceptions
)
);
}
await commands.threadConfigurationCommand.updateConfiguration({
pauseOnExceptions: shouldPauseOnExceptions,
ignoreCaughtExceptions: !shouldPauseOnCaughtExceptions,
});
}
async function blackBox(sourceActor, isBlackBoxed, range) {

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

@ -45,6 +45,7 @@ const { DevToolsServer: WorkerDevToolsServer } = worker.require(
const { DevToolsClient } = require("devtools/client/devtools-client");
const { ObjectFront } = require("devtools/client/fronts/object");
const { LongStringFront } = require("devtools/client/fronts/string");
const { createCommandsDictionary } = require("devtools/shared/commands/index");
const { addDebuggerToGlobal } = ChromeUtils.import(
"resource://gre/modules/jsdebugger.jsm"
@ -370,27 +371,38 @@ async function getTestTab(client, title) {
}
return null;
}
// Attach to |client|'s tab whose title is |title|; and return the targetFront instance
// referring to that tab.
/**
* Attach to the client's tab whose title is specified
* @param {Object} client
* @param {Object} title
* @returns commands
*/
async function attachTestTab(client, title) {
const descriptorFront = await getTestTab(client, title);
const targetFront = await descriptorFront.getTarget();
await targetFront.attach();
return targetFront;
const commands = await createCommandsDictionary(descriptorFront);
await commands.targetCommand.startListening();
return commands;
}
// Attach to |client|'s tab whose title is |title|, and then attach to
// that tab's thread. Return the TargetFront referring to the tab,
// and a ThreadFront referring to the thread.
/**
* Attach to the client's tab whose title is specified, and then attach to
* that tab's thread.
* @param {Object} client
* @param {Object} title
* @returns {Object}
* targetFront
* threadFront
* commands
*/
async function attachTestThread(client, title) {
const targetFront = await attachTestTab(client, title);
const commands = await attachTestTab(client, title);
const targetFront = commands.targetCommand.targetFront;
const threadFront = await targetFront.getFront("thread");
await targetFront.attachThread({
autoBlackBox: true,
});
Assert.equal(threadFront.state, "attached", "Thread front is attached");
return { targetFront, threadFront };
return { targetFront, threadFront, commands };
}
/**
@ -857,7 +869,7 @@ function threadFrontTest(test, options = {}) {
// Attach to the fake tab target and retrieve the ThreadFront instance.
// Automatically resume as the thread is paused by default after attach.
const { targetFront, threadFront } = await attachTestThread(
const { targetFront, threadFront, commands } = await attachTestThread(
client,
scriptName
);
@ -878,6 +890,7 @@ function threadFrontTest(test, options = {}) {
client,
server,
targetFront,
commands,
};
if (waitForFinish) {
// Use dispatchToMainThread so that the test function does not have to

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

@ -9,7 +9,7 @@
*/
add_task(
threadFrontTest(async ({ threadFront, debuggee }) => {
threadFrontTest(async ({ threadFront, debuggee, commands }) => {
await executeOnNextTickAndWaitForPause(
() => evalCode(debuggee),
threadFront
@ -20,7 +20,10 @@ add_task(
const sourceFront = await getSource(threadFront, BLACK_BOXED_URL);
await blackBox(sourceFront);
threadFront.pauseOnExceptions(true, false);
await commands.threadConfigurationCommand.updateConfiguration({
pauseOnExceptions: true,
ignoreCaughtExceptions: false,
});
threadFront.resume();
const packet = await waitForPause(threadFront);

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

@ -10,7 +10,7 @@
*/
add_task(
threadFrontTest(async ({ threadFront, debuggee }) => {
threadFrontTest(async ({ threadFront, debuggee, commands }) => {
const packet1 = await executeOnNextTickAndWaitForPause(
() => evalCode(debuggee),
threadFront
@ -18,7 +18,10 @@ add_task(
const source = await getSourceById(threadFront, packet1.frame.where.actor);
threadFront.pauseOnExceptions(true, false);
await commands.threadConfigurationCommand.updateConfiguration({
pauseOnExceptions: true,
ignoreCaughtExceptions: false,
});
const location = { sourceUrl: source.url, line: 3 };
threadFront.setBreakpoint(location, { condition: "throw new Error()" });

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

@ -11,13 +11,16 @@
add_task(
threadFrontTest(
async ({ threadFront, debuggee }) => {
async ({ threadFront, debuggee, commands }) => {
await executeOnNextTickAndWaitForPause(
() => evaluateTestCode(debuggee),
threadFront
);
threadFront.pauseOnExceptions(true, true);
await commands.threadConfigurationCommand.updateConfiguration({
pauseOnExceptions: true,
ignoreCaughtExceptions: true,
});
await resume(threadFront);
const paused = await waitForPause(threadFront);
Assert.equal(paused.why.type, "exception");

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

@ -10,13 +10,16 @@
*/
add_task(
threadFrontTest(async ({ threadFront, debuggee }) => {
threadFrontTest(async ({ threadFront, debuggee, commands }) => {
await executeOnNextTickAndWaitForPause(
() => evaluateTestCode(debuggee),
threadFront
);
threadFront.pauseOnExceptions(true, false);
await commands.threadConfigurationCommand.updateConfiguration({
pauseOnExceptions: true,
ignoreCaughtExceptions: false,
});
threadFront.resume();
const packet = await waitForPause(threadFront);

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

@ -9,8 +9,11 @@
*/
add_task(
threadFrontTest(async ({ threadFront, debuggee }) => {
threadFront.pauseOnExceptions(true, false);
threadFrontTest(async ({ threadFront, debuggee, commands }) => {
await commands.threadConfigurationCommand.updateConfiguration({
pauseOnExceptions: true,
ignoreCaughtExceptions: false,
});
const packet = await executeOnNextTickAndWaitForPause(
() => evaluateTestCode(debuggee),

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

@ -11,13 +11,16 @@
add_task(
threadFrontTest(
async ({ threadFront, debuggee }) => {
async ({ threadFront, debuggee, commands }) => {
await executeOnNextTickAndWaitForPause(
() => evaluateTestCode(debuggee),
threadFront
);
threadFront.pauseOnExceptions(true, false);
await commands.threadConfigurationCommand.updateConfiguration({
pauseOnExceptions: true,
ignoreCaughtExceptions: false,
});
await resume(threadFront);
const paused = await waitForPause(threadFront);
Assert.equal(paused.why.type, "exception");

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

@ -4,6 +4,8 @@
"use strict";
const { waitForTick } = require("devtools/shared/DevToolsUtils");
/**
* Test that setting pauseOnExceptions to true and then to false will not cause
* the debuggee to pause when an exception is thrown.
@ -11,7 +13,7 @@
add_task(
threadFrontTest(
async ({ threadFront, client, debuggee }) => {
async ({ threadFront, client, debuggee, commands }) => {
let onResume = null;
let packet = null;
@ -20,23 +22,12 @@ add_task(
onResume = threadFront.resume();
});
await threadFront.pauseOnExceptions(true, true);
try {
/* eslint-disable */
Cu.evalInSandbox(
` // 1
function stopMe() { // 2
throw 42; // 3
} // 4
stopMe(); // 5
`, // 6
debuggee,
"1.8",
"test_pause_exceptions-04.js",
1
);
/* eslint-enable */
} catch (e) {}
await commands.threadConfigurationCommand.updateConfiguration({
pauseOnExceptions: true,
ignoreCaughtExceptions: true,
});
await evaluateTestCode(debuggee, "42");
await onResume;
@ -50,45 +41,23 @@ add_task(
onResume = threadFront.resume();
});
await threadFront.pauseOnExceptions(false, true);
try {
/* eslint-disable */
Cu.evalInSandbox(
` // 1
function dontStopMe() { // 2
throw 43; // 3
} // 4
dontStopMe(); // 5
`, // 6
debuggee,
"1.8",
"test_pause_exceptions-04.js",
1
);
/* eslint-enable */
} catch (e) {}
await commands.threadConfigurationCommand.updateConfiguration({
pauseOnExceptions: false,
ignoreCaughtExceptions: true,
});
await evaluateTestCode(debuggee, "43");
// Test that the paused listener callback hasn't been called
// on the thrown error from dontStopMe()
Assert.equal(!!packet, false);
await threadFront.pauseOnExceptions(true, true);
try {
/* eslint-disable */
Cu.evalInSandbox(
` // 1
function stopMeAgain() { // 2
throw 44; // 3
} // 4
stopMeAgain(); // 5
`, // 6
debuggee,
"1.8",
"test_pause_exceptions-04.js",
1
);
/* eslint-enable */
} catch (e) {}
await commands.threadConfigurationCommand.updateConfiguration({
pauseOnExceptions: true,
ignoreCaughtExceptions: true,
});
await evaluateTestCode(debuggee, "44");
await onResume;
@ -104,3 +73,23 @@ add_task(
}
)
);
async function evaluateTestCode(debuggee, throwValue) {
await waitForTick();
try {
/* eslint-disable */
Cu.evalInSandbox(
` // 1
function stopMeAgain() { // 2
throw ${throwValue}; // 3
} // 4
stopMeAgain(); // 5
`, // 6
debuggee,
"1.8",
"test_pause_exceptions-04.js",
1
);
/* eslint-enable */
} catch (e) {}
}

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

@ -15,6 +15,8 @@ const Commands = {
targetCommand: "devtools/shared/commands/target/target-command",
targetConfigurationCommand:
"devtools/shared/commands/target-configuration/target-configuration-command",
threadConfigurationCommand:
"devtools/shared/commands/thread-configuration/thread-configuration-command",
};
/**

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

@ -8,6 +8,7 @@ DIRS += [
"resource",
"target",
"target-configuration",
"thread-configuration",
]
DevToolsModules(

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

@ -0,0 +1,7 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
"thread-configuration-command.js",
)

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

@ -0,0 +1,7 @@
"use strict";
// General rule from /.eslintrc.js only accept folders matching **/test*/browser*/
// where is this folder doesn't match, so manually apply browser test config
module.exports = {
extends: ["plugin:mozilla/browser-test"],
};

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

@ -0,0 +1,7 @@
[DEFAULT]
tags = devtools
subsuite = devtools
support-files =
!/devtools/client/shared/test/shared-head.js
head.js

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

@ -0,0 +1,13 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/* eslint no-unused-vars: [2, {"vars": "local"}] */
/* import-globals-from ../../../../client/shared/test/shared-head.js */
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/shared/test/shared-head.js",
this
);

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

@ -0,0 +1,53 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/**
* The ThreadConfigurationCommand should be used to maintain thread settings
* sent from the client for the thread actor.
*
* See the ThreadConfigurationActor for a list of supported configuration options.
*/
class ThreadConfigurationCommand {
constructor({ commands, watcherFront }) {
this._commands = commands;
this._watcherFront = watcherFront;
}
/**
* Return a promise that resolves to the related thread configuration actor's front.
*
* @return {Promise<ThreadConfigurationFront>}
*/
async getThreadConfigurationFront() {
const front = await this._watcherFront.getThreadConfigurationActor();
return front;
}
async updateConfiguration(configuration) {
if (this._commands.targetCommand.hasTargetWatcherSupport()) {
const threadConfigurationFront = await this.getThreadConfigurationFront();
const updatedConfiguration = await threadConfigurationFront.updateConfiguration(
configuration
);
this._configuration = updatedConfiguration;
} else {
const threadFronts = await this._commands.targetCommand.getAllFronts(
this._commands.targetCommand.ALL_TYPES,
"thread"
);
await Promise.all(
threadFronts.map(threadFront =>
threadFront.pauseOnExceptions(
configuration.pauseOnExceptions,
configuration.ignoreCaughtExceptions
)
)
);
}
}
}
module.exports = ThreadConfigurationCommand;

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

@ -8,7 +8,7 @@ const { generateActorSpec, Arg, types } = require("devtools/shared/protocol");
types.addDictType("thread-configuration.configuration", {
pauseOnExceptions: "nullable:boolean",
IgnoreCaughtExceptions: "nullable:boolean",
ignoreCaughtExceptions: "nullable:boolean",
});
const threadConfigurationSpec = generateActorSpec({