mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-07 21:43:24 +00:00
5fc9f15115
Reftest-family test suites can be "run-by-manifest" (reftest-plain, on desktop), or not (all reftest-family suites on Android, crashtest and jsreftest on desktop). When not run-by-manifest, code in reftest.jsm is used to format the suite_start data; when run-by-manifest, code in runreftest.py is used. Currently, the reftest.jsm implementation submits a simple array of test IDs -- no associated manifests -- possibly consistent with the concept that tests are not being run/grouped by manifest. This patch updates the reftest.jsm implementation to generate the same format of suite_start data as the python implementation: An array of dictionaries mapping manifest IDs to arrays of associated test IDs. Differential Revision: https://phabricator.services.mozilla.com/D63875 --HG-- extra : moz-landing-system : lando
300 lines
6.5 KiB
JavaScript
300 lines
6.5 KiB
JavaScript
/* 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";
|
|
|
|
var EXPORTED_SYMBOLS = ["StructuredLogger", "StructuredFormatter"];
|
|
|
|
/**
|
|
* TestLogger: Logger class generating messages compliant with the
|
|
* structured logging protocol for tests exposed by mozlog
|
|
*
|
|
* @param name
|
|
* The name of the logger to instantiate.
|
|
* @param dumpFun
|
|
* An underlying function to be used to log raw messages. This function
|
|
* will receive the complete serialized json string to log.
|
|
* @param mutators
|
|
* An array of functions used to add global context to log messages.
|
|
* These will each be called with the complete object to log as an
|
|
* argument.
|
|
*/
|
|
var StructuredLogger = function(name, dumpFun = dump, mutators = []) {
|
|
this.name = name;
|
|
this._dumpFun = dumpFun;
|
|
this._mutatorFuns = mutators;
|
|
};
|
|
|
|
/**
|
|
* Log functions producing messages in the format specified by mozlog
|
|
*/
|
|
StructuredLogger.prototype = {
|
|
testStart(test) {
|
|
var data = { test: this._testId(test) };
|
|
this._logData("test_start", data);
|
|
},
|
|
|
|
testStatus(
|
|
test,
|
|
subtest,
|
|
status,
|
|
expected = "PASS",
|
|
message = null,
|
|
stack = null,
|
|
extra = null
|
|
) {
|
|
if (subtest === null || subtest === undefined) {
|
|
// Fix for assertions that don't pass in a name
|
|
subtest = "undefined assertion name";
|
|
}
|
|
|
|
var data = {
|
|
test: this._testId(test),
|
|
subtest,
|
|
status,
|
|
};
|
|
|
|
if (expected != status && status != "SKIP") {
|
|
data.expected = expected;
|
|
}
|
|
if (message !== null) {
|
|
data.message = String(message);
|
|
}
|
|
if (stack !== null) {
|
|
data.stack = stack;
|
|
}
|
|
if (extra !== null) {
|
|
data.extra = extra;
|
|
}
|
|
|
|
this._logData("test_status", data);
|
|
},
|
|
|
|
testEnd(
|
|
test,
|
|
status,
|
|
expected = "OK",
|
|
message = null,
|
|
stack = null,
|
|
extra = null
|
|
) {
|
|
var data = { test: this._testId(test), status };
|
|
|
|
if (expected != status && status != "SKIP") {
|
|
data.expected = expected;
|
|
}
|
|
if (message !== null) {
|
|
data.message = String(message);
|
|
}
|
|
if (stack !== null) {
|
|
data.stack = stack;
|
|
}
|
|
if (extra !== null) {
|
|
data.extra = extra;
|
|
}
|
|
|
|
this._logData("test_end", data);
|
|
},
|
|
|
|
assertionCount(test, count, minExpected = 0, maxExpected = 0) {
|
|
var data = {
|
|
test: this._testId(test),
|
|
min_expected: minExpected,
|
|
max_expected: maxExpected,
|
|
count,
|
|
};
|
|
|
|
this._logData("assertion_count", data);
|
|
},
|
|
|
|
suiteStart(
|
|
ids,
|
|
name = null,
|
|
runinfo = null,
|
|
versioninfo = null,
|
|
deviceinfo = null,
|
|
extra = null
|
|
) {
|
|
Object.keys(ids).map(function(manifest) {
|
|
ids[manifest] = ids[manifest].map(x => this._testId(x));
|
|
}, this);
|
|
var data = { tests: ids };
|
|
|
|
if (name !== null) {
|
|
data.name = name;
|
|
}
|
|
|
|
if (runinfo !== null) {
|
|
data.runinfo = runinfo;
|
|
}
|
|
|
|
if (versioninfo !== null) {
|
|
data.versioninfo = versioninfo;
|
|
}
|
|
|
|
if (deviceinfo !== null) {
|
|
data.deviceinfo = deviceinfo;
|
|
}
|
|
|
|
if (extra !== null) {
|
|
data.extra = extra;
|
|
}
|
|
|
|
this._logData("suite_start", data);
|
|
},
|
|
|
|
suiteEnd(extra = null) {
|
|
var data = {};
|
|
|
|
if (extra !== null) {
|
|
data.extra = extra;
|
|
}
|
|
|
|
this._logData("suite_end", data);
|
|
},
|
|
|
|
/**
|
|
* Unstructured logging functions. The "extra" parameter can always by used to
|
|
* log suite specific data. If a "stack" field is provided it is logged at the
|
|
* top level of the data object for the benefit of mozlog's formatters.
|
|
*/
|
|
log(level, message, extra = null) {
|
|
var data = {
|
|
level,
|
|
message: String(message),
|
|
};
|
|
|
|
if (extra !== null) {
|
|
data.extra = extra;
|
|
if ("stack" in extra) {
|
|
data.stack = extra.stack;
|
|
}
|
|
}
|
|
|
|
this._logData("log", data);
|
|
},
|
|
|
|
debug(message, extra = null) {
|
|
this.log("DEBUG", message, extra);
|
|
},
|
|
|
|
info(message, extra = null) {
|
|
this.log("INFO", message, extra);
|
|
},
|
|
|
|
warning(message, extra = null) {
|
|
this.log("WARNING", message, extra);
|
|
},
|
|
|
|
error(message, extra = null) {
|
|
this.log("ERROR", message, extra);
|
|
},
|
|
|
|
critical(message, extra = null) {
|
|
this.log("CRITICAL", message, extra);
|
|
},
|
|
|
|
processOutput(thread, message) {
|
|
this._logData("process_output", {
|
|
message,
|
|
thread,
|
|
});
|
|
},
|
|
|
|
_logData(action, data = {}) {
|
|
var allData = {
|
|
action,
|
|
time: Date.now(),
|
|
thread: null,
|
|
pid: null,
|
|
source: this.name,
|
|
};
|
|
|
|
for (var field in data) {
|
|
allData[field] = data[field];
|
|
}
|
|
|
|
for (var fun of this._mutatorFuns) {
|
|
fun(allData);
|
|
}
|
|
|
|
this._dumpFun(allData);
|
|
},
|
|
|
|
_testId(test) {
|
|
if (Array.isArray(test)) {
|
|
return test.join(" ");
|
|
}
|
|
return test;
|
|
},
|
|
};
|
|
|
|
/**
|
|
* StructuredFormatter: Formatter class turning structured messages
|
|
* into human-readable messages.
|
|
*/
|
|
var StructuredFormatter = function() {
|
|
this.testStartTimes = {};
|
|
};
|
|
|
|
StructuredFormatter.prototype = {
|
|
log(message) {
|
|
return message.message;
|
|
},
|
|
|
|
suite_start(message) {
|
|
this.suiteStartTime = message.time;
|
|
return "SUITE-START | Running " + message.tests.length + " tests";
|
|
},
|
|
|
|
test_start(message) {
|
|
this.testStartTimes[message.test] = new Date().getTime();
|
|
return "TEST-START | " + message.test;
|
|
},
|
|
|
|
test_status(message) {
|
|
var statusInfo =
|
|
message.test +
|
|
" | " +
|
|
message.subtest +
|
|
(message.message ? " | " + message.message : "");
|
|
if (message.expected) {
|
|
return (
|
|
"TEST-UNEXPECTED-" +
|
|
message.status +
|
|
" | " +
|
|
statusInfo +
|
|
" - expected: " +
|
|
message.expected
|
|
);
|
|
}
|
|
return "TEST-" + message.status + " | " + statusInfo;
|
|
},
|
|
|
|
test_end(message) {
|
|
var startTime = this.testStartTimes[message.test];
|
|
delete this.testStartTimes[message.test];
|
|
var statusInfo =
|
|
message.test + (message.message ? " | " + String(message.message) : "");
|
|
var result;
|
|
if (message.expected) {
|
|
result =
|
|
"TEST-UNEXPECTED-" +
|
|
message.status +
|
|
" | " +
|
|
statusInfo +
|
|
" - expected: " +
|
|
message.expected;
|
|
} else {
|
|
return "TEST-" + message.status + " | " + statusInfo;
|
|
}
|
|
result = result + " | took " + message.time - startTime + "ms";
|
|
return result;
|
|
},
|
|
|
|
suite_end(message) {
|
|
return "SUITE-END | took " + message.time - this.suiteStartTime + "ms";
|
|
},
|
|
};
|