diff --git a/jest.config.js b/jest.config.js index 1995eb4..9cacd5a 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,6 +1,7 @@ module.exports = { preset: 'ts-jest', testEnvironment: 'node', + clearMocks : true, moduleFileExtensions: [ "ts", "js", diff --git a/package-lock.json b/package-lock.json index c2d7673..4214683 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3721,7 +3721,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -3742,12 +3743,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3762,17 +3765,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -3889,7 +3895,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -3901,6 +3908,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3915,6 +3923,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -3922,12 +3931,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -3946,6 +3957,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -4026,7 +4038,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -4038,6 +4051,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -4123,7 +4137,8 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -4159,6 +4174,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -4178,6 +4194,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -4221,12 +4238,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, diff --git a/src/type-declarations/winston-logstash-transport.d.ts b/src/type-declarations/winston-logstash-transport.d.ts index d95226c..1913caf 100644 --- a/src/type-declarations/winston-logstash-transport.d.ts +++ b/src/type-declarations/winston-logstash-transport.d.ts @@ -1,15 +1,14 @@ declare module 'winston-logstash-transport' { import * as Transport from 'winston-transport'; - import {TransportStreamOptions} from 'winston-transport'; - interface logstashTransportOptions extends TransportStreamOptions { + interface LogstashTransportOptions extends Transport.TransportStreamOptions { host?: string, port?: number, trailingLineFeed?: boolean, trailingLineFeedChar?: string } - export class LogstashTransport extends Transport{ - constructor({}: logstashTransportOptions) + export class LogstashTransport extends Transport { + constructor({}: LogstashTransportOptions) } } diff --git a/test/foo.test.ts b/test/foo.test.ts deleted file mode 100644 index c571fd9..0000000 --- a/test/foo.test.ts +++ /dev/null @@ -1,3 +0,0 @@ -test('adds 1 + 2 to equal 3', () => { - expect(1 + 2).toBe(3); -}); diff --git a/test/polaris-logger.test.ts b/test/polaris-logger.test.ts new file mode 100644 index 0000000..5205b86 --- /dev/null +++ b/test/polaris-logger.test.ts @@ -0,0 +1,121 @@ +import { Logger } from 'winston'; +import { LoggerConfiguration } from '../src/configurations/logger-configuration'; +import { ApplicationLogProperties } from '../src/entities'; +import { PolarisLogger } from '../src/polaris-logger'; +import { createLogger } from '../src/winston-logger'; + +const loggerImplMock: { [T in keyof Logger]: any } = { + fatal: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + info: jest.fn(), + debug: jest.fn(), + trace: jest.fn(), +} as any; +jest.mock('../src/winston-logger', () => { + return { + createLogger: jest.fn(() => { + return loggerImplMock; + }), + }; +}); + +describe('polaris-logger tests', () => { + const appProps: ApplicationLogProperties = { + id: 'p0laris-l0gs', + name: 'polaris-logs', + repositoryVersion: 'v1', + environment: 'environment', + component: 'component', + }; + const config: LoggerConfiguration = { + loggerLevel: 'info', + logstashHost: '127.0.0.1', + logstashPort: 8080, + }; + const message: string = 'log message'; + + test('creating a polaris logger with application properties and configuration - winston createLogger was called with configuration', () => { + const logger = new PolarisLogger(appProps, config); + + expect(createLogger).toHaveBeenCalledWith(config); + }); + + test('fatal - logging message - message and application properties are in the log', () => { + const logger = new PolarisLogger(appProps, config); + logger.fatal(message); + expect(loggerImplMock.fatal).toHaveBeenCalledWith({ + message, + component: appProps.component, + environment: appProps.environment, + repositoryVersion: appProps.repositoryVersion, + eventKindDescription: { systemId: appProps.id }, + system: { id: appProps.id, name: appProps.name }, + }); + }); + + test('error - logging message - message and application properties are in the log', () => { + const logger = new PolarisLogger(appProps, config); + logger.error(message); + expect(loggerImplMock.error).toHaveBeenCalledWith({ + message, + component: appProps.component, + environment: appProps.environment, + repositoryVersion: appProps.repositoryVersion, + eventKindDescription: { systemId: appProps.id }, + system: { id: appProps.id, name: appProps.name }, + }); + }); + + test('warn - logging message - message and application properties are in the log', () => { + const logger = new PolarisLogger(appProps, config); + logger.warn(message); + expect(loggerImplMock.warn).toHaveBeenCalledWith({ + message, + component: appProps.component, + environment: appProps.environment, + repositoryVersion: appProps.repositoryVersion, + eventKindDescription: { systemId: appProps.id }, + system: { id: appProps.id, name: appProps.name }, + }); + }); + + test('info - logging message - message and application properties are in the log', () => { + const logger = new PolarisLogger(appProps, config); + logger.info(message); + expect(loggerImplMock.info).toHaveBeenCalledWith({ + message, + component: appProps.component, + environment: appProps.environment, + repositoryVersion: appProps.repositoryVersion, + eventKindDescription: { systemId: appProps.id }, + system: { id: appProps.id, name: appProps.name }, + }); + }); + + test('debug - logging message - message and application properties are in the log', () => { + const logger = new PolarisLogger(appProps, config); + logger.debug(message); + expect(loggerImplMock.debug).toHaveBeenCalledWith({ + message, + component: appProps.component, + environment: appProps.environment, + repositoryVersion: appProps.repositoryVersion, + eventKindDescription: { systemId: appProps.id }, + system: { id: appProps.id, name: appProps.name }, + }); + }); + + test('trace - logging message - message and application properties are in the log', () => { + const logger = new PolarisLogger(appProps, config); + logger.trace(message); + expect(loggerImplMock.trace).toHaveBeenCalledWith({ + message, + component: appProps.component, + environment: appProps.environment, + repositoryVersion: appProps.repositoryVersion, + eventKindDescription: { systemId: appProps.id }, + system: { id: appProps.id, name: appProps.name }, + }); + }); +}); diff --git a/test/winston-logger.test.ts b/test/winston-logger.test.ts new file mode 100644 index 0000000..caaf8bd --- /dev/null +++ b/test/winston-logger.test.ts @@ -0,0 +1,226 @@ +import * as winston from 'winston'; +import * as DailyRotateFile from 'winston-daily-rotate-file'; +import { LogstashTransport } from 'winston-logstash-transport'; +import { LoggerConfiguration } from '../src/configurations/logger-configuration'; +import * as winstonLogger from '../src/winston-logger'; + +jest.mock('winston', () => { + return { + format: { + timestamp: jest.fn(), + align: jest.fn(), + printf: jest.fn(), + combine: jest.fn(), + json: jest.fn(), + colorize: jest.fn(), + }, + createLogger: jest.fn(() => ({ + add: jest.fn(), + })), + addColors: jest.fn(), + transports: { + File: jest.fn(), + Console: jest.fn(), + }, + }; +}); +jest.mock('winston-daily-rotate-file', () => { + return jest.fn().mockImplementation(() => ({ + DailyRotateFile: jest.fn(), + })); +}); +jest.mock('winston-logstash-transport', () => { + return { LogstashTransport: jest.fn() }; +}); + +describe('winston-logger tests', () => { + const loggerLevel: string = 'info'; + const logstashHost: string = 'test'; + const logstashPort: number = 8080; + const filePath: string = './temp/file-test.txt'; + const directoryPath: string = './temp/'; + const fileNamePrefix: string = 'rotate-file-test'; + const fileExtension: string = 'txt'; + const numberOfDaysToDeleteFile: number = 55; + + test('createLogger - basic configuration - creates the logger with basic configuration', () => { + const config: LoggerConfiguration = { + loggerLevel, + logstashHost, + logstashPort, + }; + + winstonLogger.createLogger(config); + + expect(winston.createLogger).toHaveBeenCalledWith( + expect.objectContaining({ + level: loggerLevel, + levels: { + debug: 4, + error: 1, + fatal: 0, + info: 3, + trace: 5, + warn: 2, + }, + exitOnError: false, + }), + ); + + expect(LogstashTransport).toHaveBeenCalledWith( + expect.objectContaining({ + host: logstashHost, + port: logstashPort, + }), + ); + }); + + test('createLogger - configuration with console writing - console transport have been called', () => { + const config: LoggerConfiguration = { + loggerLevel, + logstashHost, + logstashPort, + writeToConsole: true, + }; + + winstonLogger.createLogger(config); + + expect(winston.transports.Console).toHaveBeenCalled(); + }); + + test('createLogger - configuration with file writing - file transport have been called with configuration', () => { + const config: LoggerConfiguration = { + loggerLevel, + logstashHost, + logstashPort, + logFilePath: filePath, + }; + + winstonLogger.createLogger(config); + + expect(winston.transports.File).toHaveBeenCalledWith( + expect.objectContaining({ + filename: filePath, + }), + ); + }); + + test('createLogger - configuration with rotate file writing - rotate file transport have been called with configuration', () => { + const config: LoggerConfiguration = { + loggerLevel, + logstashHost, + logstashPort, + dailyRotateFileConfiguration: { + directoryPath, + fileNamePrefix, + fileExtension, + numberOfDaysToDeleteFile, + }, + }; + + winstonLogger.createLogger(config); + + expect(DailyRotateFile).toHaveBeenCalledWith( + expect.objectContaining({ + datePattern: 'DD-MM-YYYY', + filename: `${directoryPath}${fileNamePrefix}${'-%DATE%'}.${fileExtension}`, + maxFiles: `${numberOfDaysToDeleteFile}d`, + }), + ); + }); + + test('createLogger - configuration with default days for rotate file writing - rotate file transport have been called with default days', () => { + const config: LoggerConfiguration = { + loggerLevel, + logstashHost, + logstashPort, + dailyRotateFileConfiguration: { + directoryPath, + fileNamePrefix, + fileExtension, + }, + }; + + winstonLogger.createLogger(config); + + expect(DailyRotateFile).toHaveBeenCalledWith( + expect.objectContaining({ + maxFiles: '30d', + }), + ); + }); + + test('createLogger - configuration with console and file writing - both console and file transports have been called', () => { + const config: LoggerConfiguration = { + loggerLevel, + logstashHost, + logstashPort, + writeToConsole: true, + logFilePath: filePath, + }; + + winstonLogger.createLogger(config); + + expect(winston.transports.Console).toHaveBeenCalled(); + expect(winston.transports.File).toHaveBeenCalled(); + }); + + test('createLogger - configuration with console and rotate file writing - both console and rotate file transports have been called', () => { + const config: LoggerConfiguration = { + loggerLevel, + logstashHost, + logstashPort, + writeToConsole: true, + dailyRotateFileConfiguration: { + directoryPath, + fileNamePrefix, + fileExtension, + }, + }; + + winstonLogger.createLogger(config); + + expect(winston.transports.Console).toHaveBeenCalled(); + expect(DailyRotateFile).toHaveBeenCalled(); + }); + + test('createLogger - configuration with file and rotate file - only rotate file transport have been called', () => { + const config: LoggerConfiguration = { + loggerLevel, + logstashHost, + logstashPort, + logFilePath: filePath, + dailyRotateFileConfiguration: { + directoryPath, + fileNamePrefix, + fileExtension, + }, + }; + + winstonLogger.createLogger(config); + + expect(winston.transports.File).not.toHaveBeenCalled(); + expect(DailyRotateFile).toHaveBeenCalled(); + }); + + test('createLogger - configuration with console and file and rotate file writing - only console and rotate file transports have been called', () => { + const config: LoggerConfiguration = { + loggerLevel, + logstashHost, + logstashPort, + writeToConsole: true, + logFilePath: filePath, + dailyRotateFileConfiguration: { + directoryPath, + fileNamePrefix, + fileExtension, + }, + }; + + winstonLogger.createLogger(config); + + expect(winston.transports.Console).toHaveBeenCalled(); + expect(winston.transports.File).not.toHaveBeenCalled(); + expect(DailyRotateFile).toHaveBeenCalled(); + }); +});