Skip to content

Commit 04fdc3e

Browse 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

4 files changed

Lines changed: 43 additions & 21 deletions

File tree

‎lib/internal/test_runner/harness.js‎

Lines 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+
constisTestRunner=getOptionValue('--test');
1920
consttestResources=newSafeMap();
2021
constroot=newTest({__proto__: null,name: '<root>'});
2122
letwasRootSetup=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();
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
consttest=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));
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
consttest=require('node:test');
2+
3+
test('never ending test',()=>{
4+
while(true);
5+
});

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

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,29 @@
22
constcommon=require('../common');
33
constfixtures=require('../common/fixtures');
44
constassert=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+
asyncfunctionrunAndKill(file){
10+
if(common.isWindows){
11+
common.printSkipMessage(`signals are not supported in windows, skipping ${file}`);
12+
return;
13+
}
14+
letstdout='';
15+
constchild=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]=awaitonce(child,'exit');
22+
awaitfinished(child.stdout);
23+
assert.match(stdout,/notok1/);
24+
assert.match(stdout,/#cancelled1\n/);
25+
assert.strictEqual(signal,null);
26+
assert.strictEqual(code,1);
27+
}
728

829
if(process.argv[2]==='child'){
930
consttest=require('node:test');
@@ -17,12 +38,6 @@ if (process.argv[2] === 'child') {
1738
test('failing test',()=>{
1839
assert.strictEqual(true,false);
1940
});
20-
}elseif(process.argv[3]==='never_ends'){
21-
assert.strictEqual(process.argv[3],'never_ends');
22-
test('never ending test',()=>{
23-
returnsetTimeout(100_000_000);
24-
});
25-
process.kill(process.pid,'SIGINT');
2641
}elseassert.fail('unreachable');
2742
}else{
2843
letchild=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-
conststdout=child.stdout.toString();
47-
assert.match(stdout,/notok1-neverendingtest/);
48-
assert.match(stdout,/#cancelled1/);
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)