summaryrefslogtreecommitdiffstats
path: root/devtools/shared/test-helpers
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/shared/test-helpers')
-rw-r--r--devtools/shared/test-helpers/allocation-tracker.js7
-rw-r--r--devtools/shared/test-helpers/moz.build2
-rw-r--r--devtools/shared/test-helpers/test-stepper.js97
-rw-r--r--devtools/shared/test-helpers/test_javascript_tracer.js72
-rw-r--r--devtools/shared/test-helpers/thread-helpers.sys.mjs143
-rw-r--r--devtools/shared/test-helpers/xpcshell.toml6
6 files changed, 102 insertions, 225 deletions
diff --git a/devtools/shared/test-helpers/allocation-tracker.js b/devtools/shared/test-helpers/allocation-tracker.js
index 17dcfafdf0..345eb23a43 100644
--- a/devtools/shared/test-helpers/allocation-tracker.js
+++ b/devtools/shared/test-helpers/allocation-tracker.js
@@ -41,7 +41,8 @@ const MemoryReporter = Cc["@mozilla.org/memory-reporter-manager;1"].getService(
const global = Cu.getGlobalForObject(this);
const { addDebuggerToGlobal } = ChromeUtils.importESModule(
- "resource://gre/modules/jsdebugger.sys.mjs"
+ "resource://gre/modules/jsdebugger.sys.mjs",
+ { global: "contextual" }
);
addDebuggerToGlobal(global);
@@ -313,14 +314,14 @@ exports.allocationTracker = function ({
logAllocationSites(message, sources, { first = 1000 } = {}) {
const allocationList = Object.entries(sources)
// Sort by number of total object
- .sort(([srcA, itemA], [srcB, itemB]) => itemB.count - itemA.count)
+ .sort(([, itemA], [, itemB]) => itemB.count - itemA.count)
// Keep only the first n-th sources, with the most allocations
.filter((_, i) => i < first)
.map(([src, item]) => {
const lines = [];
Object.entries(item.lines)
// Filter out lines where we only freed objects
- .filter(([line, count]) => count > 0)
+ .filter(([, count]) => count > 0)
.sort(([lineA, countA], [lineB, countB]) => {
if (countA != countB) {
return countB - countA;
diff --git a/devtools/shared/test-helpers/moz.build b/devtools/shared/test-helpers/moz.build
index 92b1d5212d..2c14b6a7b7 100644
--- a/devtools/shared/test-helpers/moz.build
+++ b/devtools/shared/test-helpers/moz.build
@@ -5,7 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
- "thread-helpers.sys.mjs",
+ "test-stepper.js",
"tracked-objects.sys.mjs",
)
diff --git a/devtools/shared/test-helpers/test-stepper.js b/devtools/shared/test-helpers/test-stepper.js
new file mode 100644
index 0000000000..314a687dbf
--- /dev/null
+++ b/devtools/shared/test-helpers/test-stepper.js
@@ -0,0 +1,97 @@
+/* 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";
+
+const {
+ startTracing,
+ addTracingListener,
+ stopTracing,
+ removeTracingListener,
+} = require("resource://devtools/server/tracer/tracer.jsm");
+
+let testFileContent;
+
+function traceFrame({ frame }) {
+ const { script } = frame;
+ const { lineNumber, columnNumber } = script.getOffsetMetadata(frame.offset);
+
+ const { url } = script.source;
+ const filename = url.substr(url.lastIndexOf("/") + 1);
+ const line = testFileContent[lineNumber - 1];
+ // Grey out the beginning of the line, before frame's column,
+ // and display an arrow before displaying the rest of the line.
+ const code =
+ "\x1b[2m" +
+ line.substr(0, columnNumber - 1) +
+ "\x1b[0m" +
+ "\u21A6 " +
+ line.substr(columnNumber - 1);
+
+ const position = (lineNumber + ":" + columnNumber).padEnd(7);
+ logStep(`${filename} @ ${position} :: ${code}`);
+
+ // Disable builtin tracer logging
+ return false;
+}
+
+function logStep(message) {
+ dump(` \x1b[2m[STEP]\x1b[0m ${message}\n`);
+}
+
+const tracingListener = {
+ onTracingFrame: traceFrame,
+ onTracingFrameStep: traceFrame,
+};
+
+exports.start = function (testGlobal, testUrl, pause) {
+ const tracerOptions = {
+ global: testGlobal,
+ // Ensure tracing each execution within functions (and not only function calls)
+ traceSteps: true,
+ // Only trace the running test and nothing else
+ filterFrameSourceUrl: testUrl,
+ };
+ testFileContent = readURI(testUrl).split("\n");
+ // Only pause on each step if the passed value is a number,
+ // otherwise we are only going to print each executed line in the test script.
+ if (!isNaN(pause)) {
+ // Delay each step by an amount of milliseconds
+ tracerOptions.pauseOnStep = Number(pause);
+ logStep(`Tracing all test script steps with ${pause}ms pause`);
+ logStep(
+ `/!\\ Be conscious about each pause releasing the event loop and breaking run-to-completion.`
+ );
+ } else {
+ logStep(`Tracing all test script steps`);
+ }
+ logStep(
+ `'\u21A6 ' symbol highlights what precise instruction is being called`
+ );
+ startTracing(tracerOptions);
+ addTracingListener(tracingListener);
+};
+
+exports.stop = function () {
+ stopTracing();
+ removeTracingListener(tracingListener);
+};
+
+function readURI(uri) {
+ const { NetUtil } = ChromeUtils.importESModule(
+ "resource://gre/modules/NetUtil.sys.mjs",
+ { global: "contextual" }
+ );
+ const stream = NetUtil.newChannel({
+ uri: NetUtil.newURI(uri, "UTF-8"),
+ loadUsingSystemPrincipal: true,
+ }).open();
+ const count = stream.available();
+ const data = NetUtil.readInputStreamToString(stream, count, {
+ charset: "UTF-8",
+ });
+
+ stream.close();
+ return data;
+}
diff --git a/devtools/shared/test-helpers/test_javascript_tracer.js b/devtools/shared/test-helpers/test_javascript_tracer.js
deleted file mode 100644
index 268e054c56..0000000000
--- a/devtools/shared/test-helpers/test_javascript_tracer.js
+++ /dev/null
@@ -1,72 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
-
-"use strict";
-
-/**
- * Test for the thread helpers utility module.
- *
- * This uses a xpcshell test in order to avoid recording the noise
- * of all Firefox components when using a mochitest.
- */
-
-const { traceAllJSCalls } = ChromeUtils.importESModule(
- "resource://devtools/shared/test-helpers/thread-helpers.sys.mjs"
-);
-// ESLint thinks this is a browser test, but it's actually an xpcshell
-// test and so `setTimeout` isn't available out of the box.
-// eslint-disable-next-line mozilla/no-redeclare-with-import-autofix
-const { setTimeout } = ChromeUtils.importESModule(
- "resource://gre/modules/Timer.sys.mjs"
-);
-
-add_task(async function sanityCheck() {
- let ranTheOtherEventLoop = false;
- setTimeout(function otherEventLoop() {
- ranTheOtherEventLoop = true;
- }, 0);
- const jsTracer = traceAllJSCalls();
- function foo() {}
- for (let i = 0; i < 10; i++) {
- foo();
- }
- jsTracer.stop();
- ok(
- !ranTheOtherEventLoop,
- "When we don't pause frame execution, the other event do not execute"
- );
-});
-
-add_task(async function withPrefix() {
- const jsTracer = traceAllJSCalls({ prefix: "my-prefix" });
- function foo() {}
- for (let i = 0; i < 10; i++) {
- foo();
- }
- jsTracer.stop();
- ok(true, "Were able to run with a prefix argument");
-});
-
-add_task(async function pause() {
- const start = Cu.now();
- let ranTheOtherEventLoop = false;
- setTimeout(function otherEventLoop() {
- ranTheOtherEventLoop = true;
- }, 0);
- const jsTracer = traceAllJSCalls({ pause: 100 });
- function foo() {}
- for (let i = 0; i < 10; i++) {
- foo();
- }
- jsTracer.stop();
- const duration = Cu.now() - start;
- Assert.greater(
- duration,
- 10 * 100,
- "The execution of the for loop was slow down by at least the pause duration in each loop"
- );
- ok(
- ranTheOtherEventLoop,
- "When we pause frame execution, the other event can execute"
- );
-});
diff --git a/devtools/shared/test-helpers/thread-helpers.sys.mjs b/devtools/shared/test-helpers/thread-helpers.sys.mjs
deleted file mode 100644
index b99fc16f00..0000000000
--- a/devtools/shared/test-helpers/thread-helpers.sys.mjs
+++ /dev/null
@@ -1,143 +0,0 @@
-/* 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/. */
-
-/**
- * Helper code to play with the javascript thread
- **/
-
-function getSandboxWithDebuggerSymbol() {
- // Bug 1835268 - Changing this to an ES module import currently throws an
- // assertion in test_javascript_tracer.js in debug builds.
- const { addDebuggerToGlobal } = ChromeUtils.import(
- "resource://gre/modules/jsdebugger.jsm"
- );
- const systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
-
- const debuggerSandbox = Cu.Sandbox(systemPrincipal, {
- // This sandbox is also reused for ChromeDebugger implementation.
- // As we want to load the `Debugger` API for debugging chrome contexts,
- // we have to ensure loading it in a distinct compartment from its debuggee.
- freshCompartment: true,
- invisibleToDebugger: true,
- });
- addDebuggerToGlobal(debuggerSandbox);
-
- return debuggerSandbox;
-}
-
-/**
- * Implementation of a Javascript tracer logging traces to stdout.
- *
- * To be used like this:
-
- const { traceAllJSCalls } = ChromeUtils.importESModule(
- "resource://devtools/shared/test-helpers/thread-helpers.sys.mjs"
- );
- const jsTracer = traceAllJSCalls();
- [... execute some code to tracer ...]
- jsTracer.stop();
-
- * @param prefix String
- * Optional, if passed, this will be displayed in front of each
- * line reporting a new frame execution.
- * @param pause Number
- * Optional, if passed, hold off each frame for `pause` ms,
- * by letting the other event loops run in between.
- * Be careful that it can introduce unexpected race conditions
- * that can't necessarily be reproduced without this.
- */
-export function traceAllJSCalls({ prefix = "", pause } = {}) {
- const debuggerSandbox = getSandboxWithDebuggerSymbol();
-
- debuggerSandbox.Services = Services;
- const f = Cu.evalInSandbox(
- "(" +
- function (pauseInMs, prefixString) {
- const dbg = new Debugger();
- // Add absolutely all the globals...
- dbg.addAllGlobalsAsDebuggees();
- // ...but avoid tracing this sandbox code
- const global = Cu.getGlobalForObject(this);
- dbg.removeDebuggee(global);
-
- // Add all globals created later on
- dbg.onNewGlobalObject = g => dbg.addDebuggee(g);
-
- function formatDisplayName(frame) {
- if (frame.type === "call") {
- const callee = frame.callee;
- return callee.name || callee.userDisplayName || callee.displayName;
- }
-
- return `(${frame.type})`;
- }
-
- function stop() {
- dbg.onEnterFrame = undefined;
- dbg.removeAllDebuggees();
- }
- global.stop = stop;
-
- let depth = 0;
- dbg.onEnterFrame = frame => {
- if (depth == 100) {
- dump(
- "Looks like an infinite loop? We stop the js tracer, but code may still be running!\n"
- );
- stop();
- return;
- }
-
- const { script } = frame;
- const { lineNumber, columnNumber } = script.getOffsetMetadata(
- frame.offset
- );
- const padding = new Array(depth).join(" ");
- dump(
- `${prefixString}${padding}--[${frame.implementation}]--> ${
- script.source.url
- } @ ${lineNumber}:${columnNumber} - ${formatDisplayName(frame)}\n`
- );
-
- depth++;
- frame.onPop = () => {
- depth--;
- };
-
- // Optionaly pause the frame execute by letting the other event loop to run in between.
- if (typeof pauseInMs == "number") {
- let freeze = true;
- const timer = Cc["@mozilla.org/timer;1"].createInstance(
- Ci.nsITimer
- );
- timer.initWithCallback(
- () => {
- freeze = false;
- },
- pauseInMs,
- Ci.nsITimer.TYPE_ONE_SHOT
- );
- Services.tm.spinEventLoopUntil("debugger-slow-motion", function () {
- return !freeze;
- });
- }
- };
-
- return { stop };
- } +
- ")",
- debuggerSandbox,
- undefined,
- "debugger-javascript-tracer",
- 1,
- /* enforceFilenameRestrictions */ false
- );
- f(pause, prefix);
-
- return {
- stop() {
- debuggerSandbox.stop();
- },
- };
-}
diff --git a/devtools/shared/test-helpers/xpcshell.toml b/devtools/shared/test-helpers/xpcshell.toml
deleted file mode 100644
index 5ded960f83..0000000000
--- a/devtools/shared/test-helpers/xpcshell.toml
+++ /dev/null
@@ -1,6 +0,0 @@
-[DEFAULT]
-tags = "devtools"
-firefox-appdir = "browser"
-skip-if = ["os == 'android'"]
-
-["test_javascript_tracer.js"]