Bug 1678550 - [devtools] Load damp.js using the main DevTools Loader r=perftest-reviewers,nchevobbe,ochameau

Depends on D97626

Differential Revision: https://phabricator.services.mozilla.com/D97727
This commit is contained in:
Julian Descottes 2021-01-04 13:07:08 +00:00
parent b45dc96375
commit d8c21acf2f
5 changed files with 106 additions and 47 deletions

View File

@ -3,7 +3,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const loaders = ChromeUtils.import("resource://devtools/shared/base-loader.js"); const BaseLoader = ChromeUtils.import(
"resource://devtools/shared/base-loader.js"
);
const { require: devtoolsRequire, loader } = ChromeUtils.import( const { require: devtoolsRequire, loader } = ChromeUtils.import(
"resource://devtools/shared/Loader.jsm" "resource://devtools/shared/Loader.jsm"
); );
@ -94,21 +96,21 @@ function BrowserLoader(options) {
* *
* @param string baseURI * @param string baseURI
* Base path to load modules from. * Base path to load modules from.
* @param Object window
* The window instance to evaluate modules within
* @param Boolean useOnlyShared
* If true, ignores `baseURI` and only loads the shared
* BROWSER_BASED_DIRS via BrowserLoader.
* @param Function commonLibRequire * @param Function commonLibRequire
* Require function that should be used to load common libraries, like React. * Require function that should be used to load common libraries, like React.
* Allows for sharing common modules between tools, instead of loading a new * Allows for sharing common modules between tools, instead of loading a new
* instance into each tool. For example, pass "toolbox.browserRequire" here. * instance into each tool. For example, pass "toolbox.browserRequire" here.
* @param Boolean useOnlyShared
* If true, ignores `baseURI` and only loads the shared
* BROWSER_BASED_DIRS via BrowserLoader.
* @param Object window
* The window instance to evaluate modules within
*/ */
function BrowserLoaderBuilder({ function BrowserLoaderBuilder({
baseURI, baseURI,
window,
useOnlyShared,
commonLibRequire, commonLibRequire,
useOnlyShared,
window,
}) { }) {
assert( assert(
!!baseURI !== !!useOnlyShared, !!baseURI !== !!useOnlyShared,
@ -198,13 +200,13 @@ function BrowserLoaderBuilder({
}, },
}; };
const mainModule = loaders.Module(baseURI, joinURI(baseURI, "main.js")); const mainModule = BaseLoader.Module(baseURI, joinURI(baseURI, "main.js"));
this.loader = loaders.Loader(opts); this.loader = BaseLoader.Loader(opts);
// When running tests, expose the BrowserLoader instance for metrics tests. // When running tests, expose the BrowserLoader instance for metrics tests.
if (flags.testing) { if (flags.testing) {
window.getBrowserLoaderForWindow = () => this; window.getBrowserLoaderForWindow = () => this;
} }
this.require = loaders.Require(this.loader, mainModule); this.require = BaseLoader.Require(this.loader, mainModule);
} }
BrowserLoaderBuilder.prototype = { BrowserLoaderBuilder.prototype = {

View File

@ -78,6 +78,19 @@ function DevToolsLoader({
paths.promise = "resource://gre/modules/Promise-backend.js"; paths.promise = "resource://gre/modules/Promise-backend.js";
} }
// DAMP tests use a dynamic path. If DEBUG_DEVTOOLS_DAMP_TEST_PATH was set as
// a custom preference, add a corresponding path mapping entry.
// DAMP runner and tests are under testing/talos/talos/tests/devtools
const dampTestPath = Services.prefs.getCharPref(
"devtools.damp.test-path",
""
);
if (dampTestPath) {
// damp-test points to testing/talos/talos/tests/devtools/addon/content/
// (prefixed by the dynamically generated talos server)
paths["damp-test"] = dampTestPath;
}
this.loader = new Loader({ this.loader = new Loader({
paths, paths,
invisibleToDebugger, invisibleToDebugger,

View File

@ -5,6 +5,9 @@ ChromeUtils.defineModuleGetter(
"Services", "Services",
"resource://gre/modules/Services.jsm" "resource://gre/modules/Services.jsm"
); );
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
/* globals ExtensionAPI */ /* globals ExtensionAPI */
this.damp = class extends ExtensionAPI { this.damp = class extends ExtensionAPI {
@ -13,14 +16,48 @@ this.damp = class extends ExtensionAPI {
damp: { damp: {
startTest() { startTest() {
let { rootURI } = context.extension; let { rootURI } = context.extension;
let window = context.appWindow;
if (!("Damp" in window)) {
let script = rootURI.resolve("content/damp.js");
Services.scriptloader.loadSubScript(script, window);
}
let damp = new window.Damp(); // Some notes about using a DevTools loader for DAMP.
return damp.startTest(rootURI); //
// 1. The DAMP loader needs to be same loader as the one used by the
// toolbox later on. Otherwise, we will not retrieve the proper
// instance of some modules.
// The main devtools loader is the exported `loader` from Loader.jsm,
// we have to use that.
//
// 2. The DAMP test path is dynamic, so we cannot hardcode the path
// mapping in the DevTools loader. To workaround this, we set the path
// in an env variable. This will then be read by Loader.jsm when it
// creates the main DevTools loader. It is important to set this
// before accessing the Loader for the first time.
//
// 3. DAMP contains at least one protocol test that loads a DAMP test
// file in the content process (tests/server/protocol.js). In order
// for the damp-test path mapping to work, Loaders in all processes
// should be able to read the "damp test path" information. We use
// use a custom preference to make the information available to
// all processes.
dump("[damp-api] Expose damp test path as a char preference\n");
// dampTestPath points to testing/talos/talos/tests/devtools/addon/content/
// (prefixed by the dynamically generated talos server)
const dampTestPath = rootURI.resolve("content");
Services.prefs.setCharPref("devtools.damp.test-path", dampTestPath);
dump("[damp-api] Retrieve the main DevTools loader\n");
const { loader, require } = ChromeUtils.import(
"resource://devtools/shared/Loader.jsm"
);
// The loader should already support the damp-test path mapping.
// We add two additional globals.
loader.loader.globals.rootURI = rootURI;
loader.loader.globals.dampWindow = context.appWindow;
dump("[damp-api] Instanciate the DAMP runner and start the test\n");
const { Damp } = require("damp-test/damp");
const damp = new Damp();
return damp.startTest();
}, },
}, },
}; };

View File

@ -1,19 +1,27 @@
"use strict";
/* globals dampWindow, exports, require, res:true, rootURI */
// eslint-disable-next-line mozilla/no-define-cc-etc
const { Ci, Cc, Cu } = require("chrome");
const {
gBrowser,
MozillaFileLogger,
performance,
requestIdleCallback,
} = dampWindow;
const ChromeUtils = require("ChromeUtils");
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
var { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
const { AddonManager } = ChromeUtils.import( const { AddonManager } = ChromeUtils.import(
"resource://gre/modules/AddonManager.jsm" "resource://gre/modules/AddonManager.jsm"
); );
const env = Cc["@mozilla.org/process/environment;1"].getService( const env = Cc["@mozilla.org/process/environment;1"].getService(
Ci.nsIEnvironment Ci.nsIEnvironment
); );
XPCOMUtils.defineLazyGetter(this, "require", function() {
let { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
return require;
});
// Record allocation count in new subtests if DEBUG_DEVTOOLS_ALLOCATIONS is set to // Record allocation count in new subtests if DEBUG_DEVTOOLS_ALLOCATIONS is set to
// "normal". Print allocation sites to stdout if DEBUG_DEVTOOLS_ALLOCATIONS is set to // "normal". Print allocation sites to stdout if DEBUG_DEVTOOLS_ALLOCATIONS is set to
// "verbose". // "verbose".
@ -28,8 +36,6 @@ function getMostRecentBrowserWindow() {
return Services.wm.getMostRecentWindow("navigator:browser"); return Services.wm.getMostRecentWindow("navigator:browser");
} }
/* globals res:true */
function Damp() {} function Damp() {}
Damp.prototype = { Damp.prototype = {
@ -239,7 +245,7 @@ Damp.prototype = {
_done: false, _done: false,
_runNextTest() { _runNextTest() {
window.clearTimeout(this._timeout); clearTimeout(this._timeout);
if (this._nextTestIndex >= this._tests.length) { if (this._nextTestIndex >= this._tests.length) {
this._onSequenceComplete(); this._onSequenceComplete();
@ -251,9 +257,9 @@ Damp.prototype = {
this._currentTest = test; this._currentTest = test;
dump(`Loading test '${test}'\n`); dump(`Loading test '${test}'\n`);
let testMethod = require(this.rootURI.resolve(`content/tests/${test}`)); let testMethod = require(`damp-test/tests/${test}`);
this._timeout = window.setTimeout(() => { this._timeout = setTimeout(() => {
this.error("Test timed out"); this.error("Test timed out");
}, TEST_TIMEOUT); }, TEST_TIMEOUT);
@ -278,11 +284,11 @@ Damp.prototype = {
}, },
_log(str) { _log(str) {
if (window.MozillaFileLogger && window.MozillaFileLogger.log) { if (MozillaFileLogger && MozillaFileLogger.log) {
window.MozillaFileLogger.log(str); MozillaFileLogger.log(str);
} }
window.dump(str); dump(str);
}, },
_logLine(str) { _logLine(str) {
@ -295,7 +301,7 @@ Damp.prototype = {
var out = ""; var out = "";
for (var i in this._results) { for (var i in this._results) {
res = this._results[i]; const res = this._results[i];
var disp = [] var disp = []
.concat(res.value) .concat(res.value)
.map(function(a) { .map(function(a) {
@ -418,15 +424,18 @@ Damp.prototype = {
await this.garbageCollect(); await this.garbageCollect();
}, },
startTest(rootURI) { /**
* This is the main entry point for DAMP, called from
* testing/talos/talos/tests/devtools/addon/api
*/
startTest() {
let promise = new Promise(resolve => { let promise = new Promise(resolve => {
this.testDone = resolve; this.testDone = resolve;
}); });
this.rootURI = rootURI;
try { try {
dump("Initialize the head file with a reference to this DAMP instance\n"); dump("Initialize the head file with a reference to this DAMP instance\n");
let head = require(rootURI.resolve("content/tests/head.js")); let head = require("damp-test/tests/head.js");
head.initialize(this); head.initialize(this);
this._registerDampLoadActors(); this._registerDampLoadActors();
@ -438,7 +447,7 @@ Damp.prototype = {
// Filter tests via `./mach --subtests filter` command line argument // Filter tests via `./mach --subtests filter` command line argument
let filter = Services.prefs.getCharPref("talos.subtests", ""); let filter = Services.prefs.getCharPref("talos.subtests", "");
let DAMP_TESTS = require(rootURI.resolve("content/damp-tests.js")); let DAMP_TESTS = require("damp-test/damp-tests.js");
let tests = DAMP_TESTS.filter(test => !test.disabled).filter(test => let tests = DAMP_TESTS.filter(test => !test.disabled).filter(test =>
test.name.includes(filter) test.name.includes(filter)
); );
@ -506,10 +515,10 @@ Damp.prototype = {
ChromeUtils.registerWindowActor("DampLoad", { ChromeUtils.registerWindowActor("DampLoad", {
kind: "JSWindowActor", kind: "JSWindowActor",
parent: { parent: {
moduleURI: this.rootURI.resolve("content/actors/DampLoadParent.jsm"), moduleURI: rootURI.resolve("content/actors/DampLoadParent.jsm"),
}, },
child: { child: {
moduleURI: this.rootURI.resolve("content/actors/DampLoadChild.jsm"), moduleURI: rootURI.resolve("content/actors/DampLoadChild.jsm"),
events: { events: {
pageshow: { mozSystemGroup: true }, pageshow: { mozSystemGroup: true },
}, },
@ -528,12 +537,12 @@ Damp.prototype = {
_getDampLoadEventDispatcher() { _getDampLoadEventDispatcher() {
if (!this._dampLoadEventDispatcher) { if (!this._dampLoadEventDispatcher) {
const DampLoadParentModule = ChromeUtils.import( const DampLoadParentModule = require("damp-test/actors/DampLoadParent.jsm");
this.rootURI.resolve("content/actors/DampLoadParent.jsm")
);
this._dampLoadEventDispatcher = DampLoadParentModule.EventDispatcher; this._dampLoadEventDispatcher = DampLoadParentModule.EventDispatcher;
} }
return this._dampLoadEventDispatcher; return this._dampLoadEventDispatcher;
}, },
}; };
exports.Damp = Damp;

View File

@ -37,8 +37,6 @@ module.exports = async function() {
let tab = await testSetup(SIMPLE_URL); let tab = await testSetup(SIMPLE_URL);
let messageManager = tab.linkedBrowser.messageManager; let messageManager = tab.linkedBrowser.messageManager;
let url = module.uri.replace(/protocol\.js$/, "actor.js");
// Register a test actor within the content process // Register a test actor within the content process
messageManager.loadFrameScript( messageManager.loadFrameScript(
"data:,(" + "data:,(" +
@ -47,7 +45,7 @@ module.exports = async function() {
const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm"); const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
const { ActorRegistry } = require("devtools/server/actors/utils/actor-registry"); const { ActorRegistry } = require("devtools/server/actors/utils/actor-registry");
ActorRegistry.registerModule("${url}", { ActorRegistry.registerModule("damp-test/tests/server/actor.js", {
prefix: "dampTest", prefix: "dampTest",
constructor: "DampTestActor", constructor: "DampTestActor",
type: { target: true } type: { target: true }