Bug 1498420 Convert talos tart extension to a webextension r=mconley a=Aryx

The biggest change here is that the tart.html page that drives the
test (not to be confused with the pages loaded in new tabs during the
test) moves from a chrome: page inside the extension to a regular http:
page.  That also required revamping the communication between tart.html
and the extension.  The rest of the changes are just the packaging and
startup mechanics for the test extension.

Differential Revision: https://phabricator.services.mozilla.com/D8807

--HG--
rename : testing/talos/talos/tests/tart/addon/bootstrap.js => testing/talos/talos/tests/tart/addon/api.js
rename : testing/talos/talos/tests/tart/addon/content/blank.icon.html => testing/talos/talos/tests/tart/addon/chrome/blank.icon.html
rename : testing/talos/talos/tests/tart/addon/install.rdf => testing/talos/talos/tests/tart/addon/manifest.json
rename : testing/talos/talos/tests/tart/addon/content/tart.html => testing/talos/talos/tests/tart/tart.html
rename : testing/talos/talos/tests/tart/addon/content/tart.ico => testing/talos/talos/tests/tart/tart.ico
extra : source : 3133f6ab1bd8ea2aa261f8e9024ab3fb8eb0ddcb
This commit is contained in:
Andrew Swan 2018-10-15 16:23:17 -07:00
parent d3ae9b224b
commit d629667d68
13 changed files with 170 additions and 153 deletions

View File

@ -0,0 +1,91 @@
"use strict";
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
Services: "resource://gre/modules/Services.jsm",
});
XPCOMUtils.defineLazyServiceGetter(this, "aomStartup",
"@mozilla.org/addons/addon-manager-startup;1",
"amIAddonManagerStartup");
XPCOMUtils.defineLazyServiceGetter(this, "clipboardHelper",
"@mozilla.org/widget/clipboardhelper;1",
"nsIClipboardHelper");
/* globals ExtensionAPI */
const PREFIX = "tart@mozilla.org";
this.tart = class extends ExtensionAPI {
constructor(...args) {
super(...args);
this.loadedWindows = new WeakSet();
}
onStartup() {
const manifestURI = Services.io.newURI("manifest.json", null, this.extension.rootURI);
this.chromeHandle = aomStartup.registerChrome(manifestURI, [
["content", "tart", "chrome/"],
]);
this.framescriptURL = this.extension.baseURI.resolve("/content/framescript.js");
Services.mm.loadFrameScript(this.framescriptURL, true);
Services.mm.addMessageListener(`${PREFIX}:chrome-exec-message`, this);
}
onShutdown() {
Services.mm.removeMessageListener(`${PREFIX}:chrome-exec-message`, this);
Services.mm.removeDelayedFrameScript(this.framescriptURL);
this.chromeHandle.destruct();
}
receiveMessage({target, data}) {
let win = target.ownerGlobal;
if (!this.loadedWindows.has(win)) {
let {baseURI} = this.extension;
Services.scriptloader.loadSubScript(baseURI.resolve("/content/Profiler.js"), win);
Services.scriptloader.loadSubScript(baseURI.resolve("/content/tart.js"), win);
this.loadedWindows.add(win);
}
function sendResult(result) {
target.messageManager.sendAsyncMessage(`${PREFIX}:chrome-exec-reply`,
{id: data.id, result});
}
let {command} = data;
switch (command.name) {
case "ping":
sendResult();
break;
case "runTest":
(new win.Tart()).startTest(sendResult, command.data);
break;
case "setASAP":
Services.prefs.setIntPref("layout.frame_rate", 0);
Services.prefs.setIntPref("docshell.event_starvation_delay_hint", 1);
sendResult();
break;
case "unsetASAP":
Services.prefs.clearUserPref("layout.frame_rate");
Services.prefs.clearUserPref("docshell.event_starvation_delay_hint");
sendResult();
break;
case "toClipboard":
clipboardHelper.copyString(command.data);
sendResult();
break;
default:
Cu.reportError(`Unknown TART command ${command.name}\n`);
break;
}
}
};

View File

