From 633b4222ab52c05cdb40f54efcdda28b415d84eb Mon Sep 17 00:00:00 2001 From: Lam Wei Li Date: Wed, 9 Mar 2022 23:36:42 +0800 Subject: [PATCH] chore(test): improve test coverage for tcpAppender appenders/tcp.js - Line 37 - debug('drain event received, emptying buffer'); appenders/tcp.js - Line 38 - canWrite = true; appenders/tcp.js - Line 39 - emptyBuffer(); appenders/tcp.js - Line 43 - debug('connection error', e); appenders/tcp.js - Line 44 - canWrite = false; appenders/tcp.js - Line 45 - emptyBuffer(); appenders/tcp.js - Line 54 - write(loggingEvent); --- test/tap/tcp-appender-test.js | 149 +++++++++++++++++++++++++++++++++- 1 file changed, 148 insertions(+), 1 deletion(-) diff --git a/test/tap/tcp-appender-test.js b/test/tap/tcp-appender-test.js index e61255f..293f682 100644 --- a/test/tap/tcp-appender-test.js +++ b/test/tap/tcp-appender-test.js @@ -1,5 +1,7 @@ const { test } = require("tap"); const net = require("net"); +const flatted = require("flatted"); +const sandbox = require("@log4js-node/sandboxed-module"); const log4js = require("../../lib/log4js"); const LoggingEvent = require("../../lib/LoggingEvent"); @@ -26,6 +28,53 @@ function makeServer(config) { return server; } +function makeFakeNet() { + return { + data: [], + cbs: {}, + createConnectionCalled: 0, + createConnection(port, host) { + const fakeNet = this; + this.port = port; + this.host = host; + this.createConnectionCalled += 1; + return { + on(evt, cb) { + fakeNet.cbs[evt] = cb; + }, + write(data, encoding) { + fakeNet.data.push(data); + fakeNet.encoding = encoding; + return false; + }, + end() { + fakeNet.closeCalled = true; + } + }; + }, + createServer(cb) { + const fakeNet = this; + cb({ + remoteAddress: "1.2.3.4", + remotePort: "1234", + setEncoding(encoding) { + fakeNet.encoding = encoding; + }, + on(event, cb2) { + fakeNet.cbs[event] = cb2; + } + }); + + return { + listen(port, host) { + fakeNet.port = port; + fakeNet.host = host; + } + }; + } + }; +} + test("TCP Appender", batch => { batch.test("Default Configuration", t => { @@ -118,7 +167,6 @@ test("TCP Appender", batch => { }); }); - batch.test("Custom Layout", t => { messages = []; @@ -171,5 +219,104 @@ test("TCP Appender", batch => { }); }); + batch.test("when underlying stream errors", t => { + const fakeNet = makeFakeNet(); + + const sandboxedLog4js = sandbox.require("../../lib/log4js", { + requires: { + net: fakeNet + } + }); + sandboxedLog4js.configure({ + appenders: { + default: { type: "tcp" }, + }, + categories: { + default: { appenders: ["default"], level: "debug" }, + } + }); + + const logger = sandboxedLog4js.getLogger(); + + logger.info("before connect"); + t.test( + "should buffer messages written before socket is connected", + assert => { + assert.equal(fakeNet.data.length, 0); + assert.equal(fakeNet.createConnectionCalled, 1); + assert.end(); + } + ); + + fakeNet.cbs.connect(); + t.test( + "should flush buffered messages", + assert => { + assert.equal(fakeNet.data.length, 1); + assert.equal(fakeNet.createConnectionCalled, 1); + assert.match(fakeNet.data[0], "before connect"); + assert.end(); + } + ); + + logger.info("after connect"); + t.test( + "should write log messages to socket as flatted strings with a terminator string", + assert => { + assert.equal(fakeNet.data.length, 2); + assert.match(fakeNet.data[0], "before connect"); + assert.ok(fakeNet.data[0].endsWith("__LOG4JS__")); + assert.match(fakeNet.data[1], "after connect"); + assert.ok(fakeNet.data[1].endsWith("__LOG4JS__")); + assert.equal(fakeNet.encoding, "utf8"); + assert.end(); + } + ); + + fakeNet.cbs.error(); + logger.info("after error, before close"); + fakeNet.cbs.close(); + logger.info("after close, before connect"); + fakeNet.cbs.connect(); + logger.info("after error, after connect"); + t.test("should attempt to re-open the socket on error", assert => { + assert.equal(fakeNet.data.length, 5); + assert.equal(fakeNet.createConnectionCalled, 2); + assert.match(fakeNet.data[2], "after error, before close"); + assert.match(fakeNet.data[3], "after close, before connect"); + assert.match(fakeNet.data[4], "after error, after connect"); + assert.end(); + }); + + t.test("should buffer messages until drain", assert => { + const previousLength = fakeNet.data.length; + logger.info("should not be flushed"); + assert.equal(fakeNet.data.length, previousLength); + assert.notMatch(fakeNet.data[fakeNet.data.length - 1], "should not be flushed"); + + fakeNet.cbs.drain(); + assert.equal(fakeNet.data.length, previousLength + 1); + assert.match(fakeNet.data[fakeNet.data.length - 1], "should not be flushed"); + assert.end(); + }); + + t.test("should serialize an Error correctly", assert => { + const previousLength = fakeNet.data.length; + logger.error(new Error("Error test")); + fakeNet.cbs.drain(); + assert.equal(fakeNet.data.length, previousLength + 1); + const raw = fakeNet.data[fakeNet.data.length - 1]; + assert.ok( + flatted.parse(raw.substring(0, raw.indexOf('__LOG4JS__'))).data[0].stack, + `Expected:\n\n${fakeNet.data[6]}\n\n to have a 'data[0].stack' property` + ); + const actual = flatted.parse(raw.substring(0, raw.indexOf('__LOG4JS__'))).data[0].stack; + assert.match(actual, /^Error: Error test/); + assert.end(); + }); + + t.end(); + }); + batch.end(); });