mirror of https://github.com/lukechilds/node.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
215 lines
7.9 KiB
215 lines
7.9 KiB
// Copyright Joyent, Inc. and other Node contributors.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
// copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
|
// persons to whom the Software is furnished to do so, subject to the
|
|
// following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included
|
|
// in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
var assert = require('assert');
|
|
|
|
/*
|
|
* The goal of this test is to make sure that:
|
|
*
|
|
* - Even if --abort-on-uncaught-exception is passed on the command line,
|
|
* setting up a top-level domain error handler and throwing an error
|
|
* within this domain does *not* make the process abort. The process exits
|
|
* gracefully.
|
|
*
|
|
* - When passing --abort-on-uncaught-exception on the command line and
|
|
* setting up a top-level domain error handler, an error thrown
|
|
* within this domain's error handler *does* make the process abort.
|
|
*
|
|
* - When *not* passing --abort-on-uncaught-exception on the command line and
|
|
* setting up a top-level domain error handler, an error thrown within this
|
|
* domain's error handler does *not* make the process abort, but makes it exit
|
|
* with the proper failure exit code.
|
|
*
|
|
* - When throwing an error within the top-level domain's error handler
|
|
* within a try/catch block, the process should exit gracefully, whether or
|
|
* not --abort-on-uncaught-exception is passed on the command line.
|
|
*/
|
|
|
|
var domainErrHandlerExMessage = 'exception from domain error handler';
|
|
|
|
if (process.argv[2] === 'child') {
|
|
var domain = require('domain');
|
|
var d = domain.create();
|
|
var triggeredProcessUncaughtException = false;
|
|
|
|
process.on('uncaughtException', function onUncaughtException() {
|
|
// The process' uncaughtException event must not be emitted when
|
|
// an error handler is setup on the top-level domain.
|
|
// Exiting with exit code of 42 here so that it would assert when
|
|
// the parent checks the child exit code.
|
|
process.exit(42);
|
|
});
|
|
|
|
d.on('error', function() {
|
|
// Swallowing the error on purpose if 'throwInDomainErrHandler' is not
|
|
// set
|
|
if (process.argv.indexOf('throwInDomainErrHandler') !== -1) {
|
|
if (process.argv.indexOf('useTryCatch') !== -1) {
|
|
try {
|
|
throw new Error(domainErrHandlerExMessage);
|
|
} catch (e) {
|
|
}
|
|
} else {
|
|
throw new Error(domainErrHandlerExMessage);
|
|
}
|
|
}
|
|
});
|
|
|
|
d.run(function doStuff() {
|
|
// Throwing from within different types of callbacks as each of them
|
|
// handles domains differently
|
|
process.nextTick(function () {
|
|
throw new Error("Error from nextTick callback");
|
|
});
|
|
|
|
var fs = require('fs');
|
|
fs.exists('/non/existing/file', function onExists(exists) {
|
|
throw new Error("Error from fs.exists callback");
|
|
});
|
|
|
|
setImmediate(function onSetImmediate() {
|
|
throw new Error("Error from setImmediate callback");
|
|
});
|
|
|
|
throw new Error("Error from domain.run callback");
|
|
});
|
|
} else {
|
|
var exec = require('child_process').exec;
|
|
|
|
function testDomainExceptionHandling(cmdLineOption, options) {
|
|
if (typeof cmdLineOption === 'object') {
|
|
options = cmdLineOption;
|
|
cmdLineOption = undefined;
|
|
}
|
|
|
|
var throwInDomainErrHandlerOpt;
|
|
if (options.throwInDomainErrHandler)
|
|
throwInDomainErrHandlerOpt = 'throwInDomainErrHandler';
|
|
|
|
var cmdToExec = '';
|
|
if (process.platform !== 'win32') {
|
|
// Do not create core files, as it can take a lot of disk space on
|
|
// continuous testing and developers' machines
|
|
cmdToExec += 'ulimit -c 0 && ';
|
|
}
|
|
|
|
var useTryCatchOpt;
|
|
if (options.useTryCatch)
|
|
useTryCatchOpt = 'useTryCatch';
|
|
|
|
cmdToExec += process.argv[0] + ' ';
|
|
cmdToExec += (cmdLineOption ? cmdLineOption : '') + ' ';
|
|
cmdToExec += process.argv[1] + ' ';
|
|
cmdToExec += ['child', throwInDomainErrHandlerOpt, useTryCatchOpt].join(' ');
|
|
|
|
var child = exec(cmdToExec);
|
|
|
|
if (child) {
|
|
var childTriggeredOnUncaughtExceptionHandler = false;
|
|
child.on('message', function onChildMsg(msg) {
|
|
if (msg === 'triggeredProcessUncaughtEx') {
|
|
childTriggeredOnUncaughtExceptionHandler = true;
|
|
}
|
|
});
|
|
|
|
child.on('exit', function onChildExited(exitCode, signal) {
|
|
// If the top-level domain's error handler does not throw,
|
|
// the process must exit gracefully, whether or not
|
|
// --abort-on-uncaught-exception was passed on the command line
|
|
var expectedExitCode = 0;
|
|
// On some platforms with KSH being the default shell (like SmartOS),
|
|
// when a process aborts, KSH exits with an exit code that is greater
|
|
// than 256, and thus the exit code emitted with the 'exit' event is
|
|
// null and the signal is set to SIGABRT. For these platforms only,
|
|
// and when the test is expected to abort, check the actual signal
|
|
// with the expected signal instead of the exit code.
|
|
var expectedSignal;
|
|
|
|
// When throwing errors from the top-level domain error handler
|
|
// outside of a try/catch block, the process should not exit gracefully
|
|
if (!options.useTryCatch && options.throwInDomainErrHandler) {
|
|
expectedExitCode = 7;
|
|
if (cmdLineOption === '--abort-on-uncaught-exception') {
|
|
// If the top-level domain's error handler throws, and only if
|
|
// --abort-on-uncaught-exception is passed on the command line,
|
|
// the process must abort.
|
|
expectedExitCode = 134;
|
|
|
|
// On linux, v8 raises SIGTRAP when aborting because
|
|
// the "debug break" flag is on by default
|
|
if (process.platform === 'linux')
|
|
expectedExitCode = 133;
|
|
|
|
if (process.platform === 'sunos') {
|
|
expectedExitCode = null;
|
|
expectedSignal = 'SIGABRT';
|
|
}
|
|
|
|
// On Windows, v8's OS::Abort also triggers a debug breakpoint
|
|
// which makes the process exit with code -2147483645
|
|
if (process.platform === 'win32') {
|
|
expectedExitCode = -2147483645;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (expectedSignal)
|
|
assert.equal(signal, expectedSignal)
|
|
|
|
assert.equal(exitCode, expectedExitCode);
|
|
});
|
|
}
|
|
}
|
|
|
|
testDomainExceptionHandling('--abort-on-uncaught-exception', {
|
|
throwInDomainErrHandler: false,
|
|
useTryCatch: false
|
|
});
|
|
|
|
testDomainExceptionHandling('--abort-on-uncaught-exception', {
|
|
throwInDomainErrHandler: false,
|
|
useTryCatch: true
|
|
});
|
|
|
|
testDomainExceptionHandling('--abort-on-uncaught-exception', {
|
|
throwInDomainErrHandler: true,
|
|
useTryCatch: false
|
|
});
|
|
|
|
testDomainExceptionHandling('--abort-on-uncaught-exception', {
|
|
throwInDomainErrHandler: true,
|
|
useTryCatch: true
|
|
});
|
|
|
|
testDomainExceptionHandling({
|
|
throwInDomainErrHandler: false
|
|
});
|
|
|
|
testDomainExceptionHandling({
|
|
throwInDomainErrHandler: false,
|
|
useTryCatch: false
|
|
});
|
|
|
|
testDomainExceptionHandling({
|
|
throwInDomainErrHandler: true,
|
|
useTryCatch: true
|
|
});
|
|
}
|
|
|