Files
meteor/packages/logging/logging_test.js
2025-02-13 07:39:45 -03:00

418 lines
11 KiB
JavaScript

import { Log } from "meteor/logging";
import { Meteor } from "meteor/meteor";
Tinytest.add("logging - _getCallerDetails", function (test) {
const details = Log._getCallerDetails();
// Ignore this test for Opera, IE, Safari since this test would work only
// in Chrome and Firefox, other browsers don't give us an ability to get
// stacktrace.
if (new Error().stack) {
if (Meteor.isServer) {
test.equal(details.file, "tinytest.js");
} else {
// Note that we want this to work in --production too, so we need to allow
// for the minified filename.
test.matches(details.file, /^(?:tinytest\.js|[a-f0-9]{40}\.js)$/);
}
// evaled statements shouldn't crash
const code = "Log._getCallerDetails().file";
// Note that we want this to work in --production too, so we need to allow
// for the minified filename
test.matches(
eval(code),
/^(?:eval|local-test_logging\.js|[a-f0-9]{40}\.js)/
);
}
});
Tinytest.add("logging - log", function (test) {
const logBothMessageAndObject = function (log, level) {
Log._intercept(3);
// Tests for correctness
log("message");
log({ property1: "foo", property2: "bar" });
log({ message: "mixed", property1: "foo", property2: "bar" });
let intercepted = Log._intercepted();
test.equal(intercepted.length, 3);
const obj1 = EJSON.parse(intercepted[0]);
test.equal(obj1.message, "message");
test.equal(obj1.level, level);
test.instanceOf(obj1.time, Date);
const obj2 = EJSON.parse(intercepted[1]);
test.isFalse(obj2.message);
test.equal(obj2.property1, "foo");
test.equal(obj2.property2, "bar");
test.equal(obj2.level, level);
test.instanceOf(obj2.time, Date);
const obj3 = EJSON.parse(intercepted[2]);
test.equal(obj3.message, "mixed");
test.equal(obj3.property1, "foo");
test.equal(obj3.property2, "bar");
test.equal(obj3.level, level);
test.instanceOf(obj3.time, Date);
// Test logging falsy values, as well as single digits
// and some other non-stringy things
// In a format of testcase, expected result, name of the test.
const testcases = [
[1, "1", "single digit"],
[0, "0", "falsy - 0"],
[null, "null", "falsy - null"],
[undefined, "undefined", "falsy - undefined"],
[
new Date("2013-06-13T01:15:16.000Z"),
new Date("2013-06-13T01:15:16.000Z"),
"date",
],
[/[^regexp]{0,1}/g, "/[^regexp]{0,1}/g", "regexp"],
[true, "true", "boolean - true"],
[false, "false", "boolean - false"],
[-Infinity, "-Infinity", "number - -Infinity"],
];
Log._intercept(testcases.length);
testcases.forEach((testcase) => {
log(testcase[0]);
});
intercepted = Log._intercepted();
test.equal(intercepted.length, testcases.length);
testcases.forEach((testcase, index) => {
const expected = testcase[1];
const testName = testcase[2];
const recieved = intercepted[index];
const obj = EJSON.parse(recieved);
// IE8 and old Safari don't support this date format. Skip it.
if (
expected &&
expected.toString &&
(expected.toString() === "NaN" ||
expected.toString() === "Invalid Date")
) {
return;
}
if (testcase[0] instanceof Date) {
obj.message = new Date(obj.message);
}
test.equal(obj.message, expected, `Logging ${testName}`);
});
// Tests for correct exceptions
Log._intercept(6);
test.throws(function () {
log({ time: "not the right time" });
});
test.throws(function () {
log({ level: "not the right level" });
});
["file", "line", "program", "originApp", "satellite"].forEach(function (
restrictedKey
) {
test.throws(function () {
const obj = {};
obj[restrictedKey] = "usage of restricted key";
log(obj);
});
});
// Can't pass numbers, objects, arrays, regexps or functions as message
const throwingTestcases = [
1,
NaN,
{ foo: "bar" },
["a", "r", "r"],
null,
undefined,
new Date(),
function () {
return 42;
},
/[regexp]/,
];
Log._intercept(throwingTestcases.length);
throwingTestcases.forEach(function (testcase) {
test.throws(function () {
log({ message: testcase });
});
});
// Since all tests above should throw, nothing should be printed.
// This call will set the logging interception to the clean state as well.
test.equal(Log._intercepted().length, 0);
};
logBothMessageAndObject(Log, "info");
["info", "warn", "error"].forEach((level) => {
logBothMessageAndObject(Log[level], level);
});
});
Tinytest.add("logging - parse", function (test) {
test.equal(Log.parse("message"), null);
test.equal(Log.parse('{"foo": "bar"}'), null);
const time = new Date();
test.equal(Log.parse(`{"foo": "bar", "time": ${EJSON.stringify(time)}}`), {
foo: "bar",
time,
});
test.equal(Log.parse('{"foo": not json "bar"}'), null);
test.equal(Log.parse('{"time": "not a date object"}'), null);
});
Tinytest.add("logging - format", function (test) {
const time = new Date(2012, 9 - 1 /*0-based*/, 8, 7, 6, 5, 4);
const utcOffsetStr = "(" + -(new Date().getTimezoneOffset() / 60) + ")";
["debug", "info", "warn", "error"].forEach(function (level) {
test.equal(
Log.format({ message: "message", time, level }),
`${level
.charAt(0)
.toUpperCase()}20120908-07:06:05.004${utcOffsetStr} message`
);
test.equal(
Log.format({
message: "message",
time,
timeInexact: true,
level,
}),
`${level
.charAt(0)
.toUpperCase()}20120908-07:06:05.004${utcOffsetStr}? message`
);
test.equal(
Log.format({ foo1: "bar1", foo2: "bar2", time, level }),
`${level
.charAt(0)
.toUpperCase()}20120908-07:06:05.004${utcOffsetStr} {"foo1":"bar1","foo2":"bar2"}`
);
test.equal(
Log.format({ message: "message", foo: "bar", time, level }),
`${level
.charAt(0)
.toUpperCase()}20120908-07:06:05.004${utcOffsetStr} message {"foo":"bar"}`
);
// Has everything except stderr field
test.equal(
Log.format({
message: "message",
foo: "bar",
time,
level,
file: "app.js",
line: 42,
app: "myApp",
originApp: "proxy",
program: "server",
}),
`${level
.charAt(0)
.toUpperCase()}20120908-07:06:05.004${utcOffsetStr} [myApp via proxy] (server:app.js:42) message {\"foo\":\"bar\"}`
);
// stderr
test.equal(
Log.format({
message: "message from stderr",
time,
level,
stderr: true,
}),
`${level
.charAt(0)
.toUpperCase()}20120908-07:06:05.004${utcOffsetStr} (STDERR) message from stderr`
);
// app/originApp
test.equal(
Log.format({
message: "message",
time,
level,
app: "app",
originApp: "app",
}),
`${level
.charAt(0)
.toUpperCase()}20120908-07:06:05.004${utcOffsetStr} [app] message`
);
test.equal(
Log.format({
message: "message",
time,
level,
app: "app",
originApp: "proxy",
}),
`${level
.charAt(0)
.toUpperCase()}20120908-07:06:05.004${utcOffsetStr} [app via proxy] message`
);
// source info
test.equal(
Log.format({
message: "message",
time,
level,
file: "app.js",
line: 42,
program: "server",
}),
`${level
.charAt(0)
.toUpperCase()}20120908-07:06:05.004${utcOffsetStr} (server:app.js:42) message`
);
test.equal(
Log.format({
message: "message",
time,
level,
file: "app.js",
line: 42,
}),
`${level
.charAt(0)
.toUpperCase()}20120908-07:06:05.004${utcOffsetStr} (app.js:42) message`
);
});
test.matches(
Log.format(
{
message: "oyez",
time: new Date(),
level: "error",
},
{
color: true,
}
),
/oyez/
);
});
Tinytest.add("logging - formats - without time", function (test) {
const time = new Date(2012, 9 - 1 /*0-based*/, 8, 7, 6, 5, 4);
// even tho time and offset are provided they should not be included in the output
Log.showTime = false;
const levels = ["debug", "info", "warn", "error"];
for (const level of levels) {
test.equal(
Log.format({ message: "message", time, level }),
`${level.charAt(0).toUpperCase()} message`
);
test.equal(
Log.format({
message: "message",
time,
timeInexact: true,
level,
}),
`${level.charAt(0).toUpperCase()} message`
);
test.equal(
Log.format({ foo1: "bar1", foo2: "bar2", time, level }),
`${level.charAt(0).toUpperCase()} {"foo1":"bar1","foo2":"bar2"}`
);
test.equal(
Log.format({ message: "message", foo: "bar", time, level }),
`${level.charAt(0).toUpperCase()} message {"foo":"bar"}`
);
// Has everything except stderr field
test.equal(
Log.format({
message: "message",
foo: "bar",
time,
level,
file: "app.js",
line: 42,
app: "myApp",
originApp: "proxy",
program: "server",
}),
`${level
.charAt(0)
.toUpperCase()} [myApp via proxy] (server:app.js:42) message {\"foo\":\"bar\"}`
);
// stderr
test.equal(
Log.format({
message: "message from stderr",
time,
level,
stderr: true,
}),
`${level.charAt(0).toUpperCase()} (STDERR) message from stderr`
);
// app/originApp
test.equal(
Log.format({
message: "message",
time,
level,
app: "app",
originApp: "app",
}),
`${level.charAt(0).toUpperCase()} [app] message`
);
test.equal(
Log.format({
message: "message",
time,
level,
app: "app",
originApp: "proxy",
}),
`${level.charAt(0).toUpperCase()} [app via proxy] message`
);
// source info
test.equal(
Log.format({
message: "message",
time,
level,
file: "app.js",
line: 42,
program: "server",
}),
`${level.charAt(0).toUpperCase()} (server:app.js:42) message`
);
test.equal(
Log.format({
message: "message",
time,
level,
file: "app.js",
line: 42,
}),
`${level.charAt(0).toUpperCase()} (app.js:42) message`
);
}
Log.showTime = true; // reset
});