1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 * TestLogger: Logger class generating messages compliant with the
7 * structured logging protocol for tests exposed by mozlog
10 * The name of the logger to instantiate.
11 * @param {function} [dumpFun]
12 * An underlying function to be used to log raw messages. This function
13 * will receive the complete serialized json string to log.
14 * @param {object} [scope]
15 * The scope that the dumpFun is loaded in, so that messages are cloned
16 * into that scope before passing them.
18 export class StructuredLogger {
23 constructor(name, dumpFun = dump, scope = null) {
25 this.#dumpFun = dumpFun;
26 this.#dumpScope = scope;
30 var data = { test: this.#testId(test) };
31 this.logData("test_start", data);
43 if (subtest === null || subtest === undefined) {
44 // Fix for assertions that don't pass in a name
45 subtest = "undefined assertion name";
49 test: this.#testId(test),
54 // handle case: known fail
55 if (expected === status && status != "SKIP") {
58 if (expected != status && status != "SKIP") {
59 data.expected = expected;
61 if (message !== null) {
62 data.message = String(message);
71 this.logData("test_status", data);
82 var data = { test: this.#testId(test), status };
84 // handle case: known fail
85 if (expected === status && status != "SKIP") {
88 if (expected != status && status != "SKIP") {
89 data.expected = expected;
91 if (message !== null) {
92 data.message = String(message);
101 this.logData("test_end", data);
104 assertionCount(test, count, minExpected = 0, maxExpected = 0) {
106 test: this.#testId(test),
107 min_expected: minExpected,
108 max_expected: maxExpected,
112 this.logData("assertion_count", data);
123 Object.keys(ids).map(function (manifest) {
124 ids[manifest] = ids[manifest].map(x => this.#testId(x));
126 var data = { tests: ids };
132 if (runinfo !== null) {
133 data.runinfo = runinfo;
136 if (versioninfo !== null) {
137 data.versioninfo = versioninfo;
140 if (deviceinfo !== null) {
141 data.deviceinfo = deviceinfo;
144 if (extra !== null) {
148 this.logData("suite_start", data);
151 suiteEnd(extra = null) {
154 if (extra !== null) {
158 this.logData("suite_end", data);
162 * Unstructured logging functions. The "extra" parameter can always by used to
163 * log suite specific data. If a "stack" field is provided it is logged at the
164 * top level of the data object for the benefit of mozlog's formatters.
166 log(level, message, extra = null) {
169 message: String(message),
172 if (extra !== null) {
174 if ("stack" in extra) {
175 data.stack = extra.stack;
179 this.logData("log", data);
182 debug(message, extra = null) {
183 this.log("DEBUG", message, extra);
186 info(message, extra = null) {
187 this.log("INFO", message, extra);
190 warning(message, extra = null) {
191 this.log("WARNING", message, extra);
194 error(message, extra = null) {
195 this.log("ERROR", message, extra);
198 critical(message, extra = null) {
199 this.log("CRITICAL", message, extra);
202 processOutput(thread, message) {
203 this.logData("process_output", {
209 logData(action, data = {}) {
218 for (var field in data) {
219 allData[field] = data[field];
222 if (this.#dumpScope) {
223 this.#dumpFun(Cu.cloneInto(allData, this.#dumpScope));
225 this.#dumpFun(allData);
230 if (Array.isArray(test)) {
231 return test.join(" ");
238 * StructuredFormatter: Formatter class turning structured messages
239 * into human-readable messages.
241 export class StructuredFormatter {
242 // The time at which the whole suite of tests started.
243 #suiteStartTime = null;
245 #testStartTimes = new Map();
248 return message.message;
251 suite_start(message) {
252 this.#suiteStartTime = message.time;
253 return "SUITE-START | Running " + message.tests.length + " tests";
256 test_start(message) {
257 this.#testStartTimes.set(message.test, new Date().getTime());
258 return "TEST-START | " + message.test;
261 test_status(message) {
266 (message.message ? " | " + message.message : "");
267 if (message.expected) {
277 return "TEST-" + message.status + " | " + statusInfo;
281 var startTime = this.#testStartTimes.get(message.test);
282 this.#testStartTimes.delete(message.test);
284 message.test + (message.message ? " | " + String(message.message) : "");
286 if (message.expected) {
295 return "TEST-" + message.status + " | " + statusInfo;
297 result = result + " | took " + message.time - startTime + "ms";
302 return "SUITE-END | took " + message.time - this.#suiteStartTime + "ms";