Bug 1700392 - [remote] Replace usage of marionette format.js by remote/shared/Format.jsm r=webdriver-reviewers,whimboo

Differential Revision: https://phabricator.services.mozilla.com/D120894
This commit is contained in:
Julian Descottes 2021-07-27 19:03:29 +00:00
parent 2a705bb2e5
commit 056dff5133
19 changed files with 15 additions and 355 deletions

View File

@ -4440,10 +4440,6 @@ pref("services.common.log.logger.tokenserverclient", "Debug");
// case-insensitively.
pref("marionette.log.level", "Info");
// Certain log messages that are known to be long are truncated. This
// preference causes them to not be truncated.
pref("marionette.log.truncate", true);
// Port to start Marionette server on.
pref("marionette.port", 2828);

View File

@ -19,7 +19,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
element: "chrome://remote/content/marionette/element.js",
error: "chrome://remote/content/shared/webdriver/Errors.jsm",
event: "chrome://remote/content/marionette/event.js",
pprint: "chrome://remote/content/marionette/format.js",
pprint: "chrome://remote/content/shared/Format.jsm",
Sleep: "chrome://remote/content/marionette/sync.js",
});

View File

@ -14,7 +14,7 @@ const { XPCOMUtils } = ChromeUtils.import(
XPCOMUtils.defineLazyModuleGetters(this, {
assert: "chrome://remote/content/shared/webdriver/Assert.jsm",
error: "chrome://remote/content/shared/webdriver/Errors.jsm",
pprint: "chrome://remote/content/marionette/format.js",
pprint: "chrome://remote/content/shared/Format.jsm",
});
const IPV4_PORT_EXPR = /:\d+$/;

View File

@ -22,11 +22,12 @@ Marionette is now using the shared Remote logger, please see `remote.log.level`
in the [Remote Agent Preferences] documentation.
`marionette.log.truncate`
`marionette.log.truncate` (deprecated)
-------------------------
Certain log messages that are known to be long, such as wire protocol
dumps, are truncated. This preference causes them not to be truncated.
This preference used to control whether long messages were truncated or not.
Marionette is now using the shared Remote format module, please see `remote.log.truncate`
in the [Remote Agent Preferences] documentation.
`marionette.port`

View File

@ -1,11 +0,0 @@
format module
=============
pprint
------
.. js:autofunction:: pprint
truncate
--------
.. js:autofunction:: truncate

View File

@ -39,7 +39,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
navigate: "chrome://remote/content/marionette/navigate.js",
permissions: "chrome://remote/content/marionette/permissions.js",
PollPromise: "chrome://remote/content/marionette/sync.js",
pprint: "chrome://remote/content/marionette/format.js",
pprint: "chrome://remote/content/shared/Format.jsm",
print: "chrome://remote/content/marionette/print.js",
reftest: "chrome://remote/content/marionette/reftest.js",
registerCommandsActor:

View File

@ -24,7 +24,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
atom: "chrome://remote/content/marionette/atom.js",
error: "chrome://remote/content/shared/webdriver/Errors.jsm",
PollPromise: "chrome://remote/content/marionette/sync.js",
pprint: "chrome://remote/content/marionette/format.js",
pprint: "chrome://remote/content/shared/Format.jsm",
});
XPCOMUtils.defineLazyServiceGetter(

View File

@ -1,196 +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/. */
"use strict";
const EXPORTED_SYMBOLS = ["pprint", "truncate"];
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
XPCOMUtils.defineLazyModuleGetters(this, {
Log: "chrome://remote/content/shared/Log.jsm",
MarionettePrefs: "chrome://remote/content/marionette/prefs.js",
});
XPCOMUtils.defineLazyGetter(this, "logger", () =>
Log.get(Log.TYPES.MARIONETTE)
);
const ELEMENT_NODE = 1;
const MAX_STRING_LENGTH = 250;
/**
* Pretty-print values passed to template strings.
*
* Usage::
*
* const { pprint } = Cu.import(
* "chrome://remote/content/marionette/format.js", {}
* );
*
* let bool = {value: true};
* pprint`Expected boolean, got ${bool}`;
* => 'Expected boolean, got [object Object] {"value": true}'
*
* let htmlElement = document.querySelector("input#foo");
* pprint`Expected element ${htmlElement}`;
* => 'Expected element <input id="foo" class="bar baz" type="input">'
*
* pprint`Current window: ${window}`;
* => '[object Window https://www.mozilla.org/]'
*/
function pprint(ss, ...values) {
function pretty(val) {
let proto = Object.prototype.toString.call(val);
if (
typeof val == "object" &&
val !== null &&
"nodeType" in val &&
val.nodeType === ELEMENT_NODE
) {
return prettyElement(val);
} else if (["[object Window]", "[object ChromeWindow]"].includes(proto)) {
return prettyWindowGlobal(val);
} else if (proto == "[object Attr]") {
return prettyAttr(val);
}
return prettyObject(val);
}
function prettyElement(el) {
let attrs = ["id", "class", "href", "name", "src", "type"];
let idents = "";
for (let attr of attrs) {
if (el.hasAttribute(attr)) {
idents += ` ${attr}="${el.getAttribute(attr)}"`;
}
}
return `<${el.localName}${idents}>`;
}
function prettyWindowGlobal(win) {
let proto = Object.prototype.toString.call(win);
return `[${proto.substring(1, proto.length - 1)} ${win.location}]`;
}
function prettyAttr(obj) {
return `[object Attr ${obj.name}="${obj.value}"]`;
}
function prettyObject(obj) {
let proto = Object.prototype.toString.call(obj);
let s = "";
try {
s = JSON.stringify(obj);
} catch (e) {
if (e instanceof TypeError) {
s = `<${e.message}>`;
} else {
throw e;
}
}
return `${proto} ${s}`;
}
let res = [];
for (let i = 0; i < ss.length; i++) {
res.push(ss[i]);
if (i < values.length) {
let s;
try {
s = pretty(values[i]);
} catch (e) {
logger.warn("Problem pretty printing:", e);
s = typeof values[i];
}
res.push(s);
}
}
return res.join("");
}
this.pprint = pprint;
/**
* Template literal that truncates string values in arbitrary objects.
*
* Given any object, the template will walk the object and truncate
* any strings it comes across to a reasonable limit. This is suitable
* when you have arbitrary data and data integrity is not important.
*
* The strings are truncated in the middle so that the beginning and
* the end is preserved. This will make a long, truncated string look
* like "X <...> Y", where X and Y are half the number of characters
* of the maximum string length from either side of the string.
*
* If the `marionette.log.truncate` preference is false, this
* function acts as a no-op.
*
* Usage::
*
* truncate`Hello ${"x".repeat(260)}!`;
* // Hello xxx ... xxx!
*
* Functions named `toJSON` or `toString` on objects will be called.
*/
function truncate(strings, ...values) {
function walk(obj) {
const typ = Object.prototype.toString.call(obj);
switch (typ) {
case "[object Undefined]":
case "[object Null]":
case "[object Boolean]":
case "[object Number]":
return obj;
case "[object String]":
if (MarionettePrefs.truncateLog) {
if (obj.length > MAX_STRING_LENGTH) {
let s1 = obj.substring(0, MAX_STRING_LENGTH / 2);
let s2 = obj.substring(obj.length - MAX_STRING_LENGTH / 2);
return `${s1} ... ${s2}`;
}
}
return obj;
case "[object Array]":
return obj.map(walk);
// arbitrary object
default:
if (
Object.getOwnPropertyNames(obj).includes("toString") &&
typeof obj.toString == "function"
) {
return walk(obj.toString());
}
let rv = {};
for (let prop in obj) {
rv[prop] = walk(obj[prop]);
}
return rv;
}
}
let res = [];
for (let i = 0; i < strings.length; ++i) {
res.push(strings[i]);
if (i < values.length) {
let obj = walk(values[i]);
let t = Object.prototype.toString.call(obj);
if (t == "[object Array]" || t == "[object Object]") {
res.push(JSON.stringify(obj));
} else {
res.push(obj);
}
}
}
return res.join("");
}
this.truncate = truncate;

View File

@ -19,7 +19,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
error: "chrome://remote/content/shared/webdriver/Errors.jsm",
event: "chrome://remote/content/marionette/event.js",
Log: "chrome://remote/content/shared/Log.jsm",
pprint: "chrome://remote/content/marionette/format.js",
pprint: "chrome://remote/content/shared/Format.jsm",
TimedPromise: "chrome://remote/content/marionette/sync.js",
});

