UNPKG

stryker

Version:
218 lines 11.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var tslib_1 = require("tslib"); var path = require("path"); var log4js_1 = require("log4js"); var mkdirp = require("mkdirp"); var test_runner_1 = require("stryker-api/test_runner"); var objectUtils_1 = require("./utils/objectUtils"); var ResilientTestRunnerFactory_1 = require("./test-runner/ResilientTestRunnerFactory"); var TempFolder_1 = require("./utils/TempFolder"); var fileUtils_1 = require("./utils/fileUtils"); var TestableMutant_1 = require("./TestableMutant"); var report_1 = require("stryker-api/report"); var Sandbox = /** @class */ (function () { function Sandbox(options, index, files, testFramework, timeOverheadMS, loggingContext) { var _this = this; this.options = options; this.index = index; this.files = files; this.testFramework = testFramework; this.timeOverheadMS = timeOverheadMS; this.loggingContext = loggingContext; this.log = log4js_1.getLogger(Sandbox.name); this.retrieveEarlyResult = function (transpiledMutant) { if (transpiledMutant.transpileResult.error) { if (_this.log.isDebugEnabled()) { _this.log.debug("Transpile error occurred: \"" + transpiledMutant.transpileResult.error + "\" during transpiling of mutant " + transpiledMutant.mutant.toString()); } var result = transpiledMutant.mutant.result(report_1.MutantStatus.TranspileError, []); return result; } else if (!transpiledMutant.mutant.selectedTests.length) { var result = transpiledMutant.mutant.result(report_1.MutantStatus.NoCoverage, []); return result; } else if (!transpiledMutant.changedAnyTranspiledFiles) { var result = transpiledMutant.mutant.result(report_1.MutantStatus.Survived, []); return result; } else { // No early result possible, need to run in the sandbox later return null; } }; this.workingDirectory = TempFolder_1.TempFolder.instance().createRandomFolder('sandbox'); this.log.debug('Creating a sandbox for files in %s', this.workingDirectory); } Sandbox.prototype.initialize = function () { return tslib_1.__awaiter(this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.fillSandbox()]; case 1: _a.sent(); return [4 /*yield*/, this.symlinkNodeModulesIfNeeded()]; case 2: _a.sent(); return [2 /*return*/, this.initializeTestRunner()]; } }); }); }; Sandbox.create = function (options, index, files, testFramework, timeoutOverheadMS, loggingContext) { var sandbox = new Sandbox(options, index, files, testFramework, timeoutOverheadMS, loggingContext); return sandbox.initialize().then(function () { return sandbox; }); }; Sandbox.prototype.run = function (timeout, testHooks, mutatedFileName) { return this.testRunner.run({ timeout: timeout, testHooks: testHooks, mutatedFileName: mutatedFileName }); }; Sandbox.prototype.dispose = function () { return this.testRunner.dispose() || Promise.resolve(); }; Sandbox.prototype.runMutant = function (transpiledMutant) { return tslib_1.__awaiter(this, void 0, void 0, function () { var earlyResult, mutantFiles, runResult; var _this = this; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: earlyResult = this.retrieveEarlyResult(transpiledMutant); if (!earlyResult) return [3 /*break*/, 1]; return [2 /*return*/, earlyResult]; case 1: mutantFiles = transpiledMutant.transpileResult.outputFiles; if (transpiledMutant.mutant.testSelectionResult === TestableMutant_1.TestSelectionResult.Failed) { this.log.warn("Failed find coverage data for this mutant, running all tests. This might have an impact on performance: " + transpiledMutant.mutant.toString()); } return [4 /*yield*/, Promise.all(mutantFiles.map(function (mutatedFile) { return _this.writeFileInSandbox(mutatedFile); }))]; case 2: _a.sent(); return [4 /*yield*/, this.run(this.calculateTimeout(transpiledMutant.mutant), this.getFilterTestsHooks(transpiledMutant.mutant), this.fileMap[transpiledMutant.mutant.fileName])]; case 3: runResult = _a.sent(); return [4 /*yield*/, this.reset(mutantFiles)]; case 4: _a.sent(); return [2 /*return*/, this.collectMutantResult(transpiledMutant.mutant, runResult)]; } }); }); }; Sandbox.prototype.collectMutantResult = function (mutant, runResult) { var status = this.determineMutantState(runResult); var testNames = runResult.tests .filter(function (t) { return t.status !== test_runner_1.TestStatus.Skipped; }) .map(function (t) { return t.name; }); if (this.log.isDebugEnabled() && status === report_1.MutantStatus.RuntimeError) { var error = runResult.errorMessages ? runResult.errorMessages.toString() : '(undefined)'; this.log.debug('A runtime error occurred: %s during execution of mutant: %s', error, mutant.toString()); } return mutant.result(status, testNames); }; Sandbox.prototype.determineMutantState = function (runResult) { switch (runResult.status) { case test_runner_1.RunStatus.Timeout: return report_1.MutantStatus.TimedOut; case test_runner_1.RunStatus.Error: return report_1.MutantStatus.RuntimeError; case test_runner_1.RunStatus.Complete: if (runResult.tests.some(function (t) { return t.status === test_runner_1.TestStatus.Failed; })) { return report_1.MutantStatus.Killed; } else { return report_1.MutantStatus.Survived; } } }; Sandbox.prototype.reset = function (mutatedFiles) { var _this = this; var originalFiles = this.files.filter(function (originalFile) { return mutatedFiles.some(function (mutatedFile) { return mutatedFile.name === originalFile.name; }); }); return Promise.all(originalFiles.map(function (file) { return fileUtils_1.writeFile(_this.fileMap[file.name], file.content); })); }; Sandbox.prototype.writeFileInSandbox = function (file) { var fileNameInSandbox = this.fileMap[file.name]; return fileUtils_1.writeFile(fileNameInSandbox, file.content); }; Sandbox.prototype.fillSandbox = function () { var _this = this; this.fileMap = Object.create(null); var copyPromises = this.files .map(function (file) { return _this.fillFile(file); }); return Promise.all(copyPromises); }; Sandbox.prototype.symlinkNodeModulesIfNeeded = function () { return tslib_1.__awaiter(this, void 0, void 0, function () { var basePath, nodeModules_1; var _this = this; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: if (!this.options.symlinkNodeModules) return [3 /*break*/, 4]; basePath = process.cwd(); return [4 /*yield*/, fileUtils_1.findNodeModules(basePath)]; case 1: nodeModules_1 = _a.sent(); if (!nodeModules_1) return [3 /*break*/, 3]; return [4 /*yield*/, fileUtils_1.symlinkJunction(nodeModules_1, path.join(this.workingDirectory, 'node_modules')) .catch(function (error) { if (error.code === 'EEXIST') { _this.log.warn(objectUtils_1.normalizeWhiteSpaces("Could not symlink \"" + nodeModules_1 + "\" in sandbox directory,\n it is already created in the sandbox. Please remove the node_modules from your sandbox files.\n Alternatively, set `symlinkNodeModules` to `false` to disable this warning.")); } else { _this.log.warn("Unexpected error while trying to symlink \"" + nodeModules_1 + "\" in sandbox directory.", error); } })]; case 2: _a.sent(); return [3 /*break*/, 4]; case 3: this.log.warn("Could not find a node_modules folder to symlink into the sandbox directory. Search \"" + basePath + "\" and its parent directories"); _a.label = 4; case 4: return [2 /*return*/]; } }); }); }; Sandbox.prototype.fillFile = function (file) { var relativePath = path.relative(process.cwd(), file.name); var folderName = path.join(this.workingDirectory, path.dirname(relativePath)); mkdirp.sync(folderName); var targetFile = path.join(folderName, path.basename(relativePath)); this.fileMap[file.name] = targetFile; return fileUtils_1.writeFile(targetFile, file.content); }; Sandbox.prototype.initializeTestRunner = function () { return tslib_1.__awaiter(this, void 0, void 0, function () { var fileNames; var _this = this; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: fileNames = Object.keys(this.fileMap).map(function (sourceFileName) { return _this.fileMap[sourceFileName]; }); this.log.debug("Creating test runner %s", this.index); this.testRunner = ResilientTestRunnerFactory_1.default.create(this.options, fileNames, this.workingDirectory, this.loggingContext); return [4 /*yield*/, this.testRunner.init()]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }; Sandbox.prototype.calculateTimeout = function (mutant) { var baseTimeout = mutant.timeSpentScopedTests; return (this.options.timeoutFactor * baseTimeout) + this.options.timeoutMS + this.timeOverheadMS; }; Sandbox.prototype.getFilterTestsHooks = function (mutant) { if (this.testFramework) { return objectUtils_1.wrapInClosure(this.testFramework.filter(mutant.selectedTests)); } else { return undefined; } }; return Sandbox; }()); exports.default = Sandbox; //# sourceMappingURL=Sandbox.js.map