Skip to content

Commit

Permalink
test_runner, cli: add --test-concurrency flag
Browse files Browse the repository at this point in the history
This commit adds a new --test-concurrency CLI flag that controls
the parallelism of the test runner CLI.

PR-URL: #49996
Fixes: #49487
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
  • Loading branch information
cjihrig authored and targos committed Nov 27, 2023
1 parent 54168b7 commit 428301a
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 6 deletions.
9 changes: 9 additions & 0 deletions doc/api/cli.md
Expand Up @@ -1298,6 +1298,15 @@ Starts the Node.js command line test runner. This flag cannot be combined with
See the documentation on [running tests from the command line][]
for more details.

### `--test-concurrency`

<!-- YAML
added: REPLACEME
-->

The maximum number of test files that the test runner CLI will execute
concurrently. The default value is `os.availableParallelism() - 1`.

### `--test-name-pattern`

<!-- YAML
Expand Down
12 changes: 7 additions & 5 deletions doc/api/test.md
Expand Up @@ -367,11 +367,12 @@ When searching for test files to execute, the test runner behaves as follows:
automatically executed by the test runner, but are supported if explicitly
provided on the command line.

Each matching test file is executed in a separate child process. If the child
process finishes with an exit code of 0, the test is considered passing.
Otherwise, the test is considered to be a failure. Test files must be
executable by Node.js, but are not required to use the `node:test` module
internally.
Each matching test file is executed in a separate child process. The maximum
number of child processes running at any time is controlled by the
[`--test-concurrency`][] flag. If the child process finishes with an exit code
of 0, the test is considered passing. Otherwise, the test is considered to be a
failure. Test files must be executable by Node.js, but are not required to use
the `node:test` module internally.

Each test file is executed as if it was a regular script. That is, if the test
file itself uses `node:test` to define tests, all of those tests will be
Expand Down Expand Up @@ -2449,6 +2450,7 @@ added: v18.7.0
[TAP]: https://testanything.org/
[TTY]: tty.md
[`--experimental-test-coverage`]: cli.md#--experimental-test-coverage
[`--test-concurrency`]: cli.md#--test-concurrency
[`--test-name-pattern`]: cli.md#--test-name-pattern
[`--test-only`]: cli.md#--test-only
[`--test-reporter-destination`]: cli.md#--test-reporter-destination
Expand Down
4 changes: 4 additions & 0 deletions doc/node.1
Expand Up @@ -400,6 +400,10 @@ Specify the minimum allocation from the OpenSSL secure heap. The default is 2. T
.It Fl -test
Starts the Node.js command line test runner.
.
.It Fl -test-concurrency
The maximum number of test files that the test runner CLI will execute
concurrently.
.
.It Fl -test-name-pattern
A regular expression that configures the test runner to only execute tests
whose name matches the provided pattern.
Expand Down
2 changes: 1 addition & 1 deletion lib/internal/main/test_runner.js
Expand Up @@ -21,7 +21,7 @@ const {
prepareMainThreadExecution(false);
markBootstrapComplete();

let concurrency = true;
let concurrency = getOptionValue('--test-concurrency') || true;
let inspectPort;

if (isUsingInspector()) {
Expand Down
3 changes: 3 additions & 0 deletions src/node_options.cc
Expand Up @@ -570,6 +570,9 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
AddOption("--test",
"launch test runner on startup",
&EnvironmentOptions::test_runner);
AddOption("--test-concurrency",
"specify test runner concurrency",
&EnvironmentOptions::test_runner_concurrency);
AddOption("--experimental-test-coverage",
"enable code coverage in the test runner",
&EnvironmentOptions::test_runner_coverage);
Expand Down
1 change: 1 addition & 0 deletions src/node_options.h
Expand Up @@ -156,6 +156,7 @@ class EnvironmentOptions : public Options {
std::string redirect_warnings;
std::string diagnostic_dir;
bool test_runner = false;
uint64_t test_runner_concurrency = 0;
bool test_runner_coverage = false;
std::vector<std::string> test_name_pattern;
std::vector<std::string> test_reporter;
Expand Down
45 changes: 45 additions & 0 deletions test/parallel/test-runner-cli-concurrency.js
@@ -0,0 +1,45 @@
'use strict';
const common = require('../common');
const tmpdir = require('../common/tmpdir');
const { deepStrictEqual, strictEqual } = require('node:assert');
const { spawnSync } = require('node:child_process');
const { readdirSync, writeFileSync } = require('node:fs');
const { join } = require('node:path');
const { beforeEach, test } = require('node:test');

function createTestFile(name) {
writeFileSync(join(tmpdir.path, name), `
const fs = require('node:fs');
fs.unlinkSync(__filename);
setTimeout(() => {}, 1_000_000_000);
`);
}

beforeEach(() => {
tmpdir.refresh();
createTestFile('test-1.js');
createTestFile('test-2.js');
});

test('concurrency of one', () => {
const cp = spawnSync(process.execPath, ['--test', '--test-concurrency=1'], {
cwd: tmpdir.path,
timeout: common.platformTimeout(1000),
});

strictEqual(cp.stderr.toString(), '');
strictEqual(cp.error.code, 'ETIMEDOUT');
deepStrictEqual(readdirSync(tmpdir.path), ['test-2.js']);
});

test('concurrency of two', () => {
const cp = spawnSync(process.execPath, ['--test', '--test-concurrency=2'], {
cwd: tmpdir.path,
timeout: common.platformTimeout(1000),
});

strictEqual(cp.stderr.toString(), '');
strictEqual(cp.error.code, 'ETIMEDOUT');
deepStrictEqual(readdirSync(tmpdir.path), []);
});

0 comments on commit 428301a

Please sign in to comment.