Files
roytam1 2e02aab9a7 import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1198458: Webrtc updated to branch 43; pull made 2015-09-29 09:00AM PDT rs=jesup (c45a789c99)
- Bug 1159489: WebRTC bitrate limits for video depend on input resolution and framerate r=pkerr (e3691a247c)
- Bug 1132318: merge SelectSendFrameRate with SelectSendResolution r=bwc (bcc232994c)
- Bug 1182289: Clean up dispatches in WebrtcGmpVideoEncoder/Decoder. r=jesup, a=abillings (b5e2030b07)
- Bug 1167306: Fix preprocessor goof that disabled the load manager and some preference handling. r=jesup (0cc0dee688)
- Bug 1198458: Rollup of changes previously applied to media/webrtc/trunk/webrtc and fixes to those rs=jesup r=froyd,jib,bwc,jesup,gcp,sotaro,pkerr,pehrsons (fe384d5e63)
- Bug 1198458 Unbreak build on BSDs by fixing non-POSIX thread includes/usage. r=jesup (4ad8e88c17)
- Bug 1198458: Fix typo in merges in OMX rs=bustage,kwierso on a CLOSED TREE (211b3b1a3f)
- Bug 1226146: fix sndio audio_device backend after webrtc 43 landing in bug 1198458 r=jesup NPOTB (2b10ba3e86)
- Bug 1231106 - Make BSDs fall-through to ASSERT as well. r=jesup (775d4fedae)
- Bug 1231109 - Drop FreeBSD checks for unsupported versions. r=jld r=jesup (3cd55166fd)
- Bug 1161079: Fix VideoCodecStats to allow for collecting encoder and decoder stats r=jib (1f98af8939)
- add limits to fix gcc12 compile (d78098980f)
- Bug 1193495 - Part 1: Test case. r=mt (add2ded009)
- Bug 1193495 - Part 2: Maintain clones of supported codecs for each level, and do necessary checking to prevent payload-type clashes. r=mt (d45a24dba7)
- Bug 1191301 - Re-enable the use of media.navigator.video.use_tmmbr pref. r=bwc (d2723821d4)
- Bug 1094447 - Use UDP/TLS/RTP/SAVPF for audio/video m-lines. r=drno (e8e1dafd0a)
- Bug 1173599 - a=imageattr support. r=mt (612fc343d7)
- Bug 1173601 - Add a=simulcast support. r=mt (7c5303bacb)
- Bug 1203246 - Factor track negotiation stuff out of JsepSessionImpl, and other simplification. r=mt (b71c809b78)
- Bug 1212907 - a=rid support. r=mt (7479ab6984)
- Bug 1212908 - Update a=simulcast to match new grammar in 03 draft. r=mt (e205d3b0dd)
- Bug 1192390 - Part 1: Lay architectural groundwork for simulcast negotiation. r=mt r=jesup (e75dda3139)
- Bug 1223160 - added SDP parser file reader. r=bwc (6752195791)
- Bug 1192390 - Part 2: Simulcast and RID negotiation. r=mt (51b151ef52)
- fix some warnings stuff (fed8f513a8)
- Bug 1161317: Fix bug where sendonly video RTCP would be treated as outgoing RTP r=jesup (e24371fbe0)
- Bug 1226347: Import cherry-pick of AEC changes from 43->48 (delay-agnostic AEC). r=pkerr (d3a074f4d8)
- Bug 1226347 - Part 2: Allow control of AEC via prefs. r=rjesup (58f142005b)
- Bug 1228788 - Force QT device release to happen on the main thread. r=jesup (885e9d1236)
- Bug 1162218 - Make worker idle thread timeouts more strict, r=baku. (a7d2106987)
- No bug. Remove a stray debugging printf of mine. r=me. (77b84cda62)
- minor (22564a666e)
- Bug 1224237 - Remove the !baseURL check from ServiceWorkerContainer::Register;r=bkelly (8b13c4dc49)
- Bug 1196157 - Marks left by performance marks should print the domain of the application and not the complete URL. r=baku (d133708d8d)
- Bug 1211970 - "Muted errors in workers are not correctly reported to the console". r=bz (42c15275f4)
- Bug 1208559 - Tests. r=bholley (e16a30caa5)
-  Bug 1045891 - Tests for child-src r=ckerschb (90aa832cd0)
- Bug 1223647: CSP erroneously inherited into dedicated workers. r=ckerschb (6fd8d9bfc9)
- Bug 1218433 - Use AsyncOpen2 in dom/workers/ScriptLoader.cpp - part 1, r=sicking (a7e9187e52)
- Bug 1218433 - Use AsyncOpen2 in dom/workers/ScriptLoader.cpp - part 3 - WPT, r=sicking, r=Ms2ger (e5e3c69f6a)
- Bug 1218433 - Use AsyncOpen2 in dom/workers/ScriptLoader.cpp - part 2 - WPT, r=sicking, r=Ms2ger (1dd2d871ec)
- Bug 1211967 - Fix how we report errors when loading a worker from a data url, r=bz (8517368daa)
- nsRefPtr - RefPtr (34bb404530)
- Bug 1231055 - Fix tags usage in PluginProvider. r=dtownsend (870b0e71eb)
- bug 1228792 - remove use of array comprehensions r=mossop (3e31f18e83)
- bug 1228792 - use standard version of catch r=mossop (f306557ca2)
- Bug 1228009. Geolocation code needs to handle failures on its ErrorResults. r=smaug (8778a9e264)
- Bug 1228707. Add a away to call Web IDL callbacks while ignoring any errors from them, and use it in a few places. r=smaug (a414e0d711)
- Bug 1201692. Add a fast path to ExplicitChildIterator::Seek for the common case of seeking an actual DOM child of the parent node. r=wchen (01234ad43a)
- Bug 1202186 - use nsISensitiveInfoHidden for console methods, r=baku (888b4506ad)
- Bug 1223774 - Console API should check if the outer window exists, r=smaug (e0d7f408dc)
- Bug 1200551 - Handle multiple %c formatters without a string between them by using only the last one for styling;r=baku,r=past (463550117a)
- Bug 1213719 - Back out bug 1170314 for duplicate functionality. r=smaug (ae74e0ad52)
- Bug 1154076 followup: Mark ConsoleRunnable::Run() as override. rs=ehsan (337181faab)
- Bug 1127703 - "Support iteration on FormData" r=bz (4ddd461e99)
- Bug 1230509 - BlobImplFile should return false in IsDateUnknown and IsSizeUnknown, r=bz (1079bfe2ab)
- Bug 1198095 - FileReader should dispatch an error if the blob changes size in the meantime the read is executed, r=bz (263993a172)
- Bug 1231094 - patch 1 - nsDOMFileReader to mozilla::dom::FileReader, r=sicking (aa8c3ff373)
- Bug 1231094 - patch 2 - Get rid of FileIOObject, r=sicking (44af1e17dd)
- Bug 1231100 - Get rid of nsIDOMFileReader - patch 1, r=sicking (c909d9d793)
- Bug 1231100 - Get rid of nsIDOMFileReader - patch 2, r=sicking (4d3da1c566)
- Bug 1161183: Don't show the add-on version in the list view. r=dao (002d8f6fb1)
- Bug 1229519: Fix toolkit/modules to pass eslint checks. r=mak (8bbd9c8fe0)
2023-04-06 15:48:27 +08:00