View File

@ -24,7 +24,6 @@ remote.jar:
content/marionette/element.js (element.js)
content/marionette/evaluate.js (evaluate.js)
content/marionette/event.js (event.js)
content/marionette/format.js (format.js)
content/marionette/interaction.js (interaction.js)
content/marionette/l10n.js (l10n.js)
content/marionette/legacyaction.js (legacyaction.js)

View File

@ -13,7 +13,7 @@ const { XPCOMUtils } = ChromeUtils.import(
XPCOMUtils.defineLazyModuleGetters(this, {
assert: "chrome://remote/content/shared/webdriver/Assert.jsm",
error: "chrome://remote/content/shared/webdriver/Errors.jsm",
truncate: "chrome://remote/content/marionette/format.js",
truncate: "chrome://remote/content/shared/Format.jsm",
});
/** Representation of the packets transproted over the wire. */

View File

@ -19,7 +19,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
modal: "chrome://remote/content/marionette/modal.js",
PageLoadStrategy: "chrome://remote/content/shared/webdriver/Capabilities.jsm",
TimedPromise: "chrome://remote/content/marionette/sync.js",
truncate: "chrome://remote/content/marionette/format.js",
truncate: "chrome://remote/content/shared/Format.jsm",
});
XPCOMUtils.defineLazyGetter(this, "logger", () =>

View File

@ -181,17 +181,6 @@ class MarionetteBranch extends Branch {
}
}
/**
* Certain log messages that are known to be long are truncated
* before they are dumped to stdout. The `marionette.log.truncate`
* preference indicates that the values should not be truncated.
*
* @return {boolean}
*/
get truncateLog() {
return this.get("log.truncate");
}
/**
* Gets the `marionette.setpermission.enabled` preference, should
* only be used for testdriver's set_permission API.

View File

@ -1,118 +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/. */
const { pprint, truncate } = ChromeUtils.import(
"chrome://remote/content/marionette/format.js"
);
const MAX_STRING_LENGTH = 250;
const HALF = "x".repeat(MAX_STRING_LENGTH / 2);
add_test(function test_pprint() {
equal('[object Object] {"foo":"bar"}', pprint`${{ foo: "bar" }}`);
equal("[object Number] 42", pprint`${42}`);
equal("[object Boolean] true", pprint`${true}`);
equal("[object Undefined] undefined", pprint`${undefined}`);
equal("[object Null] null", pprint`${null}`);
let complexObj = { toJSON: () => "foo" };
equal('[object Object] "foo"', pprint`${complexObj}`);
let cyclic = {};
cyclic.me = cyclic;
equal("[object Object] <cyclic object value>", pprint`${cyclic}`);
let el = {
hasAttribute: attr => attr in el,
getAttribute: attr => (attr in el ? el[attr] : null),
nodeType: 1,
localName: "input",
id: "foo",
class: "a b",
href: "#",
name: "bar",
src: "s",
type: "t",
};
equal(
'<input id="foo" class="a b" href="#" name="bar" src="s" type="t">',
pprint`${el}`
);
run_next_test();
});
add_test(function test_truncate_empty() {
equal(truncate``, "");
run_next_test();
});
add_test(function test_truncate_noFields() {
equal(truncate`foo bar`, "foo bar");
run_next_test();
});
add_test(function test_truncate_multipleFields() {
equal(truncate`${0}`, "0");
equal(truncate`${1}${2}${3}`, "123");
equal(truncate`a${1}b${2}c${3}`, "a1b2c3");
run_next_test();
});
add_test(function test_truncate_primitiveFields() {
equal(truncate`${123}`, "123");
equal(truncate`${true}`, "true");
equal(truncate`${null}`, "");
equal(truncate`${undefined}`, "");
run_next_test();
});
add_test(function test_truncate_string() {
equal(truncate`${"foo"}`, "foo");
equal(truncate`${"x".repeat(250)}`, "x".repeat(250));
equal(truncate`${"x".repeat(260)}`, `${HALF} ... ${HALF}`);
run_next_test();
});
add_test(function test_truncate_array() {
equal(truncate`${["foo"]}`, JSON.stringify(["foo"]));
equal(truncate`${"foo"} ${["bar"]}`, `foo ${JSON.stringify(["bar"])}`);
equal(
truncate`${["x".repeat(260)]}`,
JSON.stringify([`${HALF} ... ${HALF}`])
);
run_next_test();
});
add_test(function test_truncate_object() {
equal(truncate`${{}}`, JSON.stringify({}));
equal(truncate`${{ foo: "bar" }}`, JSON.stringify({ foo: "bar" }));
equal(
truncate`${{ foo: "x".repeat(260) }}`,
JSON.stringify({ foo: `${HALF} ... ${HALF}` })
);
equal(truncate`${{ foo: ["bar"] }}`, JSON.stringify({ foo: ["bar"] }));
equal(
truncate`${{ foo: ["bar", { baz: 42 }] }}`,
JSON.stringify({ foo: ["bar", { baz: 42 }] })
);
let complex = {
toString() {
return "hello world";
},
};
equal(truncate`${complex}`, "hello world");
let longComplex = {
toString() {
return "x".repeat(260);
},
};
equal(truncate`${longComplex}`, `${HALF} ... ${HALF}`);
run_next_test();
});