@ -1,52 +0,0 @@
"use strict";
/* globals initializeBrowser */
// PLEASE NOTE:
//
// The canonical version of this file lives in testing/talos/talos, and
// is duplicated in a number of test add-ons in directories below it.
// Please do not update one withput updating all.
// Reads the chrome.manifest from a legacy non-restartless extension and loads
// its overlays into the appropriate top-level windows.
ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
ChromeUtils.import("resource://gre/modules/Services.jsm");
const windowTracker = {
init() {
Services.ww.registerNotification(this);
},
async observe(window, topic, data) {
if (topic === "domwindowopened") {
await new Promise(resolve =>
window.addEventListener("DOMWindowCreated", resolve, {once: true}));
let {document} = window;
let {documentURI} = document;
if (documentURI !== AppConstants.BROWSER_CHROME_URL) {
return;
}
initializeBrowser(window);
}
},
};
function readSync(uri) {
let channel = NetUtil.newChannel({uri, loadUsingSystemPrincipal: true});
let buffer = NetUtil.readInputStream(channel.open2());
return new TextDecoder().decode(buffer);
}
function startup(data, reason) {
Services.scriptloader.loadSubScript(data.resourceURI.resolve("content/initialize_browser.js"));
windowTracker.init();
}
function shutdown(data, reason) {}
function install(data, reason) {}
function uninstall(data, reason) {}

View File

@ -1 +0,0 @@
content tart content/

View File

@ -2,9 +2,22 @@
const TART_PREFIX = "tart@mozilla.org:";
addEventListener(TART_PREFIX + "chrome-exec-event", function(e) {
if (content.document.documentURI.indexOf("chrome://tart/content/tart.html")) {
// Can have url fragment. Backward compatible version of !str.startsWidth("prefix")
throw new Error("Cannot be used outside of TART's launch page");
if (!content.location.pathname.endsWith("tart.html")) {
Cu.reportError(`Ignore chrome-exec-event on non-tart page ${content.location.href}`);
return;
}
function dispatchReply(result) {
let contentEvent = Cu.cloneInto({
bubbles: true,
detail: result,
}, content);
content.dispatchEvent(new content.CustomEvent(e.detail.replyEvent, contentEvent));
}
if (e.detail.command.name == "ping") {
dispatchReply();
return;
}
// eslint-disable-next-line mozilla/avoid-Date-timing
@ -13,7 +26,7 @@
addMessageListener(TART_PREFIX + "chrome-exec-reply", function done(reply) {
if (reply.data.id == uniqueMessageId) {
removeMessageListener(TART_PREFIX + "chrome-exec-reply", done);
e.detail.doneCallback(reply.data.result);
dispatchReply(reply.data.result);
}
});
@ -21,5 +34,5 @@
command: e.detail.command,
id: uniqueMessageId,
});
}, false);
}, false, true);
})();

View File

@ -1,54 +0,0 @@
function initializeBrowser(win) {
Services.scriptloader.loadSubScript("chrome://tart/content/Profiler.js", win);
Services.scriptloader.loadSubScript("chrome://tart/content/tart.js", win);
var prefs = Services.prefs;
const TART_PREFIX = "tart@mozilla.org:";
// "services" which the framescript can execute at the chrome process
var proxiedServices = {
runTest(config, callback) {
(new win.Tart()).startTest(callback, config);
},
setASAP() {
prefs.setIntPref("layout.frame_rate", 0);
prefs.setIntPref("docshell.event_starvation_delay_hint", 1);
},
unsetASAP() {
prefs.clearUserPref("layout.frame_rate");
prefs.clearUserPref("docshell.event_starvation_delay_hint");
},
toClipboard(text) {
const gClipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"]
.getService(Ci.nsIClipboardHelper);
gClipboardHelper.copyString(text);
},
};
var groupMM = win.getGroupMessageManager("browsers");
groupMM.loadFrameScript("chrome://tart/content/framescript.js", true);
// listener/executor on the chrome process for tart.html
groupMM.addMessageListener(TART_PREFIX + "chrome-exec-message", function listener(m) {
function sendResult(result) {
groupMM.broadcastAsyncMessage(TART_PREFIX + "chrome-exec-reply", {
id: m.data.id,
result,
});
}
var command = m.data.command;
if (!proxiedServices.hasOwnProperty(command.name))
throw new Error("TART: service doesn't exist: '" + command.name + "'");
var service = proxiedServices[command.name];
if (command.name == "runTest") // Needs async execution
service(command.data, sendResult);
else
sendResult(service(command.data));
});
}

View File

