Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 04fdc3e

Browse filesBrowse files
MoLowruyadorno
authored andcommitted
test_runner: graceful termination on --test only
PR-URL: #43977 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Nitzan Uziely <linkgoron@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
1 parent 72a9ecf commit 04fdc3e
Copy full SHA for 04fdc3e

File tree

Expand file treeCollapse file tree

4 files changed

+43
-21
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

4 files changed

+43
-21
lines changed
Open diff view settings
Collapse file

‎lib/internal/test_runner/harness.js‎

Copy file name to clipboardExpand all lines: lib/internal/test_runner/harness.js
+7-3Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ const {
1313
ERR_TEST_FAILURE,
1414
},
1515
} = require('internal/errors');
16+
const { getOptionValue } = require('internal/options');
1617
const { Test, ItTest, Suite } = require('internal/test_runner/test');
1718

18-
19+
const isTestRunner = getOptionValue('--test');
1920
const testResources = new SafeMap();
2021
const root = new Test({ __proto__: null, name: '<root>' });
2122
let wasRootSetup = false;
@@ -134,8 +135,11 @@ function setup(root) {
134135
process.on('uncaughtException', exceptionHandler);
135136
process.on('unhandledRejection', rejectionHandler);
136137
process.on('beforeExit', exitHandler);
137-
process.on('SIGINT', terminationHandler);
138-
process.on('SIGTERM', terminationHandler);
138+
// TODO(MoLow): Make it configurable to hook when isTestRunner === false.
139+
if (isTestRunner) {
140+
process.on('SIGINT', terminationHandler);
141+
process.on('SIGTERM', terminationHandler);
142+
}
139143

140144
root.reporter.pipe(process.stdout);
141145
root.reporter.version();
Collapse file
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
const test = require('node:test');
2+
const { setTimeout } = require('timers/promises');
3+
4+
// We are using a very large timeout value to ensure that the parent process
5+
// will have time to send a SIGINT signal to cancel the test.
6+
test('never ending test', () => setTimeout(100_000_000));
Collapse file
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const test = require('node:test');
2+
3+
test('never ending test', () => {
4+
while (true);
5+
});
Collapse file

‎test/parallel/test-runner-exit-code.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-runner-exit-code.js
+25-18Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,29 @@
22
const common = require('../common');
33
const fixtures = require('../common/fixtures');
44
const assert = require('assert');
5-
const { spawnSync } = require('child_process');
6-
const { setTimeout } = require('timers/promises');
5+
const { spawnSync, spawn } = require('child_process');
6+
const { once } = require('events');
7+
const { finished } = require('stream/promises');
8+
9+
async function runAndKill(file) {
10+
if (common.isWindows) {
11+
common.printSkipMessage(`signals are not supported in windows, skipping ${file}`);
12+
return;
13+
}
14+
let stdout = '';
15+
const child = spawn(process.execPath, ['--test', file]);
16+
child.stdout.setEncoding('utf8');
17+
child.stdout.on('data', (chunk) => {
18+
if (!stdout.length) child.kill('SIGINT');
19+
stdout += chunk;
20+
});
21+
const [code, signal] = await once(child, 'exit');
22+
await finished(child.stdout);
23+
assert.match(stdout, /not ok 1/);
24+
assert.match(stdout, /# cancelled 1\n/);
25+
assert.strictEqual(signal, null);
26+
assert.strictEqual(code, 1);
27+
}
728

829
if (process.argv[2] === 'child') {
930
const test = require('node:test');
@@ -17,12 +38,6 @@ if (process.argv[2] === 'child') {
1738
test('failing test', () => {
1839
assert.strictEqual(true, false);
1940
});
20-
} else if (process.argv[3] === 'never_ends') {
21-
assert.strictEqual(process.argv[3], 'never_ends');
22-
test('never ending test', () => {
23-
return setTimeout(100_000_000);
24-
});
25-
process.kill(process.pid, 'SIGINT');
2641
} else assert.fail('unreachable');
2742
} else {
2843
let child = spawnSync(process.execPath, [__filename, 'child', 'pass']);
@@ -37,14 +52,6 @@ if (process.argv[2] === 'child') {
3752
assert.strictEqual(child.status, 1);
3853
assert.strictEqual(child.signal, null);
3954

40-
child = spawnSync(process.execPath, [__filename, 'child', 'never_ends']);
41-
assert.strictEqual(child.status, 1);
42-
assert.strictEqual(child.signal, null);
43-
if (common.isWindows) {
44-
common.printSkipMessage('signals are not supported in windows');
45-
} else {
46-
const stdout = child.stdout.toString();
47-
assert.match(stdout, /not ok 1 - never ending test/);
48-
assert.match(stdout, /# cancelled 1/);
49-
}
55+
runAndKill(fixtures.path('test-runner', 'never_ending_sync.js')).then(common.mustCall());
56+
runAndKill(fixtures.path('test-runner', 'never_ending_async.js')).then(common.mustCall());
5057
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.