Skip to content
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"lines": 50,
"statements": 50,
"functions": 50,
"branches": 50,
"branches": 45,
"sourceMap": true,
"include": [
"packages/*/src/*.ts",
Expand Down
Empty file.
33 changes: 28 additions & 5 deletions packages/testring-logger/src/abstract-logger-client.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as util from 'util';
import { merge } from 'lodash';
import { transport } from '@testring/transport';
import { ITransport, ILogEntry, ILoggerClient, LoggerMessageTypes, LogTypes, LogLevel } from '@testring/types';

Expand All @@ -13,8 +14,8 @@ const formatLog = (logLevel: LogLevel, time: Date, content: Array<any>): string
export abstract class AbstractLoggerClient implements ILoggerClient {
constructor(
protected transportInstance: ITransport = transport,
protected logNesting: number = 0,
protected logLevel: LogLevel = LogLevel.info
protected logLevel: LogLevel = LogLevel.info,
protected logEnvironment?: any,
) {
}

Expand All @@ -35,7 +36,8 @@ export abstract class AbstractLoggerClient implements ILoggerClient {
protected buildEntry(
type: LogTypes,
content: Array<any>,
logLevel: LogLevel = this.logLevel
logLevel: LogLevel = this.logLevel,
logEnvironment: any = this.logEnvironment,
): ILogEntry {
const time = new Date();
const formattedMessage = formatLog(logLevel, time, content);
Expand All @@ -58,15 +60,17 @@ export abstract class AbstractLoggerClient implements ILoggerClient {
formattedMessage,
stepUid,
parentStep,
logEnvironment,
};
}

protected createLog(
type: LogTypes,
content: Array<any>,
logLevel: LogLevel = this.logLevel
logLevel: LogLevel = this.logLevel,
logEnvironment: any = this.logEnvironment,
): void {
const logEntry = this.buildEntry(type, content, logLevel);
const logEntry = this.buildEntry(type, content, logLevel, logEnvironment);

if (this.getCurrentStep()) {
this.logBatch.push(logEntry);
Expand Down Expand Up @@ -107,6 +111,21 @@ export abstract class AbstractLoggerClient implements ILoggerClient {
this.createLog(LogTypes.debug, args, LogLevel.debug);
}

public media(filename: string, content: Buffer): void {
this.createLog(LogTypes.media, [ filename, content ], LogLevel.info);
}

public withLogEnvironment(logEnvironment: any) {
return {
log: (...args) => this.createLog(LogTypes.log, args, LogLevel.info, logEnvironment),
info: (...args) => this.createLog(LogTypes.info, args, LogLevel.info, logEnvironment),
warn: (...args) => this.createLog(LogTypes.warning, args, LogLevel.warning, logEnvironment),
error: (...args) => this.createLog(LogTypes.error, args, LogLevel.error, logEnvironment),
debug: (...args) => this.createLog(LogTypes.debug, args, LogLevel.debug, logEnvironment),
media: (...args) => this.createLog(LogTypes.media, args, LogLevel.info, logEnvironment),
};
}

public startStep(message: string): void {
const step = nanoid();

Expand Down Expand Up @@ -137,4 +156,8 @@ export abstract class AbstractLoggerClient implements ILoggerClient {

this.endStep();
}

public setLogEnvironment(logEnvironment: object): void {
this.logEnvironment = merge(this.logEnvironment, logEnvironment);
}
}
81 changes: 80 additions & 1 deletion packages/testring-logger/test/logger-client.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import * as chai from 'chai';
import * as sinon from 'sinon';
import { TransportMock } from '@testring/test-utils';
import { LoggerMessageTypes, LogTypes } from '@testring/types';
import { LoggerMessageTypes, LogTypes, LogLevel } from '@testring/types';
import { LoggerClient } from '../src/logger-client';
import { report } from './fixtures/constants';

Expand Down Expand Up @@ -252,4 +252,83 @@ describe('Logger client', () => {
callback();
}, 0);
});

it('should allow to set logEnvironment which will be sent with every log', () => {
const logEnvironment = {
foo: 'bar',
};
const transport = new TransportMock();
const loggerClient = new LoggerClient(
transport,
LogLevel.verbose,
logEnvironment,
);

transport.on(
LoggerMessageTypes.REPORT,
(message) => {
chai.expect(message).to.have.deep.property('logEnvironment', logEnvironment);
}
);

loggerClient.log('foobar');
});


it('should allow to modify logEnvironment', () => {
const logEnvironment = {
foo: 'bar',
};
const logEnvironmentMod = {
baz: 'qux',
};
const transport = new TransportMock();
const loggerClient = new LoggerClient(
transport,
LogLevel.verbose,
logEnvironment,
);

transport.on(
LoggerMessageTypes.REPORT,
(message) => {
chai.expect(message)
.to.have.deep.property('logEnvironment', { ...logEnvironment, ...logEnvironmentMod });
}
);

loggerClient.setLogEnvironment(logEnvironmentMod);
loggerClient.log('foobar');
});

it('should should allow to log message with log environment without affecting instance logEnvironment', () => {
const logEnvironment = {
foo: 'bar',
};
const logEnvironmentMod = {
baz: 'qux',
};
const transport = new TransportMock();
const loggerClient = new LoggerClient(
transport,
LogLevel.verbose,
logEnvironment,
);

transport.on(
LoggerMessageTypes.REPORT,
(message) => {
if (message.type === LogTypes.debug) {
chai.expect(message)
.to.have.deep.property('logEnvironment', logEnvironmentMod);
} else {
chai.expect(message)
.to.have.deep.property('logEnvironment', logEnvironment);
}
}
);

loggerClient.withLogEnvironment(logEnvironmentMod).debug('modified');
loggerClient.log('unmodified');
});
});
16 changes: 14 additions & 2 deletions packages/testring-plugin-api/src/modules/test-run-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,19 @@ import { AbstractAPI } from './abstract';

export class TestRunControllerAPI extends AbstractAPI {

beforeRun(handler: (queue: Array<IQueuedTest>) => Array<IQueuedTest>) {
this.registrySyncPlugin(TestRunControllerHooks.beforeRun, handler);
beforeRun(handler: (queue: Array<IQueuedTest>) => Promise<IQueuedTest[]>) {
this.registryAsyncPlugin(TestRunControllerHooks.beforeRun, handler);
}

beforeTest(handler: (test: IQueuedTest) => Promise<void>) {
this.registryAsyncPlugin(TestRunControllerHooks.beforeTest, handler);
}

afterTest(handler: (params: IQueuedTest) => Promise<void>) {
this.registryAsyncPlugin(TestRunControllerHooks.afterTest, handler);
}

afterRun(handler: (queue: Array<IQueuedTest>) => Promise<void>) {
this.registryAsyncPlugin(TestRunControllerHooks.afterRun, handler);
}
}
22 changes: 18 additions & 4 deletions packages/testring-test-run-controller/src/test-run-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,34 @@ export class TestRunController extends PluggableModule implements ITestRunContro
) {
super([
TestRunControllerHooks.beforeRun,
TestRunControllerHooks.beforeTest,
TestRunControllerHooks.afterTest,
TestRunControllerHooks.afterRun,
]);
}

public async runQueue(testSet: Array<ITestFile>): Promise<Error[] | void> {
const testQueue = this.prepareTests(testSet);
const testQueueAfterHook = await this.callHook(TestRunControllerHooks.beforeRun, testQueue);

loggerClientLocal.debug('Run controller: tests queue created.');

const configWorkerLimit = this.config.workerLimit || 0;

const workerLimit = configWorkerLimit < testQueueAfterHook.length ?
configWorkerLimit :
testQueueAfterHook.length;

const workers = this.createWorkers(workerLimit);

loggerClientLocal.debug(`Run controller: ${workerLimit} worker(s) created.`);

try {
await Promise.all(
workers.map(worker => this.executeWorker(worker, testQueueAfterHook))
);

await this.callHook(TestRunControllerHooks.afterRun, testQueue);
} catch (e) {
loggerClientLocal.error(...this.errors);
throw e;
Expand All @@ -66,11 +74,11 @@ export class TestRunController extends PluggableModule implements ITestRunContro

private prepareTests(testFiles: Array<ITestFile>): Array<IQueuedTest> {
const testQueue = new Array(testFiles.length);
const retryCount = this.config.retryCount || 0;

for (let index = 0; index < testFiles.length; index++) {
testQueue[index] = {
retryCount: retryCount,
retryCount: 0,
retryErrors: [],
test: testFiles[index]
};
}
Expand All @@ -97,8 +105,8 @@ export class TestRunController extends PluggableModule implements ITestRunContro
throw exception.error;
}

if (test.retryCount > 0) {
test.retryCount--;
if (test.retryCount < (this.config.retryCount || 0)) {
test.retryCount++;

await delay(this.config.retryDelay || 0);

Expand All @@ -108,6 +116,8 @@ export class TestRunController extends PluggableModule implements ITestRunContro
} else {
this.errors.push(exception.error);

await this.callHook(TestRunControllerHooks.afterTest, test);

await this.occupyWorker(worker, queue);
}
}
Expand All @@ -120,8 +130,12 @@ export class TestRunController extends PluggableModule implements ITestRunContro
}

try {
await this.callHook(TestRunControllerHooks.beforeTest, queuedTest);
await worker.execute(queuedTest.test.content, queuedTest.test.path, queuedTest.test.meta);
await this.callHook(TestRunControllerHooks.afterTest, queuedTest);
} catch (error) {
queuedTest.retryErrors.push(error);

await this.onTestFailed(error, worker, queuedTest, queue);
} finally {
await this.occupyWorker(worker, queue);
Expand Down
2 changes: 2 additions & 0 deletions packages/testring-types/src/logger/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const enum LogTypes {
error = 'error',
debug = 'debug',
step = 'step',
media = 'media',
}

export const enum LogLevel {
Expand Down Expand Up @@ -40,6 +41,7 @@ export interface ILogEntry {
formattedMessage: string,
stepUid?: string,
parentStep: string | null,
logEnvironment?: any,
}

export interface ILoggerServer {
Expand Down
4 changes: 4 additions & 0 deletions packages/testring-types/src/test-run-controller/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ import { ITestFile } from '../test-finder';

export const enum TestRunControllerHooks {
beforeRun = 'beforeRun',
beforeTest = 'beforeTest',
afterTest = 'afterTest',
afterRun = 'afterRun',
}

export interface IQueuedTest {
retryCount: number,
retryErrors: Array<any>,
test: ITestFile
}

Expand Down