593 lines
22 KiB
JavaScript

/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const {utils: Cu} = Components;
Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource://gre/modules/osfile.jsm");
Cu.import("resource://gre/modules/Promise.jsm")
Cu.import("resource://gre/modules/Log.jsm");
var testFormatter = {
format: function format(message) {
return message.loggerName + "\t" +
message.levelDesc + "\t" +
message.message;
}
};
function MockAppender(formatter) {
Log.Appender.call(this, formatter);
this.messages = [];
}
MockAppender.prototype = {
__proto__: Log.Appender.prototype,
doAppend: function DApp_doAppend(message) {
this.messages.push(message);
}
};
function run_test() {
run_next_test();
}
add_task(function test_Logger() {
let log = Log.repository.getLogger("test.logger");
let appender = new MockAppender(new Log.BasicFormatter());
log.level = Log.Level.Debug;
appender.level = Log.Level.Info;
log.addAppender(appender);
log.info("info test");
log.debug("this should be logged but not appended.");
do_check_eq(appender.messages.length, 1);
let msgRe = /\d+\ttest.logger\t\INFO\tinfo test/;
do_check_true(msgRe.test(appender.messages[0]));
});
add_task(function test_Logger_parent() {
// Check whether parenting is correct
let grandparentLog = Log.repository.getLogger("grandparent");
let childLog = Log.repository.getLogger("grandparent.parent.child");
do_check_eq(childLog.parent.name, "grandparent");
let parentLog = Log.repository.getLogger("grandparent.parent");
do_check_eq(childLog.parent.name, "grandparent.parent");
// Check that appends are exactly in scope
let gpAppender = new MockAppender(new Log.BasicFormatter());
gpAppender.level = Log.Level.Info;
grandparentLog.addAppender(gpAppender);
childLog.info("child info test");
Log.repository.rootLogger.info("this shouldn't show up in gpAppender");
do_check_eq(gpAppender.messages.length, 1);
do_check_true(gpAppender.messages[0].indexOf("child info test") > 0);
});
add_test(function test_LoggerWithMessagePrefix() {
let log = Log.repository.getLogger("test.logger.prefix");
let appender = new MockAppender(new Log.MessageOnlyFormatter());
log.addAppender(appender);
let prefixed = Log.repository.getLoggerWithMessagePrefix(
"test.logger.prefix", "prefix: ");
log.warn("no prefix");
prefixed.warn("with prefix");
Assert.equal(appender.messages.length, 2, "2 messages were logged.");
Assert.deepEqual(appender.messages, [
"no prefix",
"prefix: with prefix",
], "Prefix logger works.");
run_next_test();
});
/*
* A utility method for checking object equivalence.
* Fields with a reqular expression value in expected will be tested
* against the corresponding value in actual. Otherwise objects
* are expected to have the same keys and equal values.
*/
function checkObjects(expected, actual) {
do_check_true(expected instanceof Object);
do_check_true(actual instanceof Object);
for (let key in expected) {
do_check_neq(actual[key], undefined);
if (expected[key] instanceof RegExp) {
do_check_true(expected[key].test(actual[key].toString()));
} else {
if (expected[key] instanceof Object) {
checkObjects(expected[key], actual[key]);
} else {
do_check_eq(expected[key], actual[key]);
}
}
}
for (let key in actual) {
do_check_neq(expected[key], undefined);
}
}
add_task(function test_StructuredLogCommands() {
let appender = new MockAppender(new Log.StructuredFormatter());
let logger = Log.repository.getLogger("test.StructuredOutput");
logger.addAppender(appender);
logger.level = Log.Level.Info;
logger.logStructured("test_message", {_message: "message string one"});
logger.logStructured("test_message", {_message: "message string two",
_level: "ERROR",
source_file: "test_Log.js"});
logger.logStructured("test_message");
logger.logStructured("test_message", {source_file: "test_Log.js",
message_position: 4});
let messageOne = {"_time": /\d+/,
"_namespace": "test.StructuredOutput",
"_level": "INFO",
"_message": "message string one",
"action": "test_message"};
let messageTwo = {"_time": /\d+/,
"_namespace": "test.StructuredOutput",
"_level": "ERROR",
"_message": "message string two",
"action": "test_message",
"source_file": "test_Log.js"};
let messageThree = {"_time": /\d+/,
"_namespace": "test.StructuredOutput",
"_level": "INFO",
"action": "test_message"};
let messageFour = {"_time": /\d+/,
"_namespace": "test.StructuredOutput",
"_level": "INFO",
"action": "test_message",
"source_file": "test_Log.js",
"message_position": 4};
checkObjects(messageOne, JSON.parse(appender.messages[0]));
checkObjects(messageTwo, JSON.parse(appender.messages[1]));
checkObjects(messageThree, JSON.parse(appender.messages[2]));
checkObjects(messageFour, JSON.parse(appender.messages[3]));
let errored = false;
try {
logger.logStructured("", {_message: "invalid message"});
} catch (e) {
errored = true;
do_check_eq(e, "An action is required when logging a structured message.");
} finally {
do_check_true(errored);
}
errored = false;
try {
logger.logStructured("message_action", "invalid params");
} catch (e) {
errored = true;
do_check_eq(e, "The params argument is required to be an object.");
} finally {
do_check_true(errored);
}
// Logging with unstructured interface should produce the same messages
// as the structured interface for these cases.
appender = new MockAppender(new Log.StructuredFormatter());
logger = Log.repository.getLogger("test.StructuredOutput1");
messageOne._namespace = "test.StructuredOutput1";
messageTwo._namespace = "test.StructuredOutput1";
logger.addAppender(appender);
logger.level = Log.Level.All;
logger.info("message string one", {action: "test_message"});
logger.error("message string two", {action: "test_message",
source_file: "test_Log.js"});
checkObjects(messageOne, JSON.parse(appender.messages[0]));
checkObjects(messageTwo, JSON.parse(appender.messages[1]));
});
add_task(function test_StorageStreamAppender() {
let appender = new Log.StorageStreamAppender(testFormatter);
do_check_eq(appender.getInputStream(), null);
// Log to the storage stream and verify the log was written and can be
// read back.
let logger = Log.repository.getLogger("test.StorageStreamAppender");
logger.addAppender(appender);
logger.info("OHAI");
let inputStream = appender.getInputStream();
let data = NetUtil.readInputStreamToString(inputStream,
inputStream.available());
do_check_eq(data, "test.StorageStreamAppender\tINFO\tOHAI\n");
// We can read it again even.
let sndInputStream = appender.getInputStream();
let sameData = NetUtil.readInputStreamToString(sndInputStream,
sndInputStream.available());
do_check_eq(data, sameData);
// Reset the appender and log some more.
appender.reset();
do_check_eq(appender.getInputStream(), null);
logger.debug("wut?!?");
inputStream = appender.getInputStream();
data = NetUtil.readInputStreamToString(inputStream,
inputStream.available());
do_check_eq(data, "test.StorageStreamAppender\tDEBUG\twut?!?\n");
});
function fileContents(path) {
let decoder = new TextDecoder();
return OS.File.read(path).then(array => {
return decoder.decode(array);
});
}
add_task(function* test_FileAppender() {
// This directory does not exist yet
let dir = OS.Path.join(do_get_profile().path, "test_Log");
do_check_false(yield OS.File.exists(dir));
let path = OS.Path.join(dir, "test_FileAppender");
let appender = new Log.FileAppender(path, testFormatter);
let logger = Log.repository.getLogger("test.FileAppender");
logger.addAppender(appender);
// Logging to a file that can't be created won't do harm.
do_check_false(yield OS.File.exists(path));
logger.info("OHAI!");
yield OS.File.makeDir(dir);
logger.info("OHAI");
yield appender._lastWritePromise;
do_check_eq((yield fileContents(path)),
"test.FileAppender\tINFO\tOHAI\n");
logger.info("OHAI");
yield appender._lastWritePromise;
do_check_eq((yield fileContents(path)),
"test.FileAppender\tINFO\tOHAI\n" +
"test.FileAppender\tINFO\tOHAI\n");
// Reset the appender and log some more.
yield appender.reset();
do_check_false(yield OS.File.exists(path));
logger.debug("O RLY?!?");
yield appender._lastWritePromise;
do_check_eq((yield fileContents(path)),
"test.FileAppender\tDEBUG\tO RLY?!?\n");
yield appender.reset();
logger.debug("1");
logger.info("2");
logger.info("3");
logger.info("4");
logger.info("5");
// Waiting on only the last promise should account for all of these.
yield appender._lastWritePromise;
// Messages ought to be logged in order.
do_check_eq((yield fileContents(path)),
"test.FileAppender\tDEBUG\t1\n" +
"test.FileAppender\tINFO\t2\n" +
"test.FileAppender\tINFO\t3\n" +
"test.FileAppender\tINFO\t4\n" +
"test.FileAppender\tINFO\t5\n");
});
add_task(function* test_BoundedFileAppender() {
let dir = OS.Path.join(do_get_profile().path, "test_Log");
if (!(yield OS.File.exists(dir))) {
yield OS.File.makeDir(dir);
}
let path = OS.Path.join(dir, "test_BoundedFileAppender");
// This appender will hold about two lines at a time.
let appender = new Log.BoundedFileAppender(path, testFormatter, 40);
let logger = Log.repository.getLogger("test.BoundedFileAppender");
logger.addAppender(appender);
logger.info("ONE");
logger.info("TWO");
yield appender._lastWritePromise;
do_check_eq((yield fileContents(path)),
"test.BoundedFileAppender\tINFO\tONE\n" +
"test.BoundedFileAppender\tINFO\tTWO\n");
logger.info("THREE");
logger.info("FOUR");
do_check_neq(appender._removeFilePromise, undefined);
yield appender._removeFilePromise;
yield appender._lastWritePromise;
do_check_eq((yield fileContents(path)),
"test.BoundedFileAppender\tINFO\tTHREE\n" +
"test.BoundedFileAppender\tINFO\tFOUR\n");
yield appender.reset();
logger.info("ONE");
logger.info("TWO");
logger.info("THREE");
logger.info("FOUR");
do_check_neq(appender._removeFilePromise, undefined);
yield appender._removeFilePromise;
yield appender._lastWritePromise;
do_check_eq((yield fileContents(path)),
"test.BoundedFileAppender\tINFO\tTHREE\n" +
"test.BoundedFileAppender\tINFO\tFOUR\n");
});
/*
* Test parameter formatting.
*/
add_task(function* log_message_with_params() {
let formatter = new Log.BasicFormatter();
function formatMessage(text, params) {
let full = formatter.format(new Log.LogMessage("test.logger", Log.Level.Warn, text, params));
return full.split("\t")[3];
}
// Strings are substituted directly.
do_check_eq(formatMessage("String is ${foo}", {foo: "bar"}),
"String is bar");
// Numbers are substituted.
do_check_eq(formatMessage("Number is ${number}", {number: 47}),
"Number is 47")
// The entire params object is JSON-formatted and substituted.
do_check_eq(formatMessage("Object is ${}", {foo: "bar"}),
'Object is {"foo":"bar"}');
// An object nested inside params is JSON-formatted and substituted.
do_check_eq(formatMessage("Sub object is ${sub}", {sub: {foo: "bar"}}),
'Sub object is {"foo":"bar"}');
// The substitution field is missing from params. Leave the placeholder behind
// to make the mistake obvious.
do_check_eq(formatMessage("Missing object is ${missing}", {}),
'Missing object is ${missing}');
// Make sure we don't treat the parameter name 'false' as a falsey value.
do_check_eq(formatMessage("False is ${false}", {false: true}),
'False is true');
// If an object has a .toJSON method, the formatter uses it.
let ob = function() {};
ob.toJSON = function() {return {sneaky: "value"}};
do_check_eq(formatMessage("JSON is ${sub}", {sub: ob}),
'JSON is {"sneaky":"value"}');
// Fall back to .toSource() if JSON.stringify() fails on an object.
ob = function() {};
ob.toJSON = function() {throw "oh noes JSON"};
do_check_eq(formatMessage("Fail is ${sub}", {sub: ob}),
'Fail is (function () {})');
// Fall back to .toString if both .toJSON and .toSource fail.
ob.toSource = function() {throw "oh noes SOURCE"};
do_check_eq(formatMessage("Fail is ${sub}", {sub: ob}),
'Fail is function () {}');
// Fall back to '[object]' if .toJSON, .toSource and .toString fail.
ob.toString = function() {throw "oh noes STRING"};
do_check_eq(formatMessage("Fail is ${sub}", {sub: ob}),
'Fail is [object]');
// If params are passed but there are no substitution in the text
// we JSON format and append the entire parameters object.
do_check_eq(formatMessage("Text with no subs", {a: "b", c: "d"}),
'Text with no subs: {"a":"b","c":"d"}');
// If we substitute one parameter but not the other,
// we ignore any params that aren't substituted.
do_check_eq(formatMessage("Text with partial sub ${a}", {a: "b", c: "d"}),
'Text with partial sub b');
// We don't format internal fields stored in params.
do_check_eq(formatMessage("Params with _ ${}", {a: "b", _c: "d", _level:20, _message:"froo",
_time:123456, _namespace:"here.there"}),
'Params with _ {"a":"b","_c":"d"}');
// Don't print an empty params holder if all params are internal.
do_check_eq(formatMessage("All params internal", {_level:20, _message:"froo",
_time:123456, _namespace:"here.there"}),
'All params internal');
// Format params with null and undefined values.
do_check_eq(formatMessage("Null ${n} undefined ${u}", {n: null, u: undefined}),
'Null null undefined undefined');
// Format params with number, bool, and Object/String type.
do_check_eq(formatMessage("number ${n} boolean ${b} boxed Boolean ${bx} String ${s}",
{n: 45, b: false, bx: new Boolean(true), s: new String("whatevs")}),
'number 45 boolean false boxed Boolean true String whatevs');
/*
* Check that errors get special formatting if they're formatted directly as
* a named param or they're the only param, but not if they're a field in a
* larger structure.
*/
let err = Components.Exception("test exception", Components.results.NS_ERROR_FAILURE);
let str = formatMessage("Exception is ${}", err);
do_check_true(str.includes('Exception is [Exception... "test exception"'));
do_check_true(str.includes("(NS_ERROR_FAILURE)"));
str = formatMessage("Exception is", err);
do_check_true(str.includes('Exception is: [Exception... "test exception"'));
str = formatMessage("Exception is ${error}", {error: err});
do_check_true(str.includes('Exception is [Exception... "test exception"'));
str = formatMessage("Exception is", {_error: err});
do_print(str);
// Exceptions buried inside objects are formatted badly.
do_check_true(str.includes('Exception is: {"_error":{}'));
// If the message text is null, the message contains only the formatted params object.
str = formatMessage(null, err);
do_check_true(str.startsWith('[Exception... "test exception"'));
// If the text is null and 'params' is a String object, the message is exactly that string.
str = formatMessage(null, new String("String in place of params"));
do_check_eq(str, "String in place of params");
// We use object.valueOf() internally; make sure a broken valueOf() method
// doesn't cause the logger to fail.
let vOf = {a: 1, valueOf: function() {throw "oh noes valueOf"}};
do_check_eq(formatMessage("Broken valueOf ${}", vOf),
'Broken valueOf ({a:1, valueOf:(function () {throw "oh noes valueOf"})})');
// Test edge cases of bad data to formatter:
// If 'params' is not an object, format it as a basic type.
do_check_eq(formatMessage("non-object no subst", 1),
'non-object no subst: 1');
do_check_eq(formatMessage("non-object all subst ${}", 2),
'non-object all subst 2');
do_check_eq(formatMessage("false no subst", false),
'false no subst: false');
do_check_eq(formatMessage("null no subst", null),
'null no subst: null');
// If 'params' is undefined and there are no substitutions expected,
// the message should still be output.
do_check_eq(formatMessage("undefined no subst", undefined),
'undefined no subst');
// If 'params' is not an object, no named substitutions can succeed;
// therefore we leave the placeholder and append the formatted params.
do_check_eq(formatMessage("non-object named subst ${junk} space", 3),
'non-object named subst ${junk} space: 3');
// If there are no params, we leave behind the placeholders in the text.
do_check_eq(formatMessage("no params ${missing}", undefined),
'no params ${missing}');
// If params doesn't contain any of the tags requested in the text,
// we leave them all behind and append the formatted params.
do_check_eq(formatMessage("object missing tag ${missing} space", {mising: "not here"}),
'object missing tag ${missing} space: {"mising":"not here"}');
// If we are given null text and no params, the resulting formatted message is empty.
do_check_eq(formatMessage(null), '');
});
/*
* If we call a log function with a non-string object in place of the text
* argument, and no parameters, treat that the same as logging empty text
* with the object argument as parameters. This makes the log useful when the
* caller does "catch(err) {logger.error(err)}"
*/
add_task(function* test_log_err_only() {
let log = Log.repository.getLogger("error.only");
let testFormatter = { format: msg => msg };
let appender = new MockAppender(testFormatter);
log.addAppender(appender);
/*
* Check that log.error(err) is treated the same as
* log.error(null, err) by the logMessage constructor; the formatMessage()
* tests above ensure that the combination of null text and an error object
* is formatted correctly.
*/
try {
eval("javascript syntax error");
}
catch (e) {
log.error(e);
msg = appender.messages.pop();
do_check_eq(msg.message, null);
do_check_eq(msg.params, e);
}
});
/*
* Test logStructured() messages through basic formatter.
*/
add_task(function* test_structured_basic() {
let log = Log.repository.getLogger("test.logger");
let appender = new MockAppender(new Log.BasicFormatter());
log.level = Log.Level.Info;
appender.level = Log.Level.Info;
log.addAppender(appender);
// A structured entry with no _message is treated the same as log./level/(null, params)
// except the 'action' field is added to the object.
log.logStructured("action", {data: "structure"});
do_check_eq(appender.messages.length, 1);
do_check_true(appender.messages[0].includes('{"data":"structure","action":"action"}'));
// A structured entry with _message and substitution is treated the same as
// log./level/(null, params).
log.logStructured("action", {_message: "Structured sub ${data}", data: "structure"});
do_check_eq(appender.messages.length, 2);
do_print(appender.messages[1]);
do_check_true(appender.messages[1].includes('Structured sub structure'));
});
/*
* Test that all the basic logger methods pass the message and params through to the appender.
*/
add_task(function* log_message_with_params() {
let log = Log.repository.getLogger("error.logger");
let testFormatter = { format: msg => msg };
let appender = new MockAppender(testFormatter);
log.addAppender(appender);
let testParams = {a:1, b:2};
log.fatal("Test fatal", testParams);
log.error("Test error", testParams);
log.warn("Test warn", testParams);
log.info("Test info", testParams);
log.config("Test config", testParams);
log.debug("Test debug", testParams);
log.trace("Test trace", testParams);
do_check_eq(appender.messages.length, 7);
for (let msg of appender.messages) {
do_check_true(msg.params === testParams);
do_check_true(msg.message.startsWith("Test "));
}
});
/*
* Check that we format JS Errors reasonably.
*/
add_task(function* format_errors() {
let pFormat = new Log.ParameterFormatter();
// Test that subclasses of Error are recognized as errors.
err = new ReferenceError("Ref Error", "ERROR_FILE", 28);
str = pFormat.format(err);
do_check_true(str.includes("ReferenceError"));
do_check_true(str.includes("ERROR_FILE:28"));
do_check_true(str.includes("Ref Error"));
// Test that JS-generated Errors are recognized and formatted.
try {
yield Promise.resolve(); // Scrambles the stack
eval("javascript syntax error");
}
catch (e) {
str = pFormat.format(e);
do_check_true(str.includes("SyntaxError: missing ;"));
// Make sure we identified it as an Error and formatted the error location as
// lineNumber:columnNumber.
do_check_true(str.includes(":1:11)"));
// Make sure that we use human-readable stack traces
// Check that the error doesn't contain any reference to "Promise.jsm" or "Task.jsm"
do_check_false(str.includes("Promise.jsm"));
do_check_false(str.includes("Task.jsm"));
do_check_true(str.includes("format_errors"));
}
});