Skip to content

Commit

Permalink
refactor(Task): Refactor task to use Promise.race
Browse files Browse the repository at this point in the history
Don't reinvent the wheel
  • Loading branch information
nicojs committed Jul 24, 2018
1 parent dd2ee86 commit 91495dd
Show file tree
Hide file tree
Showing 7 changed files with 32 additions and 39 deletions.
12 changes: 8 additions & 4 deletions packages/stryker-mocha-runner/src/StrykerMochaReporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { getLogger } from 'stryker-api/logging';
import Timer from './Timer';

export default class StrykerMochaReporter {

private readonly log = getLogger(StrykerMochaReporter.name);
public runResult: RunResult;
private timer = new Timer();
Expand Down Expand Up @@ -36,7 +36,9 @@ export default class StrykerMochaReporter {
});
this.passedCount++;
this.timer.reset();
this.log.debug(`Test passed: ${test.fullTitle()}`);
if (this.log.isTraceEnabled()) {
this.log.trace(`Test passed: ${test.fullTitle()}`);
}
});

this.runner.on('fail', (test: any, err: any) => {
Expand All @@ -50,12 +52,14 @@ export default class StrykerMochaReporter {
this.runResult.errorMessages = [];
}
this.runResult.errorMessages.push(err.message);
this.log.debug(`Test failed: ${test.fullTitle()}. Error: ${err.message}`);
if (this.log.isTraceEnabled()) {
this.log.trace(`Test failed: ${test.fullTitle()}. Error: ${err.message}`);
}
});

this.runner.on('end', () => {
this.runResult.status = RunStatus.Complete;
this.log.debug(`Mocha test run completed: ${this.passedCount}/${this.runResult.tests.length} passed`);
this.log.debug('Mocha test run completed: %s/%s passed', this.passedCount, this.runResult.tests.length);
});
}
}
6 changes: 3 additions & 3 deletions packages/stryker/src/child-proxy/ChildProcessProxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { File } from 'stryker-api/core';
import { getLogger } from 'stryker-api/logging';
import { WorkerMessage, WorkerMessageKind, ParentMessage, autoStart, ParentMessageKind } from './messageProtocol';
import { serialize, deserialize, kill, isErrnoException } from '../utils/objectUtils';
import Task from '../utils/Task';
import { Task, ExpirableTask } from '../utils/Task';
import LoggingClientContext from '../logging/LoggingClientContext';
import StrykerError from '../utils/StrykerError';
import ChildProcessCrashedError from './ChildProcessCrashedError';
Expand All @@ -24,7 +24,7 @@ export default class ChildProcessProxy<T> {

private worker: ChildProcess;
private initTask: Task;
private disposeTask: Task<void> | undefined;
private disposeTask: ExpirableTask<void> | undefined;
private currentError: StrykerError | undefined;
private workerTasks: Task<any>[] = [];
private log = getLogger(ChildProcessProxy.name);
Expand Down Expand Up @@ -203,7 +203,7 @@ export default class ChildProcessProxy<T> {
kill(this.worker.pid);
this.isDisposed = true;
};
this.disposeTask = new Task(TIMEOUT_FOR_DISPOSE);
this.disposeTask = new ExpirableTask(TIMEOUT_FOR_DISPOSE);
this.send({ kind: WorkerMessageKind.Dispose });
return this.disposeTask.promise
.then(killWorker)
Expand Down
45 changes: 17 additions & 28 deletions packages/stryker/src/utils/Task.ts
Original file line number Diff line number Diff line change
@@ -1,59 +1,48 @@
import { sleep } from './objectUtils';

/**
* Wraps a promise in a Task api for convenience.
*/
export default class Task<T = void> {
export class Task<T = void> {

private _promise: Promise<T>;
protected _promise: Promise<T>;
private resolveFn: (value?: T | PromiseLike<T>) => void;
private rejectFn: (reason: any) => void;
private _isResolved = false;
private timeout: NodeJS.Timer;

constructor(timeoutMs?: number, private timeoutHandler?: () => PromiseLike<T>) {
constructor() {
this._promise = new Promise<T>((resolve, reject) => {
this.resolveFn = resolve;
this.rejectFn = reject;
});
if (timeoutMs) {
this.timeout = setTimeout(() => this.handleTimeout(), timeoutMs);
}
}

get isResolved() {
return this._isResolved;
}

get promise() {
return this._promise;
}

handleTimeout() {
if (this.timeoutHandler) {
this.timeoutHandler().then(val => this.resolve(val));
} else {
this.resolve(undefined);
}
}

chainTo(promise: Promise<T>) {
promise.then(value => this.resolve(value), reason => this.reject(reason));
get isResolved() {
return this._isResolved;
}

resolve(result: undefined | T | PromiseLike<T>) {
this.resolveTimeout();
this._isResolved = true;
this.resolveFn(result);
}

reject(reason: any) {
this.resolveTimeout();
this._isResolved = true;
this.rejectFn(reason);
}
}

private resolveTimeout() {
if (this.timeout) {
clearTimeout(this.timeout);
}
this._isResolved = true;
/**
* A task that can expire after the given time.
* If that happens, the inner promise is resolved
*/
export class ExpirableTask<T = void> extends Task<T | void> {
constructor(timeoutMS: number) {
super();
this._promise = Promise.race([this._promise, sleep(timeoutMS)]);
}
}
2 changes: 1 addition & 1 deletion packages/stryker/src/utils/objectUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export function kill(pid: number): Promise<void> {
});
}

export function sleep(ms: number) {
export function sleep(ms: number): Promise<void> {
return new Promise(res => {
setTimeout(res, ms);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { File, LogLevel } from 'stryker-api/core';
import { Logger } from 'stryker-api/logging';
import Echo from './Echo';
import ChildProcessProxy from '../../../src/child-proxy/ChildProcessProxy';
import Task from '../../../src/utils/Task';
import { Task } from '../../../src/utils/Task';
import LoggingServer from '../../helpers/LoggingServer';
import { filter } from 'rxjs/operators';
import { Mock } from '../../helpers/producers';
Expand Down
2 changes: 1 addition & 1 deletion packages/stryker/test/unit/SandboxPoolSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { File, LogLevel } from 'stryker-api/core';
import { TestFramework } from 'stryker-api/test_framework';
import Sandbox from '../../src/Sandbox';
import SandboxPool from '../../src/SandboxPool';
import Task from '../../src/utils/Task';
import { Task } from '../../src/utils/Task';
import '../helpers/globals';
import { Mock, config, file, mock, testFramework } from '../helpers/producers';
import LoggingClientContext from '../../src/logging/LoggingClientContext';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import ChildProcessProxy from '../../../src/child-proxy/ChildProcessProxy';
import LoggingClientContext from '../../../src/logging/LoggingClientContext';
import ChildProcessTestRunnerWorker from '../../../src/test-runner/ChildProcessTestRunnerWorker';
import TestRunnerDecorator from '../../../src/test-runner/TestRunnerDecorator';
import Task from '../../../src/utils/Task';
import { Task } from '../../../src/utils/Task';
import ChildProcessCrashedError from '../../../src/child-proxy/ChildProcessCrashedError';

describe(ChildProcessTestRunnerDecorator.name, () => {
Expand Down

0 comments on commit 91495dd

Please sign in to comment.