150 lines
5.6 KiB
TypeScript
150 lines
5.6 KiB
TypeScript
import { createInterface, Interface } from 'readline';
|
|
import chai, { expect } from 'chai';
|
|
import 'mocha';
|
|
import chaiFs from 'chai-fs';
|
|
import fc from 'fast-check';
|
|
import fs from 'fs-extra';
|
|
import { container } from '../../core/container';
|
|
import { setDev } from '../../core/env.spec';
|
|
import { LogLevel } from './log-level';
|
|
|
|
chai.use(chaiFs);
|
|
|
|
describe('Logger Service', () => {
|
|
function getLastLine(rl: Interface): Promise<string> {
|
|
return new Promise((resolve) => {
|
|
let lastLine = '';
|
|
rl.on('line', (line) => {
|
|
lastLine = line;
|
|
});
|
|
|
|
rl.on('close', () => {
|
|
resolve(lastLine);
|
|
});
|
|
});
|
|
}
|
|
|
|
function getDefaultLogReadLineInterface(logger: LoggerInterface) {
|
|
return createInterface(fs.createReadStream(logger.getLogFile()));
|
|
}
|
|
|
|
// no debug because it gets tested separately
|
|
const logLevels = ['fatal', 'error', 'warning', 'notice', 'info'];
|
|
const logLevelsNumber = [0, 1, 2, 3, 4];
|
|
|
|
// hard-coded because it is hardcoded in the logger as well and therefore can be tested to be this way, in bytes
|
|
const maxLogSize = 50000;
|
|
|
|
type LogLevelArbitrary = fc.Arbitrary<'fatal' | 'error' | 'warning' | 'notice' | 'info'>;
|
|
const logLevelArbitrary = fc.constantFrom(...logLevels);
|
|
|
|
const logLevelNumberArbitrary = fc.constantFrom(...logLevelsNumber);
|
|
|
|
it('creates log files', () => {
|
|
const logger: LoggerInterface = container.get('logger');
|
|
|
|
expect(logger.getLogFile()).path('log file is not created');
|
|
expect(logger.getExceptionsLogFile()).path('exception log file is not created');
|
|
});
|
|
|
|
it('logs exceptions', async () => {
|
|
const logger: LoggerInterface = container.get('logger');
|
|
|
|
await logger.exception(new Error('this is an error'));
|
|
});
|
|
|
|
it("default log file doesn't get bigger than 50KB @slow", async () => {
|
|
const logger: LoggerInterface = container.get('logger');
|
|
|
|
let prevLogFileSize = (await fs.stat(logger.getLogFile())).size;
|
|
let minNumberOfLines = maxLogSize;
|
|
const sizeIncreases = [];
|
|
for (let i = 0; i <= minNumberOfLines; i++) {
|
|
await logger.log(4, 'your waifu is trash');
|
|
const currLogFileSize = (await fs.stat(logger.getLogFile())).size;
|
|
const sizeIncrease = currLogFileSize - prevLogFileSize;
|
|
if (sizeIncrease) {
|
|
sizeIncreases.push(sizeIncrease);
|
|
minNumberOfLines = maxLogSize / (sizeIncreases.reduce((sum, e) => sum + e, 0) / sizeIncreases.length);
|
|
}
|
|
prevLogFileSize = currLogFileSize;
|
|
}
|
|
|
|
const logFileStats = await fs.stat(logger.getLogFile());
|
|
expect(logFileStats.size).lessThan(maxLogSize, 'log is bigger than its max size');
|
|
}).timeout(15000);
|
|
|
|
it("exception log file doesn't get bigger than 50KB @slow", async () => {
|
|
const logger: LoggerInterface = container.get('logger');
|
|
|
|
let prevLogFileSize = (await fs.stat(logger.getExceptionsLogFile())).size;
|
|
let minNumberOfLines = maxLogSize;
|
|
const sizeIncreases = [];
|
|
for (let i = 0; i <= minNumberOfLines; i++) {
|
|
await logger.exception(new Error('your waifu is trash'));
|
|
const currLogFileSize = (await fs.stat(logger.getExceptionsLogFile())).size;
|
|
const sizeIncrease = currLogFileSize - prevLogFileSize;
|
|
if (sizeIncrease) {
|
|
sizeIncreases.push(sizeIncrease);
|
|
minNumberOfLines = maxLogSize / (sizeIncreases.reduce((sum, e) => sum + e, 0) / sizeIncreases.length);
|
|
}
|
|
prevLogFileSize = currLogFileSize;
|
|
}
|
|
|
|
const logFileStats = await fs.stat(logger.getExceptionsLogFile());
|
|
expect(logFileStats.size).lessThan(maxLogSize, 'exception log is bigger than its max size');
|
|
}).timeout(15000);
|
|
|
|
it('logs different levels directly', () => {
|
|
const logger: LoggerInterface = container.get('logger');
|
|
|
|
return fc.assert(
|
|
fc.asyncProperty(logLevelArbitrary as LogLevelArbitrary, fc.string(), async (logLevel, message) => {
|
|
await logger[logLevel](message);
|
|
const lastLine = await getLastLine(getDefaultLogReadLineInterface(logger));
|
|
expect(lastLine).contains(message, 'the log line does not contain the message');
|
|
expect(lastLine).contains(logLevel, `the log line does not contain the '${logLevel}' keyword`);
|
|
}),
|
|
{
|
|
numRuns: 50,
|
|
}
|
|
);
|
|
});
|
|
|
|
it('logs different levels indirectly via the generic log function', () => {
|
|
const logger: LoggerInterface = container.get('logger');
|
|
|
|
return fc.assert(
|
|
fc.asyncProperty(logLevelNumberArbitrary, fc.string(), async (logLevelNumber, message) => {
|
|
await logger.log(logLevelNumber, message);
|
|
const lastLine = await getLastLine(getDefaultLogReadLineInterface(logger));
|
|
expect(lastLine).contains(message, 'the log line does not contain the message');
|
|
expect(lastLine).contains(
|
|
logLevels[logLevelNumber],
|
|
`the log line does not contain the '${logLevels[logLevelNumber]}' keyword`
|
|
);
|
|
}),
|
|
{
|
|
numRuns: 50,
|
|
}
|
|
);
|
|
});
|
|
|
|
it('logs debug only in dev mode', async () => {
|
|
const logger: LoggerInterface = container.get('logger');
|
|
|
|
setDev();
|
|
await logger.debug('this is a development message');
|
|
const lastLine = await getLastLine(getDefaultLogReadLineInterface(logger));
|
|
expect(lastLine).contains('this is a development message', 'the dev log line does not contain the message');
|
|
expect(lastLine).contains('debug', `the dev log line does not contain the 'debug' keyword`);
|
|
setDev(false);
|
|
await logger.log(LogLevel.warning, 'this is a warning');
|
|
await logger.debug('this is a second development message, should not be here');
|
|
expect(lastLine).not.contain(
|
|
'this is a second development message, should not be here',
|
|
'debug is logged even in non-dev mode'
|
|
);
|
|
});
|
|
});
|