Skip to content

Commit

Permalink
test_runner: do not spawn run in child processes
Browse files Browse the repository at this point in the history
  • Loading branch information
koh110 committed Jul 20, 2023
1 parent c301404 commit 7db06c7
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 1 deletion.
12 changes: 11 additions & 1 deletion lib/internal/test_runner/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ const {
convertStringToRegExp,
countCompletedTest,
kDefaultPattern,
parseCommandLine,
} = require('internal/test_runner/utils');
const { Glob } = require('internal/fs/glob');
const { once } = require('events');
Expand Down Expand Up @@ -470,13 +471,22 @@ function run(options) {
}

const root = createTestTree({ concurrency, timeout, signal });
let postRun = () => root.postRun();

// don't spawn `run` in child processes to prevent infinite loops

Check failure on line 476 in lib/internal/test_runner/runner.js

View workflow job for this annotation

GitHub Actions / lint-js-and-md

Comments should not begin with a lowercase character
const { isChildProcess, isChildProcessV8 } = parseCommandLine()

Check failure on line 477 in lib/internal/test_runner/runner.js

View workflow job for this annotation

GitHub Actions / lint-js-and-md

Missing semicolon
if (isChildProcess || isChildProcessV8) {
PromisePrototypeThen(PromisePrototypeThen(PromiseResolve(setup?.(root)), []), postRun);

return root.reporter;
}

let testFiles = files ?? createTestFileList();

if (shard) {
testFiles = ArrayPrototypeFilter(testFiles, (_, index) => index % shard.total === shard.index - 1);
}

let postRun = () => root.postRun();
let filesWatcher;
if (watch) {
filesWatcher = watchFiles(testFiles, root, inspectPort, signal, testNamePatterns);
Expand Down
2 changes: 2 additions & 0 deletions lib/internal/test_runner/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,8 @@ function parseCommandLine() {
testNamePatterns,
reporters,
destinations,
isChildProcess,
isChildProcessV8,
};

return globalTestOptions;
Expand Down
3 changes: 3 additions & 0 deletions test/fixtures/test-runner/run_null_files/a.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import test from 'node:test';

test('this a should pass');
3 changes: 3 additions & 0 deletions test/fixtures/test-runner/run_null_files/b.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import test from 'node:test';

test('this b should pass');
16 changes: 16 additions & 0 deletions test/fixtures/test-runner/run_null_files/run.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { run } from 'node:test';
import assert from 'node:assert';
import { tap } from 'node:test/reporters';

const stream = run({
timeout: 1000
})
.compose(tap)
.pipe(process.stdout)

stream.on('test:fail', (f) => {
assert.ok(false)
});
stream.on('test:pass', (p) => {
assert.ok(false)
});
22 changes: 22 additions & 0 deletions test/fixtures/test-runner/run_self_path.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { run, test } from 'node:test';
import { fileURLToPath } from 'node:url';
import assert from 'node:assert';
import { tap } from 'node:test/reporters';

const stream = run({
files: [fileURLToPath(import.meta.url)],
timeout: 1000
})
.compose(tap)
.pipe(process.stdout)

stream.on('test:fail', (f) => {
assert.ok(false)
});
stream.on('test:pass', (p) => {
assert.ok(false)
});

test('1 + 1 = 2', async () => {
assert.strictEqual(1 + 1, 2, '1 + 1 = 2')
})
18 changes: 18 additions & 0 deletions test/parallel/test-runner-run.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as fixtures from '../common/fixtures.mjs';
import { join } from 'node:path';
import { describe, it, run } from 'node:test';
import { dot, spec, tap } from 'node:test/reporters';
import { execFileSync } from 'child_process';
import assert from 'node:assert';

const testFixtures = fixtures.path('test-runner');
Expand All @@ -17,6 +18,23 @@ describe('require(\'node:test\').run', { concurrency: true }, () => {
for await (const _ of stream);
});

it('should run without infinite loops (self path)', { timeout: 10000 }, async () => {
execFileSync(
process.execPath,
['--test', join(testFixtures, 'run_self_path.mjs')],
{ timeout: 10000, cwd: testFixtures }
);
});

it('should run without infinite loops (Default: files)', { timeout: 10000 }, async () => {
const cwd = join(testFixtures, 'run_null_files')

Check failure on line 30 in test/parallel/test-runner-run.mjs

View workflow job for this annotation

GitHub Actions / lint-js-and-md

Missing semicolon
execFileSync(
process.execPath,
['--test', join(cwd, 'run.mjs')],
{ timeout: 10000, cwd }
);
});

it('should fail with non existing file', async () => {
const stream = run({ files: ['a-random-file-that-does-not-exist.js'] });
stream.on('test:fail', common.mustCall(1));
Expand Down

0 comments on commit 7db06c7

Please sign in to comment.