View File

@ -13,7 +13,6 @@ skip-if = appname == "thunderbird"
[test_dom.js]
[test_element.js]
[test_evaluate.js]
[test_format.js]
[test_message.js]
[test_modal.js]
[test_navigate.js]

View File

@ -20,6 +20,7 @@ XPCOMUtils.defineLazyGetter(this, "logger", () => Log.get());
const ELEMENT_NODE = 1;
const MAX_STRING_LENGTH = 250;
const PREF_TRUNCATE = "remote.log.truncate";
/**

View File

@ -13,7 +13,7 @@ const { XPCOMUtils } = ChromeUtils.import(
XPCOMUtils.defineLazyModuleGetters(this, {
AppInfo: "chrome://remote/content/marionette/appinfo.js",
error: "chrome://remote/content/shared/webdriver/Errors.jsm",
pprint: "chrome://remote/content/marionette/format.js",
pprint: "chrome://remote/content/shared/Format.jsm",
});
/**

View File

@ -23,7 +23,7 @@ XPCOMUtils.defineLazyModuleGetters(this, {
AppInfo: "chrome://remote/content/marionette/appinfo.js",
assert: "chrome://remote/content/shared/webdriver/Assert.jsm",
error: "chrome://remote/content/shared/webdriver/Errors.jsm",
pprint: "chrome://remote/content/marionette/format.js",
pprint: "chrome://remote/content/shared/Format.jsm",
RemoteAgent: "chrome://remote/content/components/RemoteAgent.jsm",
});

View File

@ -11,7 +11,7 @@ const { XPCOMUtils } = ChromeUtils.import(
);
XPCOMUtils.defineLazyModuleGetters(this, {
pprint: "chrome://remote/content/marionette/format.js",
pprint: "chrome://remote/content/shared/Format.jsm",
});
const ERRORS = new Set([