Skip to content

Commit

Permalink
fix(stryker-init): Stryker init won't create temp folder (#361)
Browse files Browse the repository at this point in the history
* Refactor `StrykerTempFolder` to a class using a singleton
* Add `initialize` method for the actual initialization of the folder.
* Rename `StrykerTempFolder` -> `TempFolder`
* Add unit tests for TempFolder
  • Loading branch information
sharikovvladislav authored and nicojs committed Sep 3, 2017
1 parent be2cc17 commit a4333c9
Show file tree
Hide file tree
Showing 11 changed files with 243 additions and 111 deletions.
6 changes: 3 additions & 3 deletions packages/stryker/src/Mutant.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Location, Range } from 'stryker-api/core';
import StrykerTempFolder from './utils/StrykerTempFolder';
import { TempFolder } from './utils/TempFolder';
import { TestResult, RunResult } from 'stryker-api/test_runner';

/**
Expand Down Expand Up @@ -75,15 +75,15 @@ export default class Mutant {
* @function
*/
save(filename: string) {
return StrykerTempFolder.writeFile(filename, this.mutatedCode);
return TempFolder.instance().writeFile(filename, this.mutatedCode);
}

/**
* Removes the mutated file.
* @function
*/
reset(filename: string) {
return StrykerTempFolder.writeFile(filename, this.originalCode);
return TempFolder.instance().writeFile(filename, this.originalCode);
}

