Skip to content

Commit

Permalink
Limited Process Pools (#791)
Browse files Browse the repository at this point in the history
New experimental `--concurrency` option. Note that `.only` behavior won't work reliably across test files when concurrency is limited.
  • Loading branch information
dcousineau authored and novemberborn committed May 12, 2016
1 parent 8ba3811 commit 1c3c86c
Show file tree
Hide file tree
Showing 8 changed files with 898 additions and 710 deletions.
103 changes: 94 additions & 9 deletions api.js
Expand Up @@ -116,6 +116,19 @@ Api.prototype._run = function (files, _options) {
self.precompiler = new CachingPrecompiler(cacheDir, self.options.babelConfig);
self.fileCount = files.length;

var overwatch;
if (this.options.concurrency > 0) {
overwatch = this._runLimitedPool(files, runStatus, self.options.serial ? 1 : this.options.concurrency);
} else {
// _runNoPool exists to preserve legacy behavior, specifically around `.only`
overwatch = this._runNoPool(files, runStatus);
}

return overwatch;
};

Api.prototype._runNoPool = function (files, runStatus) {
var self = this;
var tests = new Array(self.fileCount);

// TODO: thid should be cleared at the end of the run
Expand Down Expand Up @@ -154,15 +167,7 @@ Api.prototype._run = function (files, _options) {
file: path.relative('.', file)
});

return {
stats: {
passCount: 0,
skipCount: 0,
todoCount: 0,
failCount: 0
},
tests: []
};
return getBlankResults();
});
}));
}
Expand Down Expand Up @@ -224,3 +229,83 @@ Api.prototype._run = function (files, _options) {
return runStatus;
});
};

function getBlankResults() {
return {
stats: {
testCount: 0,
passCount: 0,
skipCount: 0,
todoCount: 0,
failCount: 0
},
tests: []
};
}

Api.prototype._runLimitedPool = function (files, runStatus, concurrency) {
var self = this;
var tests = {};

runStatus.on('timeout', function () {
Object.keys(tests).forEach(function (file) {
var fork = tests[file];
fork.exit();
});
});

return Promise.map(files, function (file) {
var handleException = function (err) {
runStatus.handleExceptions({
exception: err,
file: path.relative('.', file)
});
};

try {
var test = tests[file] = self._runFile(file, runStatus);

return new Promise(function (resolve, reject) {
var runner = function () {
self.emit('ready');
var options = {
// If we're looking for matches, run every single test process in exclusive-only mode
runOnlyExclusive: self.options.match.length > 0
};
test.run(options)
.then(resolve)
.catch(reject);
};

test.on('stats', runner);
test.on('exit', function () {
delete tests[file];
});
test.catch(runner);
}).catch(handleException);
} catch (err) {
handleException(err);
}
}, {concurrency: concurrency})
.then(function (results) {
// Filter out undefined results (usually result of caught exceptions)
results = results.filter(Boolean);

// cancel debounced _onTimeout() from firing
if (self.options.timeout) {
runStatus._restartTimer.cancel();
}

if (self.options.match.length > 0 && !runStatus.hasExclusive) {
// Ensure results are empty
results = [];
runStatus.handleExceptions({
exception: new AvaError('Couldn\'t find any matching tests'),
file: undefined
});
}

runStatus.processResults(results);
return runStatus;
});
};
32 changes: 18 additions & 14 deletions cli.js
Expand Up @@ -60,17 +60,18 @@ var cli = meow([
' ava [<file|directory|glob> ...]',
'',
'Options',
' --init Add AVA to your project',
' --fail-fast Stop after first test failure',
' --serial, -s Run tests serially',
' --require, -r Module to preload (Can be repeated)',
' --tap, -t Generate TAP output',
' --verbose, -v Enable verbose output',
' --no-cache Disable the transpiler cache',
' --match, -m Only run tests with matching title (Can be repeated)',
' --watch, -w Re-run tests when tests and source files change',
' --source, -S Pattern to match source files so tests can be re-run (Can be repeated)',
' --timeout, -T Set global timeout',
' --init Add AVA to your project',
' --fail-fast Stop after first test failure',
' --serial, -s Run tests serially',
' --require, -r Module to preload (Can be repeated)',
' --tap, -t Generate TAP output',
' --verbose, -v Enable verbose output',
' --no-cache Disable the transpiler cache',
' --match, -m Only run tests with matching title (Can be repeated)',
' --watch, -w Re-run tests when tests and source files change',
' --source, -S Pattern to match source files so tests can be re-run (Can be repeated)',
' --timeout, -T Set global timeout',
' --concurrency, -c Maximum number of test files running at the same time (EXPERIMENTAL)',
'',
'Examples',
' ava',
Expand All @@ -88,7 +89,8 @@ var cli = meow([
'require',
'timeout',
'source',
'match'
'match',
'concurrency'
],
boolean: [
'fail-fast',
Expand All @@ -106,7 +108,8 @@ var cli = meow([
m: 'match',
w: 'watch',
S: 'source',
T: 'timeout'
T: 'timeout',
c: 'concurrency'
}
});

Expand All @@ -133,7 +136,8 @@ var api = new Api({
explicitTitles: cli.flags.watch,
match: arrify(cli.flags.match),
babelConfig: conf.babel,
timeout: cli.flags.timeout
timeout: cli.flags.timeout,
concurrency: cli.flags.concurrency ? parseInt(cli.flags.concurrency, 10) : 0
});

var reporter;
Expand Down
23 changes: 12 additions & 11 deletions readme.md
Expand Up @@ -136,17 +136,18 @@ $ ava --help
ava [<file|directory|glob> ...]

Options
--init Add AVA to your project
--fail-fast Stop after first test failure
--serial, -s Run tests serially
--require, -r Module to preload (Can be repeated)
--tap, -t Generate TAP output
--verbose, -v Enable verbose output
--no-cache Disable the transpiler cache
--match, -m Only run tests with matching title (Can be repeated)
--watch, -w Re-run tests when tests and source files change
--source, -S Pattern to match source files so tests can be re-run (Can be repeated)
--timeout, -T Set global timeout
--init Add AVA to your project
--fail-fast Stop after first test failure
--serial, -s Run tests serially
--require, -r Module to preload (Can be repeated)
--tap, -t Generate TAP output
--verbose, -v Enable verbose output
--no-cache Disable the transpiler cache
--match, -m Only run tests with matching title (Can be repeated)
--watch, -w Re-run tests when tests and source files change
--source, -S Pattern to match source files so tests can be re-run (Can be repeated)
--timeout, -T Set global timeout
--concurrency, -c Maximum number of test files running at the same time (EXPERIMENTAL)

Examples
ava
Expand Down

0 comments on commit 1c3c86c

Please sign in to comment.