-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Exit with non-zero code when subprocess terminated by signal (#2023)
- Loading branch information
1 parent
a0ca1bd
commit 5aaca0d
Showing
5 changed files
with
56 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,39 +1,46 @@ | ||
const childProcess = require('child_process'); | ||
const path = require('path'); | ||
|
||
// Test that a signal sent to the parent process is received by the executable subcommand process (which is listening). | ||
const pmPath = path.join(__dirname, 'fixtures', 'pm'); | ||
|
||
// Disabling tests on Windows as: | ||
// Disabling some tests on Windows as: | ||
// "Windows does not support sending signals" | ||
// https://nodejs.org/api/process.html#process_signal_events | ||
const describeOrSkipOnWindows = (process.platform === 'win32') ? describe.skip : describe; | ||
|
||
// Note: the previous (sinon) test had custom code for SIGUSR1, revisit if required: | ||
// As described at https://nodejs.org/api/process.html#process_signal_events | ||
// this signal will start a debugger and thus the process might output an | ||
// additional error message: | ||
// "Failed to open socket on port 5858, waiting 1000 ms before retrying". | ||
describeOrSkipOnWindows('signals', () => { | ||
test.each(['SIGINT', 'SIGHUP', 'SIGTERM', 'SIGUSR1', 'SIGUSR2'])('when program sent %s then executableSubcommand sent signal too', (signal, done) => { | ||
// Spawn program. The listen subcommand waits for a signal and writes the name of the signal to stdout. | ||
const proc = childProcess.spawn(pmPath, ['listen'], {}); | ||
|
||
describeOrSkipOnWindows.each([['SIGINT'], ['SIGHUP'], ['SIGTERM'], ['SIGUSR1'], ['SIGUSR2']])( | ||
'test signal handling in executableSubcommand', (value) => { | ||
// Slightly tricky test, stick with callback and disable lint warning. | ||
// eslint-disable-next-line jest/no-done-callback | ||
test(`when command killed with ${value} then executableSubcommand receives ${value}`, (done) => { | ||
const pmPath = path.join(__dirname, './fixtures/pm'); | ||
let processOutput = ''; | ||
proc.stdout.on('data', (data) => { | ||
if (processOutput.length === 0) { | ||
// Send signal to program. | ||
proc.kill(`${signal}`); | ||
} | ||
processOutput += data.toString(); | ||
}); | ||
proc.on('close', (code) => { | ||
// Check the child subcommand received the signal too. | ||
expect(processOutput).toBe(`Listening for signal...${signal}`); | ||
done(); | ||
}); | ||
}); | ||
|
||
// The child process writes to stdout. | ||
const proc = childProcess.spawn(pmPath, ['listen'], {}); | ||
test('when executable subcommand sent signal then program exit code is non-zero', () => { | ||
const { status } = childProcess.spawnSync(pmPath, ['terminate'], {}); | ||
expect(status).toBeGreaterThan(0); | ||
}); | ||
|
||
let processOutput = ''; | ||
proc.stdout.on('data', (data) => { | ||
if (processOutput.length === 0) { | ||
proc.kill(`${value}`); | ||
} | ||
processOutput += data.toString(); | ||
}); | ||
proc.on('close', (code) => { | ||
expect(processOutput).toBe(`Listening for signal...${value}`); | ||
done(); | ||
}); | ||
}); | ||
test('when command has exitOverride and executable subcommand sent signal then exit code is non-zero', () => { | ||
const { status } = childProcess.spawnSync(pmPath, ['exit-override', 'terminate'], {}); | ||
expect(status).toBeGreaterThan(0); | ||
}); | ||
|
||
// Not a signal test, but closely related code so adding here. | ||
test('when command has exitOverride and executable subcommand fails then program exit code is subcommand exit code', () => { | ||
const { status } = childProcess.spawnSync(pmPath, ['exit-override', 'fail'], {}); | ||
expect(status).toEqual(42); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
process.exit(42); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
process.kill(process.pid, 'SIGINT'); |