toString() {
Expand Down
12 changes: 6 additions & 6 deletions packages/stryker/src/Sandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import TestRunnerDecorator from './isolated-runner/TestRunnerDecorator';
import { isOnlineFile } from './utils/fileUtils';
import ResilientTestRunnerFactory from './isolated-runner/ResilientTestRunnerFactory';
import IsolatedRunnerOptions from './isolated-runner/IsolatedRunnerOptions';
import StrykerTempFolder from './utils/StrykerTempFolder';
import { TempFolder } from './utils/TempFolder';
import Mutant from './Mutant';
import CoverageInstrumenter from './coverage/CoverageInstrumenter';

Expand All @@ -29,7 +29,7 @@ export default class Sandbox {
private testHooksFile: string;

constructor(private options: Config, private index: number, private files: InputFile[], private testFramework: TestFramework | null, private coverageInstrumenter: CoverageInstrumenter | null) {
this.workingFolder = StrykerTempFolder.createRandomFolder('sandbox');
this.workingFolder = TempFolder.instance().createRandomFolder('sandbox');
log.debug('Creating a sandbox for files in %s', this.workingFolder);
this.testHooksFile = path.join(this.workingFolder, '___testHooksForStryker.js');
}
Expand Down Expand Up @@ -60,9 +60,9 @@ export default class Sandbox {
let copyPromises = this.files
.map(file => this.copyFile(file));
if (this.coverageInstrumenter) {
copyPromises.push(StrykerTempFolder.writeFile(this.testHooksFile, this.coverageInstrumenter.hooksForTestRun()));
copyPromises.push(TempFolder.instance().writeFile(this.testHooksFile, this.coverageInstrumenter.hooksForTestRun()));
} else {
copyPromises.push(StrykerTempFolder.writeFile(this.testHooksFile, ''));
copyPromises.push(TempFolder.instance().writeFile(this.testHooksFile, ''));
}
return Promise.all(copyPromises);
}
Expand All @@ -80,7 +80,7 @@ export default class Sandbox {
this.fileMap[file.path] = targetFile;
const instrumentingStream = this.coverageInstrumenter ?
this.coverageInstrumenter.instrumenterStreamForFile(file) : null;
return StrykerTempFolder.copyFile(file.path, targetFile, instrumentingStream);
return TempFolder.instance().copyFile(file.path, targetFile, instrumentingStream);
}
}

Expand All @@ -106,7 +106,7 @@ export default class Sandbox {
private filterTests(mutant: Mutant) {
if (this.testFramework) {
let fileContent = wrapInClosure(this.testFramework.filter(mutant.scopedTestIds));
return StrykerTempFolder.writeFile(this.testHooksFile, fileContent);
return TempFolder.instance().writeFile(this.testHooksFile, fileContent);
} else {
return Promise.resolve(void 0);
}
Expand Down
5 changes: 3 additions & 2 deletions packages/stryker/src/Stryker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import ScoreResultCalculator from './ScoreResultCalculator';
import ConfigValidator from './ConfigValidator';
import CoverageInstrumenter from './coverage/CoverageInstrumenter';
import { freezeRecursively, isPromise } from './utils/objectUtils';
import StrykerTempFolder from './utils/StrykerTempFolder';
import { TempFolder } from './utils/TempFolder';
import * as log4js from 'log4js';
import Timer from './utils/Timer';
import StrictReporter from './reporters/StrictReporter';
Expand Down Expand Up @@ -70,6 +70,7 @@ export default class Stryker {
this.timer.reset();

const inputFiles = await new InputFileResolver(this.config.mutate, this.config.files).resolve();
TempFolder.instance().initialize();
const { runResult, sandboxCoordinator } = await this.initialTestRun(inputFiles);

if (runResult.tests.length === 0) {
Expand All @@ -81,7 +82,7 @@ export default class Stryker {
this.reporter.onScoreCalculated(score);
ScoreResultCalculator.determineExitCode(score, this.config.thresholds);
await this.wrapUpReporter();
await StrykerTempFolder.clean();
await TempFolder.instance().clean();
await this.logDone();
return mutantResults;
} else {
Expand Down
78 changes: 0 additions & 78 deletions packages/stryker/src/utils/StrykerTempFolder.ts

This file was deleted.

95 changes: 95 additions & 0 deletions packages/stryker/src/utils/TempFolder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import * as fs from 'mz/fs';
import * as path from 'path';
import * as mkdirp from 'mkdirp';
import * as log4js from 'log4js';
import { deleteDir } from './fileUtils';

const log = log4js.getLogger('TempFolder');

export class TempFolder {
baseTempFolder: string;
tempFolder: string;

private constructor() { }

initialize(tempDirName = '.stryker-tmp') {
this.baseTempFolder = path.join(process.cwd(), tempDirName);
this.tempFolder = path.join(this.baseTempFolder, this.random().toString());
mkdirp.sync(this.baseTempFolder);
mkdirp.sync(this.tempFolder);
}

/**
* Creates a new random folder with the specified prefix.
* @param prefix The prefix.
* @returns The path to the folder.
*/
createRandomFolder(prefix: string): string {
if (!this.baseTempFolder) {
throw new Error('initialize() was not called!');
}
let dir = this.baseTempFolder + path.sep + prefix + this.random();
mkdirp.sync(dir);
return dir;
}

/**
* Writes data to a specified file.
* @param filename The path to the file.
* @param data The content of the file.
* @returns A promise to eventually save the file.
*/
writeFile(filename: string, data: string): Promise<void> {
return fs.writeFile(filename, data, { encoding: 'utf8' });
}

/**
* Copies a file.
* @param fromFilename The path to the existing file.
* @param toFilename The path to copy the file to.
* @param instrumenter An optional additional instrumenter to stream the file through
* @returns A promise to eventually copy the file.
*/
copyFile(fromFilename: string, toFilename: string, instrumenter: NodeJS.ReadWriteStream | null): Promise<void> {
return new Promise<void>((resolve, reject) => {
let readStream: NodeJS.ReadableStream = fs.createReadStream(fromFilename, { encoding: 'utf8' });
let writeStream = fs.createWriteStream(toFilename);
readStream.on('error', reject);
writeStream.on('error', reject);
if (instrumenter) {
readStream = readStream.pipe(instrumenter);
}
readStream.pipe(writeStream);
readStream.on('end', () => resolve());
});
}

/**
* Deletes the Stryker-temp folder
*/
clean() {
if (!this.baseTempFolder) {
throw new Error('initialize() was not called!');
}
log.debug(`Deleting stryker temp folder ${this.baseTempFolder}`);
return deleteDir(this.baseTempFolder)
.catch(() => log.info(`Failed to delete stryker temp folder ${this.baseTempFolder}`));
}

/**
* Creates a random integer number.
* @returns A random integer.
*/
random(): number {
return Math.ceil(Math.random() * 10000000);
}

private static _instance: TempFolder;
static instance() {
if (!this._instance) {
this._instance = new TempFolder();
}
return this._instance;
}
}

2 changes: 2 additions & 0 deletions packages/stryker/test/helpers/producers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export type Mock<T> = {
[P in keyof T]: sinon.SinonStub;
};

export function mock<T>(constructorFn: { new(...args: any[]): T; }): Mock<T>;
export function mock<T>(constructorFn: any): Mock<T>;
export function mock<T>(constructorFn: { new(...args: any[]): T; }): Mock<T> {
return sinon.createStubInstance(constructorFn) as Mock<T>;
}
Expand Down
9 changes: 6 additions & 3 deletions packages/stryker/test/unit/MutantSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import Mutant from '../../src/Mutant';
import { Location } from 'stryker-api/core';
import * as parserUtils from '../../src/utils/parserUtils';
import * as sinon from 'sinon';
import StrykerTempFolder from '../../src/utils/StrykerTempFolder';
import { TempFolder } from '../../src/utils/TempFolder';
import * as estree from 'estree';
import { Mock, mock } from '../helpers/producers';

describe('Mutant', () => {
let sut: Mutant;
Expand All @@ -19,11 +20,13 @@ describe('Mutant', () => {
let ast: estree.Program;
let node: estree.Node;
let sandbox: sinon.SinonSandbox;
let tempFolderMock: Mock<TempFolder>;

beforeEach(() => {

sandbox = sinon.sandbox.create();
sandbox.stub(StrykerTempFolder, 'writeFile');
tempFolderMock = mock(TempFolder);
sandbox.stub(TempFolder, 'instance').returns(tempFolderMock);

const baseCode = 'var i = 1 + 2;\n';
originalLine = 'var j = i * 2;';
Expand Down Expand Up @@ -103,7 +106,7 @@ describe('Mutant', () => {
const code = expectedMutatedLines + restOfCode;
// Some empty lines are needed. These are not allowed to contain spaces
sut.save('a file');
expect(StrykerTempFolder.writeFile).to.have.been.calledWith('a file', code);
expect(tempFolderMock.writeFile).to.have.been.calledWith('a file', code);
});

it('should set the correct originalLines', () => {
Expand Down
13 changes: 8 additions & 5 deletions packages/stryker/test/unit/MutatorOrchestratorSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,23 @@ import MutatorOrchestrator from '../../src/MutatorOrchestrator';
import { Mutator, MutatorFactory, IdentifiedNode, Identified } from 'stryker-api/mutant';
import * as sinon from 'sinon';
import { Syntax } from 'esprima';
import StrykerTempFolder from '../../src/utils/StrykerTempFolder';
import { TempFolder } from '../../src/utils/TempFolder';
import * as estree from 'estree';
import StrictReporter from '../../src/reporters/StrictReporter';
import { reporterStub } from '../helpers/producers';
import { Mock, mock } from '../helpers/producers';

describe('MutatorOrchestrator', () => {
let sut: MutatorOrchestrator;
let fileUtilsStub: sinon.SinonStub;
let sandbox: sinon.SinonSandbox;
let reporter: StrictReporter;
let tempFolderMock: Mock<TempFolder>;

beforeEach(() => {
sandbox = sinon.sandbox.create();
sandbox.stub(StrykerTempFolder, 'writeFile');
tempFolderMock = mock<TempFolder>(TempFolder);
sandbox.stub(TempFolder, 'instance').returns(tempFolderMock);
reporter = reporterStub();
sut = new MutatorOrchestrator(reporter);
});
Expand Down Expand Up @@ -57,7 +60,7 @@ describe('MutatorOrchestrator', () => {

it('should be able to mutate code', () => {
mutants[0].save('some file');
expect(StrykerTempFolder.writeFile).to.have.been.calledWith('some file', mutatedCode);
expect(tempFolderMock.writeFile).to.have.been.calledWith('some file', mutatedCode);
});

it('should set the mutated line number', () => {
Expand Down Expand Up @@ -116,7 +119,7 @@ describe('MutatorOrchestrator', () => {

let mutants = sut.generateMutants(['src.js']);
mutants[0].save('some file');
expect(StrykerTempFolder.writeFile).to.have.been.calledWith('some file', 'if (true);');
expect(tempFolderMock.writeFile).to.have.been.calledWith('some file', 'if (true);');
});

it('a different nodeID', () => {
Expand All @@ -126,7 +129,7 @@ describe('MutatorOrchestrator', () => {

let mutants = sut.generateMutants(['src.js']);
mutants[0].save('some file');
expect(StrykerTempFolder.writeFile).to.have.been.calledWith('some file', '1 * 2');
expect(tempFolderMock.writeFile).to.have.been.calledWith('some file', '1 * 2');
});
});

Expand Down
Loading

0 comments on commit a4333c9

Please sign in to comment.