Merge pull request #931 from log4js-node/windows-fixes

chore: changes to get tests passing on windows
This commit is contained in:
Gareth Jones 2019-08-16 16:38:01 +10:00 committed by GitHub
commit b75d97f8a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 232 additions and 280 deletions

View File

@ -1,5 +1,3 @@
const dateFormat = require('date-format');
const os = require('os');
const util = require('util');

6
package-lock.json generated
View File

@ -1512,9 +1512,9 @@
},
"dependencies": {
"graceful-fs": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz",
"integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg=="
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz",
"integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q=="
}
}
},

View File

@ -28,12 +28,10 @@
"node": ">=8.0"
},
"scripts": {
"clean": "find test -type f ! -name '*.json' ! -name '*.js' ! -name '.eslintrc' -delete && rm *.log",
"posttest": "npm run clean",
"pretest": "eslint 'lib/**/*.js' 'test/**/*.js'",
"test": "tap 'test/tap/**/*.js' --cov",
"pretest": "eslint \"lib/**/*.js\" \"test/**/*.js\"",
"test": "tap \"test/tap/**/*.js\" --cov",
"typings": "tsc -p types/tsconfig.json",
"codecov": "tap 'test/tap/**/*.js' --cov --coverage-report=lcov && codecov"
"codecov": "tap \"test/tap/**/*.js\" --cov --coverage-report=lcov && codecov"
},
"directories": {
"test": "test",
@ -57,6 +55,7 @@
"eslint-import-resolver-node": "^0.3.2",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-prettier": "^3.1.0",
"fs-extra": "^8.1.0",
"husky": "^3.0.2",
"nyc": "^14.1.1",
"prettier": "^1.18.2",

View File

@ -342,11 +342,14 @@ test("log4js configuration validation", batch => {
return target[key];
}
});
// windows file paths are different to unix, so let's make this work for both.
const requires = {};
requires[path.join("/var", "lib", "cheese", "cheese")] = testAppender("correct", result);
const sandboxedLog4js = sandbox.require("../../lib/log4js", {
ignoreMissing: true,
requires: {
"/var/lib/cheese/cheese": testAppender("correct", result)
},
requires,
globals: {
process: fakeProcess
}

View File

@ -130,7 +130,7 @@ test("../../lib/appenders/dateFile", batch => {
});
batch.test("should flush logs on shutdown", t => {
const testFile = path.join(__dirname, "date-appender-default.log");
const testFile = path.join(__dirname, "date-appender-flush.log");
log4js.configure({
appenders: { test: { type: "dateFile", filename: testFile } },
categories: { default: { appenders: ["test"], level: "trace" } }
@ -141,7 +141,7 @@ test("../../lib/appenders/dateFile", batch => {
logger.info("2");
logger.info("3");
t.teardown(() => {
removeFile("date-appender-default.log");
removeFile("date-appender-flush.log");
});
log4js.shutdown(() => {

View File

@ -1,72 +1,77 @@
const { test } = require("tap");
const sandbox = require("@log4js-node/sandboxed-module");
test("file appender SIGHUP", t => {
let closeCalled = 0;
let openCalled = 0;
// no SIGHUP signals on Windows, so don't run the tests
if (process.platform !== "win32") {
test("file appender SIGHUP", t => {
let closeCalled = 0;
let openCalled = 0;
const appender = sandbox
.require("../../lib/appenders/file", {
requires: {
streamroller: {
RollingFileStream: class RollingFileStream {
constructor() {
openCalled++;
this.ended = false;
}
on() {
this.dummy = "easier than turning off lint rule";
}
end(cb) {
this.ended = true;
closeCalled++;
cb();
}
write() {
if (this.ended) {
throw new Error("write after end");
const appender = sandbox
.require("../../lib/appenders/file", {
requires: {
streamroller: {
RollingFileStream: class RollingFileStream {
constructor() {
openCalled++;
this.ended = false;
}
on() {
this.dummy = "easier than turning off lint rule";
}
end(cb) {
this.ended = true;
closeCalled++;
cb();
}
write() {
if (this.ended) {
throw new Error("write after end");
}
return true;
}
return true;
}
}
}
}
})
.configure(
{ type: "file", filename: "sighup-test-file" },
{
basicLayout() {
return "whatever";
})
.configure(
{ type: "file", filename: "sighup-test-file" },
{
basicLayout() {
return "whatever";
}
}
}
);
);
appender("something to log");
process.kill(process.pid, "SIGHUP");
appender("something to log");
process.kill(process.pid, "SIGHUP");
t.plan(2);
setTimeout(() => {
appender("something to log after sighup");
t.equal(openCalled, 2, "open should be called twice");
t.equal(closeCalled, 1, "close should be called once");
t.end();
}, 100);
});
test("file appender SIGHUP handler leak", t => {
const log4js = require("../../lib/log4js");
const initialListeners = process.listenerCount("SIGHUP");
log4js.configure({
appenders: {
file: { type: "file", filename: "test.log" }
},
categories: { default: { appenders: ["file"], level: "info" } }
t.plan(2);
setTimeout(() => {
appender("something to log after sighup");
t.equal(openCalled, 2, "open should be called twice");
t.equal(closeCalled, 1, "close should be called once");
t.end();
}, 100);
});
log4js.shutdown(() => {
t.equal(process.listenerCount("SIGHUP"), initialListeners);
t.end();
test("file appender SIGHUP handler leak", t => {
const log4js = require("../../lib/log4js");
const initialListeners = process.listenerCount("SIGHUP");
log4js.configure({
appenders: {
file: { type: "file", filename: "test.log" }
},
categories: { default: { appenders: ["file"], level: "info" } }
});
log4js.shutdown(() => {
t.equal(process.listenerCount("SIGHUP"), initialListeners);
t.end();
});
});
});
}

View File

@ -1,27 +1,31 @@
const { test } = require("tap");
const fs = require("fs");
const fs = require("fs-extra");
const path = require("path");
const sandbox = require("@log4js-node/sandboxed-module");
const zlib = require("zlib");
const util = require("util");
const sleep = util.promisify(setTimeout);
const gunzip = util.promisify(zlib.gunzip);
const EOL = require("os").EOL || "\n";
const log4js = require("../../lib/log4js");
function removeFile(filename) {
const removeFile = async filename => {
try {
fs.unlinkSync(filename);
await fs.unlink(filename);
} catch (e) {
// doesn't really matter if it failed
// let's pretend this never happened
}
}
};
test("log4js fileAppender", batch => {
batch.test("with default fileAppender settings", t => {
batch.test("with default fileAppender settings", async t => {
const testFile = path.join(__dirname, "fa-default-test.log");
const logger = log4js.getLogger("default-settings");
removeFile(testFile);
await removeFile(testFile);
t.tearDown(() => {
removeFile(testFile);
t.tearDown(async () => {
await removeFile(testFile);
});
log4js.configure({
@ -31,21 +35,19 @@ test("log4js fileAppender", batch => {
logger.info("This should be in the file.");
setTimeout(() => {
fs.readFile(testFile, "utf8", (err, fileContents) => {
t.include(fileContents, `This should be in the file.${EOL}`);
t.match(
fileContents,
/\[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}] \[INFO] default-settings - /
);
t.end();
});
}, 100);
await sleep(100);
const fileContents = await fs.readFile(testFile, "utf8");
t.include(fileContents, `This should be in the file.${EOL}`);
t.match(
fileContents,
/\[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}] \[INFO] default-settings - /
);
t.end();
});
batch.test("should flush logs on shutdown", t => {
batch.test("should flush logs on shutdown", async t => {
const testFile = path.join(__dirname, "fa-default-test.log");
removeFile(testFile);
await removeFile(testFile);
log4js.configure({
appenders: { test: { type: "file", filename: testFile } },
@ -57,29 +59,25 @@ test("log4js fileAppender", batch => {
logger.info("2");
logger.info("3");
log4js.shutdown(() => {
fs.readFile(testFile, "utf8", (err, fileContents) => {
// 3 lines of output, plus the trailing newline.
t.equal(fileContents.split(EOL).length, 4);
t.match(
fileContents,
/\[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}] \[INFO] default-settings - /
);
t.end();
});
});
await new Promise(resolve => log4js.shutdown(resolve));
const fileContents = await fs.readFile(testFile, "utf8");
// 3 lines of output, plus the trailing newline.
t.equal(fileContents.split(EOL).length, 4);
t.match(
fileContents,
/\[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}] \[INFO] default-settings - /
);
t.end();
});
batch.test("with a max file size and no backups", t => {
batch.test("with a max file size and no backups", async t => {
const testFile = path.join(__dirname, "fa-maxFileSize-test.log");
const logger = log4js.getLogger("max-file-size");
t.tearDown(() => {
removeFile(testFile);
removeFile(`${testFile}.1`);
t.tearDown(async () => {
await Promise.all([removeFile(testFile), removeFile(`${testFile}.1`)]);
});
removeFile(testFile);
removeFile(`${testFile}.1`);
await Promise.all([removeFile(testFile), removeFile(`${testFile}.1`)]);
// log file of 100 bytes maximum, no backups
log4js.configure({
@ -100,31 +98,26 @@ test("log4js fileAppender", batch => {
logger.info("This is an intermediate log message.");
logger.info("This is the second log message.");
// wait for the file system to catch up
setTimeout(() => {
fs.readFile(testFile, "utf8", (err, fileContents) => {
t.include(fileContents, "This is the second log message.");
t.equal(fileContents.indexOf("This is the first log message."), -1);
fs.readdir(__dirname, (e, files) => {
const logFiles = files.filter(file =>
file.includes("fa-maxFileSize-test.log")
);
t.equal(logFiles.length, 2, "should be 2 files");
t.end();
});
});
}, 100);
await sleep(100);
const fileContents = await fs.readFile(testFile, "utf8");
t.include(fileContents, "This is the second log message.");
t.equal(fileContents.indexOf("This is the first log message."), -1);
const files = await fs.readdir(__dirname);
const logFiles = files.filter(file =>
file.includes("fa-maxFileSize-test.log")
);
t.equal(logFiles.length, 2, "should be 2 files");
t.end();
});
batch.test("with a max file size in unit mode and no backups", t => {
batch.test("with a max file size in unit mode and no backups", async t => {
const testFile = path.join(__dirname, "fa-maxFileSize-unit-test.log");
const logger = log4js.getLogger("max-file-size-unit");
t.tearDown(() => {
removeFile(testFile);
removeFile(`${testFile}.1`);
t.tearDown(async () => {
await Promise.all([removeFile(testFile), removeFile(`${testFile}.1`)]);
});
removeFile(testFile);
removeFile(`${testFile}.1`);
await Promise.all([removeFile(testFile), removeFile(`${testFile}.1`)]);
// log file of 1K = 1024 bytes maximum, no backups
log4js.configure({
@ -133,50 +126,52 @@ test("log4js fileAppender", batch => {
type: "file",
filename: testFile,
maxLogSize: "1K",
backups: 0
backups: 0,
layout: { type: "messagePassThrough" }
}
},
categories: {
default: { appenders: ["file"], level: "debug" }
}
});
const maxLine = 13;
const maxLine = 22; // 1024 max file size / 47 bytes per line
for (let i = 0; i < maxLine; i++) {
logger.info("This is the first log message.");
logger.info("These are the log messages for the first file."); // 46 bytes per line + '\n'
}
logger.info("This is the second log message.");
// wait for the file system to catch up
setTimeout(() => {
fs.readFile(testFile, "utf8", (err, fileContents) => {
t.include(fileContents, "This is the second log message.");
t.equal(fileContents.indexOf("This is the first log message."), -1);
fs.readdir(__dirname, (e, files) => {
const logFiles = files.filter(file =>
file.includes("fa-maxFileSize-unit-test.log")
);
t.equal(logFiles.length, 2, "should be 2 files");
t.end();
});
});
}, 100);
await sleep(100);
const fileContents = await fs.readFile(testFile, "utf8");
t.match(fileContents, "This is the second log message.");
t.notMatch(fileContents, "These are the log messages for the first file.");
const files = await fs.readdir(__dirname);
const logFiles = files.filter(file =>
file.includes("fa-maxFileSize-unit-test.log")
);
t.equal(logFiles.length, 2, "should be 2 files");
t.end();
});
batch.test("with a max file size and 2 backups", t => {
batch.test("with a max file size and 2 backups", async t => {
const testFile = path.join(
__dirname,
"fa-maxFileSize-with-backups-test.log"
);
const logger = log4js.getLogger("max-file-size-backups");
removeFile(testFile);
removeFile(`${testFile}.1`);
removeFile(`${testFile}.2`);
await Promise.all([
removeFile(testFile),
removeFile(`${testFile}.1`),
removeFile(`${testFile}.2`)
]);
t.tearDown(() => {
removeFile(testFile);
removeFile(`${testFile}.1`);
removeFile(`${testFile}.2`);
t.tearDown(async () => {
await Promise.all([
removeFile(testFile),
removeFile(`${testFile}.1`),
removeFile(`${testFile}.2`)
]);
});
// log file of 50 bytes maximum, 2 backups
@ -197,68 +192,45 @@ test("log4js fileAppender", batch => {
logger.info("This is the third log message.");
logger.info("This is the fourth log message.");
// give the system a chance to open the stream
setTimeout(() => {
fs.readdir(__dirname, (err, files) => {
const logFiles = files
.sort()
.filter(file =>
file.includes("fa-maxFileSize-with-backups-test.log")
);
t.equal(logFiles.length, 3);
t.same(logFiles, [
"fa-maxFileSize-with-backups-test.log",
"fa-maxFileSize-with-backups-test.log.1",
"fa-maxFileSize-with-backups-test.log.2"
]);
t.test("the contents of the first file", assert => {
fs.readFile(
path.join(__dirname, logFiles[0]),
"utf8",
(e, contents) => {
assert.include(contents, "This is the fourth log message.");
assert.end();
}
);
});
t.test("the contents of the second file", assert => {
fs.readFile(
path.join(__dirname, logFiles[1]),
"utf8",
(e, contents) => {
assert.include(contents, "This is the third log message.");
assert.end();
}
);
});
t.test("the contents of the third file", assert => {
fs.readFile(
path.join(__dirname, logFiles[2]),
"utf8",
(e, contents) => {
assert.include(contents, "This is the second log message.");
assert.end();
}
);
});
t.end();
});
}, 200);
await sleep(200);
const files = await fs.readdir(__dirname);
const logFiles = files
.sort()
.filter(file => file.includes("fa-maxFileSize-with-backups-test.log"));
t.equal(logFiles.length, 3);
t.same(logFiles, [
"fa-maxFileSize-with-backups-test.log",
"fa-maxFileSize-with-backups-test.log.1",
"fa-maxFileSize-with-backups-test.log.2"
]);
let contents = await fs.readFile(path.join(__dirname, logFiles[0]), "utf8");
t.include(contents, "This is the fourth log message.");
contents = await fs.readFile(path.join(__dirname, logFiles[1]), "utf8");
t.include(contents, "This is the third log message.");
contents = await fs.readFile(path.join(__dirname, logFiles[2]), "utf8");
t.include(contents, "This is the second log message.");
t.end();
});
batch.test("with a max file size and 2 compressed backups", t => {
batch.test("with a max file size and 2 compressed backups", async t => {
const testFile = path.join(
__dirname,
"fa-maxFileSize-with-backups-compressed-test.log"
);
const logger = log4js.getLogger("max-file-size-backups");
removeFile(testFile);
removeFile(`${testFile}.1.gz`);
removeFile(`${testFile}.2.gz`);
await Promise.all([
removeFile(testFile),
removeFile(`${testFile}.1.gz`),
removeFile(`${testFile}.2.gz`)
]);
t.tearDown(() => {
removeFile(testFile);
removeFile(`${testFile}.1.gz`);
removeFile(`${testFile}.2.gz`);
t.tearDown(async () => {
await Promise.all([
removeFile(testFile),
removeFile(`${testFile}.1.gz`),
removeFile(`${testFile}.2.gz`)
]);
});
// log file of 50 bytes maximum, 2 backups
@ -279,56 +251,31 @@ test("log4js fileAppender", batch => {
logger.info("This is the third log message.");
logger.info("This is the fourth log message.");
// give the system a chance to open the stream
setTimeout(() => {
fs.readdir(__dirname, (err, files) => {
const logFiles = files
.sort()
.filter(file =>
file.includes("fa-maxFileSize-with-backups-compressed-test.log")
);
t.equal(logFiles.length, 3, "should be 3 files");
t.same(logFiles, [
"fa-maxFileSize-with-backups-compressed-test.log",
"fa-maxFileSize-with-backups-compressed-test.log.1.gz",
"fa-maxFileSize-with-backups-compressed-test.log.2.gz"
]);
t.test("the contents of the first file", assert => {
fs.readFile(
path.join(__dirname, logFiles[0]),
"utf8",
(e, contents) => {
assert.include(contents, "This is the fourth log message.");
assert.end();
}
);
});
t.test("the contents of the second file", assert => {
zlib.gunzip(
fs.readFileSync(path.join(__dirname, logFiles[1])),
(e, contents) => {
assert.include(
contents.toString("utf8"),
"This is the third log message."
);
assert.end();
}
);
});
t.test("the contents of the third file", assert => {
zlib.gunzip(
fs.readFileSync(path.join(__dirname, logFiles[2])),
(e, contents) => {
assert.include(
contents.toString("utf8"),
"This is the second log message."
);
assert.end();
}
);
});
t.end();
});
}, 1000);
await sleep(1000);
const files = await fs.readdir(__dirname);
const logFiles = files
.sort()
.filter(file =>
file.includes("fa-maxFileSize-with-backups-compressed-test.log")
);
t.equal(logFiles.length, 3, "should be 3 files");
t.same(logFiles, [
"fa-maxFileSize-with-backups-compressed-test.log",
"fa-maxFileSize-with-backups-compressed-test.log.1.gz",
"fa-maxFileSize-with-backups-compressed-test.log.2.gz"
]);
let contents = await fs.readFile(path.join(__dirname, logFiles[0]), "utf8");
t.include(contents, "This is the fourth log message.");
contents = await gunzip(
await fs.readFile(path.join(__dirname, logFiles[1]))
);
t.include(contents.toString("utf8"), "This is the third log message.");
contents = await gunzip(
await fs.readFile(path.join(__dirname, logFiles[2]))
);
t.include(contents.toString("utf8"), "This is the second log message.");
t.end();
});
batch.test("when underlying stream errors", t => {

View File

@ -109,25 +109,23 @@ test("log4js fileSyncAppender", batch => {
type: "fileSync",
filename: testFile,
maxLogSize: "1K",
backups: 0
backups: 0,
layout: { type: "messagePassThrough" }
}
},
categories: { default: { appenders: ["sync"], level: "debug" } }
});
const maxLine = 13;
const maxLine = 22; // 1024 max file size / 47 bytes per line
for (let i = 0; i < maxLine; i++) {
logger.info("This is the first log message.");
logger.info("These are the log messages for the first file."); // 46 bytes per line + '\n'
}
logger.info("This is the second log message.");
t.test("log file should only contain the second message", assert => {
fs.readFile(testFile, "utf8", (err, fileContents) => {
assert.include(fileContents, `This is the second log message.${EOL}`);
assert.equal(
fileContents.indexOf("This is the first log message."),
-1
);
assert.match(fileContents, `This is the second log message.${EOL}`);
assert.notMatch(fileContents, "These are the log messages for the first file.");
assert.end();
});
});

View File

@ -1,5 +1,6 @@
const { test } = require("tap");
const os = require("os");
const path = require("path");
const { EOL } = os;
@ -257,7 +258,7 @@ test("log4js layouts", batch => {
// console.log([Error('123').stack.split('\n').slice(1).join('\n')])
const callStack =
" at repl:1:14\n at ContextifyScript.Script.runInThisContext (vm.js:50:33)\n at REPLServer.defaultEval (repl.js:240:29)\n at bound (domain.js:301:14)\n at REPLServer.runBound [as eval] (domain.js:314:12)\n at REPLServer.onLine (repl.js:468:10)\n at emitOne (events.js:121:20)\n at REPLServer.emit (events.js:211:7)\n at REPLServer.Interface._onLine (readline.js:280:10)\n at REPLServer.Interface._line (readline.js:629:8)"; // eslint-disable-line
const fileName = "/log4js-node/test/tap/layouts-test.js";
const fileName = path.normalize("/log4js-node/test/tap/layouts-test.js");
const lineNumber = 1;
const columnNumber = 14;
const event = {
@ -483,7 +484,7 @@ test("log4js layouts", batch => {
event,
tokens,
"%f{2}",
"tap/layouts-test.js"
path.join("tap", "layouts-test.js")
);
testPattern(
assert,
@ -491,7 +492,7 @@ test("log4js layouts", batch => {
event,
tokens,
"%f{3}",
"test/tap/layouts-test.js"
path.join("test", "tap", "layouts-test.js")
);
testPattern(
assert,
@ -499,7 +500,7 @@ test("log4js layouts", batch => {
event,
tokens,
"%f{4}",
"log4js-node/test/tap/layouts-test.js"
path.join("log4js-node","test","tap","layouts-test.js")
);
testPattern(
assert,
@ -507,7 +508,7 @@ test("log4js layouts", batch => {
event,
tokens,
"%f{5}",
"/log4js-node/test/tap/layouts-test.js"
path.join("/log4js-node","test","tap","layouts-test.js")
);
testPattern(
assert,
@ -515,7 +516,7 @@ test("log4js layouts", batch => {
event,
tokens,
"%f{99}",
"/log4js-node/test/tap/layouts-test.js"
path.join("/log4js-node","test","tap","layouts-test.js")
);
assert.end();
});

View File

@ -140,16 +140,17 @@ test("multiFile appender", batch => {
base: "logs/",
property: "label",
extension: ".log",
maxLogSize: 61,
backups: 2
maxLogSize: 30,
backups: 2,
layout: { type: "messagePassThrough" }
}
},
categories: { default: { appenders: ["multi"], level: "info" } }
});
const loggerF = log4js.getLogger();
loggerF.addContext("label", "F");
loggerF.info("Being in logger F is the best");
loggerF.info("I am also in logger F");
loggerF.info("Being in logger F is the best.");
loggerF.info("I am also in logger F, awesome");
loggerF.info("I am in logger F");
log4js.shutdown(() => {
let contents = fs.readFileSync("logs/F.log", "utf-8");

View File

@ -4,7 +4,7 @@ const childProcess = require("child_process");
const sandbox = require("@log4js-node/sandboxed-module");
const log4js = require("../../lib/log4js");
test("multiprocess appender shutdown (master)", { timeout: 2000 }, t => {
test("multiprocess appender shutdown (master)", { timeout: 5000 }, t => {
log4js.configure({
appenders: {
stdout: { type: "stdout" },
@ -30,9 +30,9 @@ test("multiprocess appender shutdown (master)", { timeout: 2000 }, t => {
t.ok(err, "we got a connection error");
t.end();
});
}, 250);
}, 1000);
});
}, 250);
}, 1000);
});
test("multiprocess appender shutdown (worker)", t => {