Stryker

TestRunnerOrchestrator.js - Stryker report

Summary

File Based on all code Based on code coverage
TestRunnerOrchestrator.js
100%
104/104 100% 104/104

Code

"use strict";
var test_runner_1 = require('stryker-api/test_runner');
var StrykerTempFolder_1 = require('./utils/StrykerTempFolder');
var IsolatedTestRunnerAdapterFactory_1 = require('./isolated-runner/IsolatedTestRunnerAdapterFactory');
var path = require('path');
var os = require('os');
var _ = require('lodash');
var report_1 = require('stryker-api/report');
var log4js = require('log4js');
var objectUtils_1 = require('./utils/objectUtils');
var PromisePool = require('es6-promise-pool');
var log = log4js.getLogger('TestRunnerOrchestrator');
var TestRunnerOrchestrator = (function () 0{
    function TestRunnerOrchestrator(options, files, testSelector, reporter) 1{
        this.options = options;
        this.files = files;
        this.testSelector = testSelector;
        this.reporter = reporter;
    }

    TestRunnerOrchestrator.prototype.initialRun = function () 2{
        if (34this.testSelector) 5{
            return this.initialRunWithTestSelector();
        }

        else 6{
            return this.initalRunWithoutTestSelector();
        }

    };
    TestRunnerOrchestrator.prototype.initalRunWithoutTestSelector = function () 7{
        var testRunner = this.createTestRunner(this.files, true);
        return testRunner.run({ timeout: 10000 }).then(function (testResults) 8{
            testRunner.dispose();
            return [testResults];
        });
    };
    TestRunnerOrchestrator.prototype.initialRunWithTestSelector = function () 9{
        var testSelectionFilePath = this.createTestSelectorFileName(this.createTempFolder());
        var runnerAdapter = this.createTestRunner(this.files, true, testSelectionFilePath);
        var sandbox = {
            runnerAdapter: runnerAdapter,
            fileMap: null,
            testSelectionFilePath: testSelectionFilePath,
            index: 0
        };
        return this.runSingleTestsRecursive(sandbox, [], 0).then(function (testResults) 10{
            runnerAdapter.dispose();
            return testResults;
        });
    };
    TestRunnerOrchestrator.prototype.runMutations = function (mutants) 11{
        var _this = this;
        mutants = _.clone(mutants); // work with a copy because we're changing state (pop'ing values)
        var results = [];
        return this.createTestRunnerSandboxes().then(function (sandboxes) 12{
            var promiseProducer = function () 13{
                if (141516mutants.length === 0) 17{
                    return null; // we're done
                }

                else 18{
                    var mutant = mutants.pop();
                    if (19202122mutant.scopedTestIds.length > 0) 23{
                        var sandbox_1 = sandboxes.pop();
                        var sourceFileCopy_1 = sandbox_1.fileMap[mutant.filename];
                        return Promise.all([mutant.save(sourceFileCopy_1), _this.selectTestsIfPossible(sandbox_1, mutant.scopedTestIds)])
                            .then(function () 24{ return sandbox_1.runnerAdapter.run({ timeout: _this.calculateTimeout(mutant.timeSpentScopedTests) }); })
                            .then(function (runResult) 25{
                            var result = _this.collectFrozenMutantResult(mutant, runResult);
                            results.push(result);
                            _this.reporter.onMutantTested(result);
                            return mutant.reset(sourceFileCopy_1);
                        })
                            .then(function () 26{ return sandboxes.push(sandbox_1); }); // mark the runner as available again
                    }

                    else 27{
                        var result = _this.collectFrozenMutantResult(mutant);
                        results.push(result);
                        return Promise.resolve(_this.reporter.onMutantTested(result));
                    }

                }

            };
            return new PromisePool(promiseProducer, sandboxes.length)
                .start()
                .then(function () 28{ return sandboxes.forEach(function (testRunner) 29{ return testRunner.runnerAdapter.dispose(); }); })
                .then(function () 30{ return _this.reportAllMutantsTested(results); })
                .then(function () 31{ return results; });
        });
    };
    TestRunnerOrchestrator.prototype.reportAllMutantsTested = function (results) 32{
        objectUtils_1.freezeRecursively(results);
        this.reporter.onAllMutantsTested(results);
    };
    TestRunnerOrchestrator.prototype.calculateTimeout = function (baseTimeout) 33{
        return 34(35this.options.timeoutFactor * baseTimeout) + this.options.timeoutMs;
    };
    TestRunnerOrchestrator.prototype.collectFrozenMutantResult = function (mutant, runResult) 36{
        var status;
        var testNames;
        if (3738runResult) 39{
            switch (runResult.result) {
                case test_runner_1.TestResult.Timeout:
                    status = report_1.MutantStatus.TIMEDOUT;
                    break;
                case test_runner_1.TestResult.Error:
                    log.debug('Converting a test result `error` to mutant status `killed`.');
                    status = report_1.MutantStatus.KILLED;
                    break;
                case test_runner_1.TestResult.Complete:
                    if (40414243runResult.failed > 0) 44{
                        status = report_1.MutantStatus.KILLED;
                    }

                    else 45{
                        status = report_1.MutantStatus.SURVIVED;
                    }

                    break;
            }
            testNames = runResult.testNames;
        }

        else 46{
            testNames = [];
            status = report_1.MutantStatus.UNTESTED;
        }

        var result = {
            sourceFilePath: mutant.filename,
            mutatorName: mutant.mutatorName,
            status: status,
            replacement: mutant.replacement,
            location: mutant.location,
            range: mutant.range,
            testsRan: testNames,
            originalLines: mutant.originalLines,
            mutatedLines: mutant.mutatedLines,
        };
        objectUtils_1.freezeRecursively(result);
        return result;
    };
    TestRunnerOrchestrator.prototype.runSingleTestsRecursive = function (sandbox, runResults, currentTestIndex) 47{
        var _this = this;
        return new Promise(function (resolve) 48{
            _this.selectTestsIfPossible(sandbox, [currentTestIndex])
                .then(function () 49{ return sandbox.runnerAdapter.run({ timeout: 10000 }); })
                .then(function (runResult) 50{
                if (5152535455runResult.result === test_runner_1.TestResult.Complete && 5657runResult.succeeded > 0 || 5859runResult.failed > 0) 60{
                    runResults[currentTestIndex] = runResult;
                    resolve(_this.runSingleTestsRecursive(sandbox, runResults, 61currentTestIndex + 1));
                }

                else 62{
                    if (636465runResult.result !== test_runner_1.TestResult.Complete) 66{
                        // If this was iteration n+1 (n = number of tests), the runResult.result will be Complete, so we don't record it
                        runResults[currentTestIndex] = runResult;
                    }

                    sandbox.runnerAdapter.dispose();
                    resolve(runResults);
                }

            });
        });
    };
    TestRunnerOrchestrator.prototype.createTestRunnerSandboxes = function () 67{
        var cpuCount = os.cpus().length;
        var testRunnerSandboxes = [];
        var allPromises = [];
        log.info(6869"Creating " + cpuCount + " test runners (based on cpu count)");
        for (var i = 0; 707172i < cpuCount; 73i++) 74{
            allPromises.push(this.createSandbox(i).then(function (sandbox) 75{ return testRunnerSandboxes.push(sandbox); }));
        }

        return Promise.all(allPromises).then(function () 76{ return testRunnerSandboxes; });
    };
    TestRunnerOrchestrator.prototype.selectTestsIfPossible = function (sandbox, ids) 77{
        if (7879this.testSelector) 80{
            var fileContent = this.testSelector.select(ids);
            return StrykerTempFolder_1.default.writeFile(sandbox.testSelectionFilePath, fileContent);
        }

        else 81{
            return Promise.resolve(void 0);
        }

    };
    TestRunnerOrchestrator.prototype.createSandbox = function (index) 82{
        var _this = this;
        var tempFolder = this.createTempFolder();
        return this.copyAllFilesToFolder(tempFolder).then(function (fileMap) 83{
            var runnerFiles = [];
            var testSelectionFilePath = null;
            if (8485_this.testSelector) 86{
                testSelectionFilePath = _this.createTestSelectorFileName(tempFolder);
            }

            _this.files.forEach(function (originalFile) 87{ return runnerFiles.push({ path: fileMap[originalFile.path], shouldMutate: originalFile.shouldMutate }); });
            return {
                index: index,
                fileMap: fileMap,
                runnerAdapter: _this.createTestRunner(runnerFiles, false, testSelectionFilePath, index),
                testSelectionFilePath: testSelectionFilePath
            };
        });
    };
    TestRunnerOrchestrator.prototype.createTempFolder = function () 88{
        var tempFolder = StrykerTempFolder_1.default.createRandomFolder('test-runner-files');
        log.debug('Creating a sandbox for files in %s', tempFolder);
        return tempFolder;
    };
    TestRunnerOrchestrator.prototype.createTestSelectorFileName = function (folder) 89{
        return path.join(folder, '___testSelection.js');
    };
    TestRunnerOrchestrator.prototype.copyAllFilesToFolder = function (folder) 90{
        var _this = this;
        return new Promise(function (resolve, reject) 91{
            var fileMap = Object.create(null);
            var cwd = process.cwd();
            var copyPromises = _this.files.map(function (file) 92{
                var relativePath = file.path.substr(cwd.length);
                var folderName = StrykerTempFolder_1.default.ensureFolderExists(93folder + path.dirname(relativePath));
                var targetFile = path.join(folderName, path.basename(relativePath));
                fileMap[file.path] = targetFile;
                return StrykerTempFolder_1.default.copyFile(file.path, targetFile);
            });
            Promise.all(copyPromises).then(function () 94{ resolve(fileMap); }, reject);
        });
    };
    TestRunnerOrchestrator.prototype.createTestRunner = function (files, coverageEnabled, testSelectionFilePath, index) 95{
        if (969798index === void 0) 99{ index = 0; }

        if (100101testSelectionFilePath) 102{
            files = [{ path: testSelectionFilePath, shouldMutate: false }].concat(files);
        }

        var settings = {
            coverageEnabled: coverageEnabled,
            files: files,
            strykerOptions: this.options,
            port: 103this.options.port + index

        };
        log.debug("Creating test runner %s using settings {port: %s, coverageEnabled: %s}", index, settings.port, settings.coverageEnabled);
        return IsolatedTestRunnerAdapterFactory_1.default.create(settings);
    };
    return TestRunnerOrchestrator;
}());
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = TestRunnerOrchestrator;
//# sourceMappingURL=TestRunnerOrchestrator.js.map