RenaiApp/src/main/modules/logger/logger.spec.ts

142 lines
4.7 KiB
TypeScript

import rewiremock from 'rewiremock';
import '../../../../mocks/electron';
import chai, { expect } from 'chai';
import 'mocha';
import { container } from '../../core/container';
import { setDev } from '../../core/env.spec';
import { ILogger } from './i-logger';
import fs from 'fs-extra';
import { createInterface, Interface } from 'readline';
import fc from 'fast-check';
import { LogLevel } from './log-level';
import chaiFs from 'chai-fs';
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: ILogger) {
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 byte
const maxLogSize = 50000;
type LogLevelArbitrary = fc.Arbitrary<'fatal' | 'error' | 'warning' | 'notice' | 'info'>;
const logLevelArbitrary = fc.constantFrom(...logLevels);
const logLevelNumberArbitrary = fc.constantFrom(...logLevelsNumber);
before(() => {
rewiremock.enable();
});
after(() => {
rewiremock.disable();
});
it('creates log files', () => {
const logger: ILogger = 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: ILogger = 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: ILogger = container.get('logger');
for (let i = 0; i < maxLogSize; i++) {
await logger.log(4, 'your waifu is trash');
}
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: ILogger = container.get('logger');
for (let i = 0; i < maxLogSize; ++i) {
await logger.exception(new Error('your waifu is trash'));
}
const logFileStats = await fs.stat(logger.getLogFile());
expect(logFileStats.size).lessThan(maxLogSize, 'log is bigger than its max size');
}).timeout(15000);
it('logs different levels directly', () => {
const logger: ILogger = 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: ILogger = 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: ILogger = 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'
);
});
});