Skip to content

Commit

Permalink
feat: graceful termination on --test only
Browse files Browse the repository at this point in the history
PR-URL: nodejs/node#43977
Reviewed-By: Antoine du Hamel <[email protected]>
Reviewed-By: Nitzan Uziely <[email protected]>
Reviewed-By: Benjamin Gruenbaum <[email protected]>
(cherry picked from commit 26e27424ad91c60a44d3d4c58b62a39b555ba75d)
  • Loading branch information
MoLow authored and aduh95 committed Jul 27, 2022
1 parent f875da2 commit 4071052
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 26 deletions.
11 changes: 8 additions & 3 deletions lib/internal/test_runner/harness.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// https://github.com/nodejs/node/blob/1523a1817ed9b06fb51c0149451f9ea31bd2756e/lib/internal/test_runner/harness.js
// https://github.com/nodejs/node/blob/26e27424ad91c60a44d3d4c58b62a39b555ba75d/lib/internal/test_runner/harness.js
'use strict'
const {
ArrayPrototypeForEach,
Expand All @@ -14,8 +14,10 @@ const {
ERR_TEST_FAILURE
}
} = require('#internal/errors')
const { getOptionValue } = require('#internal/options')
const { Test, ItTest, Suite } = require('#internal/test_runner/test')

const isTestRunner = getOptionValue('--test')
const testResources = new SafeMap()
const root = new Test({ __proto__: null, name: '<root>' })
let wasRootSetup = false
Expand Down Expand Up @@ -136,8 +138,11 @@ function setup (root) {
process.on('uncaughtException', exceptionHandler)
process.on('unhandledRejection', rejectionHandler)
process.on('beforeExit', exitHandler)
process.on('SIGINT', terminationHandler)
process.on('SIGTERM', terminationHandler)
// TODO(MoLow): Make it configurable to hook when isTestRunner === false.
if (isTestRunner) {
process.on('SIGINT', terminationHandler)
process.on('SIGTERM', terminationHandler)
}

root.reporter.pipe(process.stdout)
root.reporter.version()
Expand Down
4 changes: 3 additions & 1 deletion test/common/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,5 +143,7 @@ if (process.version.startsWith('v14.') || process.version.startsWith('v16.')) {
}

module.exports = {
expectsError
expectsError,
isWindow: process.platform === 'win32',
mustCall
}
7 changes: 7 additions & 0 deletions test/fixtures/test-runner/never_ending_async.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// https://github.com/nodejs/node/blob/26e27424ad91c60a44d3d4c58b62a39b555ba75d/test/fixtures/test-runner/never_ending_async.js
const test = require('#node:test')
const { setTimeout } = require('#timers/promises')

// We are using a very large timeout value to ensure that the parent process
// will have time to send a SIGINT signal to cancel the test.
test('never ending test', () => setTimeout(100_000_000))
6 changes: 6 additions & 0 deletions test/fixtures/test-runner/never_ending_sync.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// https://github.com/nodejs/node/blob/26e27424ad91c60a44d3d4c58b62a39b555ba75d/test/fixtures/test-runner/never_ending_sync.js
const test = require('#node:test')

test('never ending test', () => {
while (true);
})
48 changes: 26 additions & 22 deletions test/parallel/test-runner-exit-code.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,31 @@
// https://github.com/nodejs/node/blob/2fd4c013c221653da2a7921d08fe1aa96aaba504/test/parallel/test-runner-exit-code.js

// https://github.com/nodejs/node/blob/26e27424ad91c60a44d3d4c58b62a39b555ba75d/test/parallel/test-runner-exit-code.js
'use strict'

const common = require('../common')
const fixtures = require('../common/fixtures')
const assert = require('assert')
const { spawnSync } = require('child_process')
const { promisify } = require('util')
const setTimeout = promisify(require('timers').setTimeout)
const { spawnSync, spawn } = require('child_process')
const { once } = require('events')
const finished = require('util').promisify(require('stream').finished)

async function runAndKill (file) {
if (common.isWindows) {
common.printSkipMessage(`signals are not supported in windows, skipping ${file}`)
return
}
let stdout = ''
const child = spawn(process.execPath, ['--test', file])
child.stdout.setEncoding('utf8')
child.stdout.on('data', (chunk) => {
if (!stdout.length) child.kill('SIGINT')
stdout += chunk
})
const [code, signal] = await once(child, 'exit')
await finished(child.stdout)
assert.match(stdout, /not ok 1/)
assert.match(stdout, /# cancelled 1\n/)
assert.strictEqual(signal, null)
assert.strictEqual(code, 1)
}

if (process.argv[2] === 'child') {
const test = require('#node:test')
Expand All @@ -21,12 +39,6 @@ if (process.argv[2] === 'child') {
test('failing test', () => {
assert.strictEqual(true, false)
})
} else if (process.argv[3] === 'never_ends') {
assert.strictEqual(process.argv[3], 'never_ends')
test('never ending test', () => {
return setTimeout(100_000_000)
})
process.kill(process.pid, 'SIGINT')
} else assert.fail('unreachable')
} else {
let child = spawnSync(process.execPath, [__filename, 'child', 'pass'])
Expand All @@ -41,14 +53,6 @@ if (process.argv[2] === 'child') {
assert.strictEqual(child.status, 1)
assert.strictEqual(child.signal, null)

child = spawnSync(process.execPath, [__filename, 'child', 'never_ends'])
assert.strictEqual(child.status, 1)
assert.strictEqual(child.signal, null)
if (common.isWindows) {
common.printSkipMessage('signals are not supported in windows')
} else {
const stdout = child.stdout.toString()
assert.match(stdout, /not ok 1 - never ending test/)
assert.match(stdout, /# cancelled 1/)
}
runAndKill(fixtures.path('test-runner', 'never_ending_sync.js')).then(common.mustCall())
runAndKill(fixtures.path('test-runner', 'never_ending_async.js')).then(common.mustCall())
}

0 comments on commit 4071052

Please sign in to comment.