@ -393,27 +393,13 @@ Tart.prototype = {
},
_reportAllResults() {
var testNames = [];
var testResults = [];
var out = "";
for (var i in this._results) {
res = this._results[i];
var disp = [].concat(res.value).map(function(a) { return (isNaN(a) ? -1 : a.toFixed(1)); }).join(" ");
out += res.name + ": " + disp + "\n";
if (!Array.isArray(res.value)) { // Waw intervals array is not reported to talos
testNames.push(res.name);
testResults.push(res.value);
}
}
this._log("\n" + out);
if (content && content.tpRecordTime) {
content.tpRecordTime(testResults.join(","), 0, testNames.join(","));
} else {
// alert(out);
}
},
_onTestComplete: null,

View File

@ -1,21 +0,0 @@
<?xml version="1.0"?><RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#"><Description about="urn:mozilla:install-manifest">
<!-- Required Items -->
<em:id>bug848358@mozilla.org</em:id>
<em:name>TART - Tab Animation regression Test</em:name>
<em:version>1.6.2</em:version>
<em:bootstrap>true</em:bootstrap>
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>1.5</em:minVersion>
<em:maxVersion>*</em:maxVersion>
</Description>
</em:targetApplication>
<!-- Optional Items -->
<em:creator>Avi Halachmi</em:creator>
<em:description>Bug 848358, bug 956388. To run: navigate to chrome://tart/content/tart.html</em:description>
<em:homepageURL>https://bugzilla.mozilla.org/show_bug.cgi?id=848358</em:homepageURL>
</Description></RDF>

View File

@ -0,0 +1,22 @@
{
"manifest_version": 2,
"name": "TART - Tab Animation regression Test",
"version": "2.0",
"applications": {
"gecko": {
"id": "bug848358@mozilla.org"
}
},
"experiment_apis": {
"tart": {
"schema": "schema.json",
"parent": {
"scopes": ["addon_parent"],
"script": "api.js",
"events": ["startup"]
}
}
}
}

View File

@ -0,0 +1 @@
[]

View File

@ -1,4 +1,4 @@
<html>
<html>
<head>
<meta charset="UTF-8"/>
@ -16,9 +16,14 @@ function $(id) {
// doneCallback will be called once done and, if applicable, with the result as argument.
// Execution might finish quickly (e.g. when setting prefs) or
// take a while (e.g. when triggering the test run)
let _replyId = 1;
function chromeExec(commandName, data, doneCallback) {
// dispatch an event to the framescript which will take it from there.
doneCallback = doneCallback || function dummy() {};
let replyEvent = `tart@mozilla.org:chrome-exec-reply:${_replyId++}`;
if (doneCallback) {
addEventListener(replyEvent, e => { doneCallback(e.detail); },
{once: true});
}
dispatchEvent(
new CustomEvent("tart@mozilla.org:chrome-exec-event", {
bubbles: true,
@ -27,7 +32,7 @@ function chromeExec(commandName, data, doneCallback) {
name: commandName,
data,
},
doneCallback,
replyEvent,
},
})
);
@ -49,6 +54,22 @@ function runTest(config, doneCallback) {
chromeExec("runTest", config, doneCallback);
}
// Returns a Promise that resolves when the test extension is loaded.
function waitForLoad() {
async function tryPing() {
let pingPromise = new Promise(resolve => chromeExec("ping", null, resolve));
let timeoutPromise = new Promise((resolve, reject) => setTimeout(reject, 500));
try {
await Promise.race([pingPromise, timeoutPromise]);
} catch (e) {
return tryPing();
}
return null;
}
return tryPing();
}
function sum(values) {
return values.reduce(function(a, b) { return a + b; });
@ -116,6 +137,15 @@ function doneTest(dispResult) {
// eslint-disable-next-line no-unsanitized/property
$("run-results").innerHTML = "<hr/><br/>Results <button onclick='toClipboard(lastResults)'>[ Copy to clipboard as JSON ]</button>:<br/>" + dispStats + dispResult.join("<br/>");
let testNames = [], testResults = [];
for (let result of JSON.parse(lastResults)) {
if (!Array.isArray(result.value)) {
testNames.push(result.name);
testResults.push(result.value);
}
}
window.tpRecordTime(testResults.join(","), 0, testNames.join(","));
}
}
@ -127,7 +157,9 @@ function triggerStart() {
$("show-during-run").style.display = "block";
$("run-results").innerHTML = "";
runTest(config, doneTest);
waitForLoad().then(() => {
runTest(config, doneTest);
});
}
var defaultConfig = {

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1 +1 @@
% chrome://tart/content/tart.html#auto
% http://localhost/tests/tart/tart.html#auto