|
|
|
'use strict';
|
|
|
|
|
|
|
|
// This test makes sure that when throwing an error from a domain, and then
|
|
|
|
// handling that error in an uncaughtException handler by throwing an error
|
|
|
|
// again, the exit code, signal and error messages are the ones we expect with
|
|
|
|
// and without using --abort-on-uncaught-exception.
|
|
|
|
|
|
|
|
const common = require('../common');
|
|
|
|
const assert = require('assert');
|
|
|
|
const child_process = require('child_process');
|
|
|
|
const domain = require('domain');
|
|
|
|
|
|
|
|
const uncaughtExceptionHandlerErrMsg = 'boom from uncaughtException handler';
|
|
|
|
const domainErrMsg = 'boom from domain';
|
|
|
|
|
|
|
|
const RAN_UNCAUGHT_EXCEPTION_HANDLER_EXIT_CODE = 42;
|
|
|
|
|
|
|
|
if (process.argv[2] === 'child') {
|
|
|
|
process.on('uncaughtException', common.mustCall(function onUncaught() {
|
|
|
|
if (process.execArgv.indexOf('--abort-on-uncaught-exception') !== -1) {
|
|
|
|
// When passing --abort-on-uncaught-exception to the child process,
|
|
|
|
// we want to make sure that this handler (the process' uncaughtException
|
|
|
|
// event handler) wasn't called. Unfortunately we can't parse the child
|
|
|
|
// process' output to do that, since on Windows the standard error output
|
|
|
|
// is not properly flushed in V8's Isolate::Throw right before the
|
|
|
|
// process aborts due to an uncaught exception, and thus the error
|
|
|
|
// message representing the error that was thrown cannot be read by the
|
|
|
|
// parent process. So instead of parsing the child process' stdandard
|
|
|
|
// error, the parent process will check that in the case
|
|
|
|
// --abort-on-uncaught-exception was passed, the process did not exit
|
|
|
|
// with exit code RAN_UNCAUGHT_EXCEPTION_HANDLER_EXIT_CODE.
|
|
|
|
process.exit(RAN_UNCAUGHT_EXCEPTION_HANDLER_EXIT_CODE);
|
|
|
|
} else {
|
|
|
|
// On the other hand, when not passing --abort-on-uncaught-exception to
|
|
|
|
// the node process, we want to throw in this event handler to make sure
|
|
|
|
// that the proper error message, exit code and signal are the ones we
|
|
|
|
// expect.
|
|
|
|
throw new Error(uncaughtExceptionHandlerErrMsg);
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
|
|
|
|
const d = domain.create();
|
|
|
|
d.run(common.mustCall(function() {
|
|
|
|
throw new Error(domainErrMsg);
|
|
|
|
}));
|
|
|
|
} else {
|
|
|
|
runTestWithoutAbortOnUncaughtException();
|
|
|
|
runTestWithAbortOnUncaughtException();
|
|
|
|
}
|
|
|
|
|
|
|
|
function runTestWithoutAbortOnUncaughtException() {
|
|
|
|
child_process.exec(
|
|
|
|
createTestCmdLine(),
|
|
|
|
function onTestDone(err, stdout, stderr) {
|
|
|
|
// When _not_ passing --abort-on-uncaught-exception, the process'
|
|
|
|
// uncaughtException handler _must_ be called, and thus the error
|
|
|
|
// message must include only the message of the error thrown from the
|
|
|
|
// process' uncaughtException handler.
|
|
|
|
assert(stderr.includes(uncaughtExceptionHandlerErrMsg),
|
|
|
|
'stderr output must include proper uncaughtException ' +
|
|
|
|
'handler\'s error\'s message');
|
|
|
|
assert(!stderr.includes(domainErrMsg),
|
|
|
|
'stderr output must not include domain\'s error\'s message');
|
|
|
|
|
|
|
|
assert.notStrictEqual(err.code, 0,
|
|
|
|
'child process should have exited with a ' +
|
|
|
|
'non-zero exit code, but did not');
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
function runTestWithAbortOnUncaughtException() {
|
|
|
|
child_process.exec(createTestCmdLine({
|
|
|
|
withAbortOnUncaughtException: true
|
|
|
|
}), function onTestDone(err, stdout, stderr) {
|
|
|
|
assert.notStrictEqual(err.code, RAN_UNCAUGHT_EXCEPTION_HANDLER_EXIT_CODE,
|
|
|
|
'child process should not have run its ' +
|
|
|
|
'uncaughtException event handler');
|
|
|
|
assert(common.nodeProcessAborted(err.code, err.signal),
|
|
|
|
'process should have aborted, but did not');
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function createTestCmdLine(options) {
|
|
|
|
let testCmd = '';
|
|
|
|
|
|
|
|
if (!common.isWindows) {
|
|
|
|
// Do not create core files, as it can take a lot of disk space on
|
|
|
|
// continuous testing and developers' machines
|
|
|
|
testCmd += 'ulimit -c 0 && ';
|
|
|
|
}
|
|
|
|
|
|
|
|
testCmd += process.argv[0];
|
|
|
|
|
|
|
|
if (options && options.withAbortOnUncaughtException) {
|
|
|
|
testCmd += ' ' + '--abort-on-uncaught-exception';
|
|
|
|
}
|
|
|
|
|
|
|
|
testCmd += ' ' + process.argv[1];
|
|
|
|
testCmd += ' ' + 'child';
|
|
|
|
|
|
|
|
return testCmd;
|
|
|
|
}
|