@stryker-mutator/core
Version:
The extendable JavaScript mutation testing framework
87 lines • 5.1 kB
JavaScript
import { errorToString } from '@stryker-mutator/util';
import { expect } from 'chai';
import { factory, assertions } from '@stryker-mutator/test-helpers';
import { ChildProcessCrashedError } from '../../../src/child-proxy/child-process-crashed-error.js';
import { OutOfMemoryError } from '../../../src/child-proxy/out-of-memory-error.js';
import { RetryRejectedDecorator } from '../../../src/test-runner/retry-rejected-decorator.js';
import { TestRunnerDecorator } from '../../../src/test-runner/test-runner-decorator.js';
import { currentLogMock } from '../../helpers/log-mock.js';
describe(RetryRejectedDecorator.name, () => {
let sut;
let testRunner1;
let testRunner2;
let availableTestRunners;
let logMock;
const crashedError = new ChildProcessCrashedError(42, '');
beforeEach(() => {
testRunner1 = factory.testRunner();
testRunner2 = factory.testRunner();
logMock = currentLogMock();
availableTestRunners = [testRunner1, testRunner2];
sut = new RetryRejectedDecorator(() => { var _a; return (_a = availableTestRunners.shift()) !== null && _a !== void 0 ? _a : factory.testRunner(); });
});
it('should not override `init`', () => {
expect(sut.init).to.be.eq(TestRunnerDecorator.prototype.init);
});
it('should not override `dispose`', () => {
expect(sut.dispose).to.be.eq(TestRunnerDecorator.prototype.dispose);
});
describeRun('dryRun', (suite, options) => suite.dryRun(options), () => factory.dryRunOptions({ timeout: 23 }), () => factory.completeDryRunResult());
describeRun('mutantRun', (suite, options) => suite.mutantRun(options), () => factory.mutantRunOptions({ timeout: 23 }), () => factory.survivedMutantRunResult());
function describeRun(runMethod, act, optionsFactory, resultFactory) {
describe(runMethod, () => {
let options;
let expectedResult;
beforeEach(() => {
options = optionsFactory();
expectedResult = resultFactory();
});
it('should pass through resolved values', async () => {
// @ts-expect-error TS isn't smart enough
testRunner1[runMethod].resolves(expectedResult);
const result = await act(sut, options);
expect(testRunner1[runMethod]).to.have.been.calledWith(options);
expect(result).to.eq(expectedResult);
});
it('should retry on a new test runner if a run is rejected', async () => {
testRunner1[runMethod].rejects(new Error('Error'));
// @ts-expect-error TS isn't smart enough
testRunner2[runMethod].resolves(expectedResult);
const result = await act(sut, options);
expect(result).to.eq(expectedResult);
});
it('should retry if a `ChildProcessCrashedError` occurred reject appears', async () => {
testRunner1[runMethod].rejects(crashedError);
// @ts-expect-error TS isn't smart enough
testRunner2[runMethod].resolves(expectedResult);
const result = await act(sut, options);
expect(result).to.eq(expectedResult);
});
it('should log and retry when an `OutOfMemoryError` occurred.', async () => {
testRunner1[runMethod].rejects(new OutOfMemoryError(123, 123));
// @ts-expect-error TS isn't smart enough
testRunner2[runMethod].resolves(expectedResult);
const result = await act(sut, options);
expect(result).to.eq(expectedResult);
expect(logMock.info).calledWith("Test runner process [%s] ran out of memory. You probably have a memory leak in your tests. Don't worry, Stryker will restart the process, but you might want to investigate this later, because this decreases performance.", 123);
});
it('should dispose a test runner when it rejected, before creating a new one', async () => {
testRunner1[runMethod].rejects(crashedError);
// @ts-expect-error TS isn't smart enough
testRunner2[runMethod].resolves(expectedResult);
await act(sut, options);
expect(testRunner1.dispose).calledBefore(testRunner2.init);
});
it('should retry at most 1 times before rejecting', async () => {
const finalError = new Error('foo');
testRunner1[runMethod].rejects(new Error('bar'));
testRunner2[runMethod].rejects(finalError);
const result = await act(sut, options);
assertions.expectErrored(result);
expect(result.errorMessage).to.be.deep.eq(`Test runner crashed. Tried twice to restart it without any luck. Last time the error message was: ${errorToString(finalError)}`);
expect(availableTestRunners).to.have.lengthOf(0);
});
});
}
});
//# sourceMappingURL=retry-rejected-decorator.spec.js.map