skutter
Version:
Skutter: Opinionated BDD Browser based test framework
123 lines (122 loc) • 6.36 kB
JavaScript
;
const Lazy = require("lazy.js");
const executor_proxy_factory_1 = require("../services/executor-proxy-factory");
const executor_message_listener_1 = require("./executor-message-listener");
const even_distributor_1 = require("../services/even-distributor");
const file_checker_1 = require("../services/file-checker");
const result_aggregator_1 = require("../result-aggregator/result-aggregator");
const feature_result_factory_1 = require("../services/feature-result-factory");
const feature_info_provider_1 = require("../services/feature-info-provider");
const just_filter_1 = require("./filters/just-filter");
const exclude_filter_1 = require("./filters/exclude-filter");
const only_filter_1 = require("./filters/only-filter");
const exit_codes_1 = require("../exit-codes");
const ireporter_registration_context_1 = require("../reporters/ireporter-registration-context");
const threadCompletionDelay = 500;
class Orchestrator {
constructor(config) {
if (!config) {
throw new Error("config is not specified.");
}
this.config = config;
this.results = [];
}
start(features, reporters = []) {
if (!features || features.length === 0) {
throw new Error("No features to run.");
}
if (!reporters || reporters.length === 0) {
throw new Error("No reporters specified.");
}
if (just_filter_1.JustFilter.apply(features)) {
console.log("@Just tag discovered.");
if (this.config.failAtJustRuns) {
let exitCode = exit_codes_1.ExitCodes.AtJustViolation;
console.log(`Exiting with code: ${exitCode}, @just applied to an executable feature and this is explicitly disallowed by the failAtJust config value.`);
process.exit(exitCode);
return;
}
}
if (exclude_filter_1.ExcludeFilter.apply(this.config.filters, features)) {
console.log("Features reduced due to exclude filters.");
}
if (only_filter_1.OnlyFilter.apply(this.config.filters, features)) {
console.log("Features reduced due to only filters.");
}
let queuedFeatures = Lazy(features).where((feature) => { return feature.queued; }).size();
if (queuedFeatures === 0) {
let exitCode = exit_codes_1.ExitCodes.NothingToRun;
console.log(`Exiting with code: ${exitCode}, No features are queued to be executed. This may indicate an unrequired filter is set.`);
process.exit(exitCode);
return;
}
let executorCount = Math.min(queuedFeatures, this.config.numExecutors);
console.log(`${executorCount} executor${executorCount > 1 ? "s" : ""} processing ${queuedFeatures} feature${queuedFeatures > 1 ? "s" : ""}.`);
let executorBootstrapScript = `${__dirname}\\..\\executor\\executor-bootstrap.js`;
if (!file_checker_1.FileChecker.exists(executorBootstrapScript)) {
throw new Error(`The required file 'executor-bootstrap.js' was not found at the expected location '${executorBootstrapScript}'.`);
}
let weightExtractorFn = (feature) => {
return 1;
};
let featureBuckets = even_distributor_1.EvenDistributor.distributeBasedOnContent(Lazy(features).where((feature) => { return feature.queued; }).toArray(), weightExtractorFn, executorCount);
let executors = [];
let executionPromises = [];
let reporterRegistrationContext = new ireporter_registration_context_1.ReporterRegistrationContext();
reporterRegistrationContext.executorsCount = executorCount;
reporters = Lazy(reporters).reject((reporter) => { return reporter.selfUnregister(reporterRegistrationContext); }).toArray();
let featureInfoProvider = new feature_info_provider_1.FeatureInfoProvider(features);
let featureResultProvider = new feature_result_factory_1.FeatureResultFactory();
let resultAggregator = new result_aggregator_1.ResultAggregator(featureInfoProvider, featureResultProvider, reporters);
let executorMessageListener = new executor_message_listener_1.ExecutorMessageListener(resultAggregator);
let executorProxyFactory = new executor_proxy_factory_1.ExecutorProxyFactory(executorMessageListener, this.config.executor, this.config.outputRootPath);
for (let reporter of reporters) {
try {
reporter.runStarting();
}
catch (exception) {
console.log("Errored during runStarting call. " + exception.message);
}
}
let debugPort = this.config.debugPort || 5999;
let nodeStartOpts = {
silent: true,
execArgv: executorCount === 1 ? [`--debug=${debugPort}`] : undefined
};
if (executorCount === 1) {
console.log(`Single thread debugging enabled on port ${debugPort}`);
}
for (let executorIndex = 0; executorIndex < executorCount; executorIndex++) {
let executorFeatures = featureBuckets[executorIndex];
let executor = executorProxyFactory.create(executorBootstrapScript, nodeStartOpts);
let executionPromise = executor.start(executorFeatures);
executionPromises.push(executionPromise);
executors.push(executor);
}
Promise.all(executionPromises)
.then(() => {
setTimeout(() => {
let runResults = resultAggregator.getResults();
let runErrors = resultAggregator.getErrors();
for (let reporter of reporters) {
try {
reporter.runCompleted(runResults, runErrors);
}
catch (exception) {
console.log("Errored during runCompleted call. " + exception.message);
}
}
}, threadCompletionDelay);
}, (error) => {
for (let reporter of reporters) {
try {
reporter.fatalError(error);
}
catch (exception) {
console.log("Errored during fatalError call. " + exception.message);
}
}
});
}
}
exports.Orchestrator = Orchestrator;