const { test } = require('tap'); const log4js = require('../../lib/log4js'); const categories = require('../../lib/categories'); test('log4js category inherit all appenders from direct parent', (batch) => { batch.test('should inherit appenders from direct parent', (t) => { const config = { appenders: { stdout1: { type: 'dummy-appender', label: 'stdout1' }, stdout2: { type: 'dummy-appender', label: 'stdout2' }, }, categories: { default: { appenders: ['stdout1'], level: 'ERROR' }, catA: { appenders: ['stdout1', 'stdout2'], level: 'INFO' }, 'catA.catB': { level: 'DEBUG' }, }, }; log4js.configure(config); const childCategoryName = 'catA.catB'; const childAppenders = categories.appendersForCategory(childCategoryName); const childLevel = categories.getLevelForCategory(childCategoryName); t.ok(childAppenders); t.equal(childAppenders.length, 2, 'inherited 2 appenders'); t.ok( childAppenders.some((a) => a.label === 'stdout1'), 'inherited stdout1' ); t.ok( childAppenders.some((a) => a.label === 'stdout2'), 'inherited stdout2' ); t.equal(childLevel.levelStr, 'DEBUG', 'child level overrides parent'); t.end(); }); batch.test( 'multiple children should inherit config from shared parent', (t) => { const config = { appenders: { stdout1: { type: 'dummy-appender', label: 'stdout1' }, stdout2: { type: 'dummy-appender', label: 'stdout2' }, }, categories: { default: { appenders: ['stdout1'], level: 'ERROR' }, catA: { appenders: ['stdout1'], level: 'INFO' }, 'catA.catB.cat1': { level: 'DEBUG' }, // should get sdtout1, DEBUG 'catA.catB.cat2': { appenders: ['stdout2'] }, // should get sdtout1,sdtout2, INFO }, }; log4js.configure(config); const child1CategoryName = 'catA.catB.cat1'; const child1Appenders = categories.appendersForCategory(child1CategoryName); const child1Level = categories.getLevelForCategory(child1CategoryName); t.equal(child1Appenders.length, 1, 'inherited 1 appender'); t.ok( child1Appenders.some((a) => a.label === 'stdout1'), 'inherited stdout1' ); t.equal(child1Level.levelStr, 'DEBUG', 'child level overrides parent'); const child2CategoryName = 'catA.catB.cat2'; const child2Appenders = categories.appendersForCategory(child2CategoryName); const child2Level = categories.getLevelForCategory(child2CategoryName); t.ok(child2Appenders); t.equal( child2Appenders.length, 2, 'inherited 1 appenders, plus its original' ); t.ok( child2Appenders.some((a) => a.label === 'stdout1'), 'inherited stdout1' ); t.ok( child2Appenders.some((a) => a.label === 'stdout2'), 'kept stdout2' ); t.equal(child2Level.levelStr, 'INFO', 'inherited parent level'); t.end(); } ); batch.test('should inherit appenders from multiple parents', (t) => { const config = { appenders: { stdout1: { type: 'dummy-appender', label: 'stdout1' }, stdout2: { type: 'dummy-appender', label: 'stdout2' }, }, categories: { default: { appenders: ['stdout1'], level: 'ERROR' }, catA: { appenders: ['stdout1'], level: 'INFO' }, 'catA.catB': { appenders: ['stdout2'], level: 'INFO' }, // should get stdout1 and stdout2 'catA.catB.catC': { level: 'DEBUG' }, // should get stdout1 and stdout2 }, }; log4js.configure(config); const childCategoryName = 'catA.catB.catC'; const childAppenders = categories.appendersForCategory(childCategoryName); t.ok(childAppenders); t.equal(childAppenders.length, 2, 'inherited 2 appenders'); t.ok( childAppenders.some((a) => a.label === 'stdout1'), 'inherited stdout1' ); t.ok( childAppenders.some((a) => a.label === 'stdout1'), 'inherited stdout1' ); const firstParentName = 'catA.catB'; const firstParentAppenders = categories.appendersForCategory(firstParentName); t.ok(firstParentAppenders); t.equal(firstParentAppenders.length, 2, 'ended up with 2 appenders'); t.ok( firstParentAppenders.some((a) => a.label === 'stdout1'), 'inherited stdout1' ); t.ok( firstParentAppenders.some((a) => a.label === 'stdout2'), 'kept stdout2' ); t.end(); }); batch.test( 'should inherit appenders from deep parent with missing direct parent', (t) => { const config = { appenders: { stdout1: { type: 'dummy-appender', label: 'stdout1' }, stdout2: { type: 'dummy-appender', label: 'stdout2' }, }, categories: { default: { appenders: ['stdout1'], level: 'ERROR' }, catA: { appenders: ['stdout1'], level: 'INFO' }, // no catA.catB, but should get created, with stdout1 'catA.catB.catC': { level: 'DEBUG' }, // should get stdout1 }, }; log4js.configure(config); const childCategoryName = 'catA.catB.catC'; const childAppenders = categories.appendersForCategory(childCategoryName); t.ok(childAppenders); t.equal(childAppenders.length, 1, 'inherited 1 appenders'); t.ok( childAppenders.some((a) => a.label === 'stdout1'), 'inherited stdout1' ); const firstParentCategoryName = 'catA.catB'; const firstParentAppenders = categories.appendersForCategory( firstParentCategoryName ); t.ok(firstParentAppenders, 'catA.catB got created implicitily'); t.equal( firstParentAppenders.length, 1, 'created with 1 inherited appender' ); t.ok( firstParentAppenders.some((a) => a.label === 'stdout1'), 'inherited stdout1' ); t.end(); } ); batch.test('should deal gracefully with missing parent', (t) => { const config = { appenders: { stdout1: { type: 'dummy-appender', label: 'stdout1' }, stdout2: { type: 'dummy-appender', label: 'stdout2' }, }, categories: { default: { appenders: ['stdout1'], level: 'ERROR' }, // no catA nor catA.catB, but should get created, with default values 'catA.catB.catC': { appenders: ['stdout2'], level: 'DEBUG' }, // should get stdout2, DEBUG }, }; log4js.configure(config); const childCategoryName = 'catA.catB.catC'; const childAppenders = categories.appendersForCategory(childCategoryName); t.ok(childAppenders); t.equal(childAppenders.length, 1); t.ok(childAppenders.some((a) => a.label === 'stdout2')); t.end(); }); batch.test( 'should not get duplicate appenders if parent has the same one', (t) => { const config = { appenders: { stdout1: { type: 'dummy-appender', label: 'stdout1' }, stdout2: { type: 'dummy-appender', label: 'stdout2' }, }, categories: { default: { appenders: ['stdout1'], level: 'ERROR' }, catA: { appenders: ['stdout1', 'stdout2'], level: 'INFO' }, 'catA.catB': { appenders: ['stdout1'], level: 'DEBUG' }, }, }; log4js.configure(config); const childCategoryName = 'catA.catB'; const childAppenders = categories.appendersForCategory(childCategoryName); t.ok(childAppenders); t.equal(childAppenders.length, 2, 'inherited 1 appender'); t.ok( childAppenders.some((a) => a.label === 'stdout1'), 'still have stdout1' ); t.ok( childAppenders.some((a) => a.label === 'stdout2'), 'inherited stdout2' ); t.end(); } ); batch.test('inherit:falses should disable inheritance', (t) => { const config = { appenders: { stdout1: { type: 'dummy-appender', label: 'stdout1' }, stdout2: { type: 'dummy-appender', label: 'stdout2' }, }, categories: { default: { appenders: ['stdout1'], level: 'ERROR' }, catA: { appenders: ['stdout1'], level: 'INFO' }, 'catA.catB': { appenders: ['stdout2'], level: 'INFO', inherit: false }, // should not inherit from catA }, }; log4js.configure(config); const childCategoryName = 'catA.catB'; const childAppenders = categories.appendersForCategory(childCategoryName); t.ok(childAppenders); t.equal(childAppenders.length, 1, 'inherited no appender'); t.ok( childAppenders.some((a) => a.label === 'stdout2'), 'kept stdout2' ); t.end(); }); batch.test( 'inheritance should stop if direct parent has inherit off', (t) => { const config = { appenders: { stdout1: { type: 'dummy-appender', label: 'stdout1' }, stdout2: { type: 'dummy-appender', label: 'stdout2' }, }, categories: { default: { appenders: ['stdout1'], level: 'ERROR' }, catA: { appenders: ['stdout1'], level: 'INFO' }, 'catA.catB': { appenders: ['stdout2'], level: 'INFO', inherit: false, }, // should not inherit from catA 'catA.catB.catC': { level: 'DEBUG' }, // should inherit from catB only }, }; log4js.configure(config); const childCategoryName = 'catA.catB.catC'; const childAppenders = categories.appendersForCategory(childCategoryName); t.ok(childAppenders); t.equal(childAppenders.length, 1, 'inherited 1 appender'); t.ok( childAppenders.some((a) => a.label === 'stdout2'), 'inherited stdout2' ); const firstParentCategoryName = 'catA.catB'; const firstParentAppenders = categories.appendersForCategory( firstParentCategoryName ); t.ok(firstParentAppenders); t.equal(firstParentAppenders.length, 1, 'did not inherit new appenders'); t.ok( firstParentAppenders.some((a) => a.label === 'stdout2'), 'kept stdout2' ); t.end(); } ); batch.test('should inherit level when it is missing', (t) => { const config = { appenders: { stdout1: { type: 'dummy-appender', label: 'stdout1' }, stdout2: { type: 'dummy-appender', label: 'stdout2' }, }, categories: { default: { appenders: ['stdout1'], level: 'ERROR' }, catA: { appenders: ['stdout1'], level: 'INFO' }, // no catA.catB, but should get created, with stdout1, level INFO 'catA.catB.catC': {}, // should get stdout1, level INFO }, }; log4js.configure(config); const childCategoryName = 'catA.catB.catC'; const childLevel = categories.getLevelForCategory(childCategoryName); t.equal(childLevel.levelStr, 'INFO', 'inherited level'); const firstParentCategoryName = 'catA.catB'; const firstParentLevel = categories.getLevelForCategory( firstParentCategoryName ); t.equal( firstParentLevel.levelStr, 'INFO', 'generate parent inherited level from base' ); t.end(); }); batch.end(); });