diff options
author | Julien Gilli <julien.gilli@joyent.com> | 2015-11-02 17:56:24 -0800 |
---|---|---|
committer | Julien Gilli <julien.gilli@joyent.com> | 2015-12-11 14:33:48 -0800 |
commit | 425a3545d26bdc0b17115bc84101191c59b0553f (patch) | |
tree | 8372ff5a2882a8e2d84ae729d98e040a0eecfea6 /test/parallel/test-domain-abort-on-uncaught.js | |
parent | 1a21a5368bab50548203970cedb318f421f4fba3 (diff) | |
download | android-node-v8-425a3545d26bdc0b17115bc84101191c59b0553f.tar.gz android-node-v8-425a3545d26bdc0b17115bc84101191c59b0553f.tar.bz2 android-node-v8-425a3545d26bdc0b17115bc84101191c59b0553f.zip |
domains: fix handling of uncaught exceptions
Fix node exiting due to an exception being thrown rather than emitting
an `'uncaughtException'` event on the process object when:
1. no error handler is set on the domain within which an error is thrown
2. an `'uncaughtException'` event listener is set on the process
Also fix an issue where the process would not abort in the proper
function call if an error is thrown within a domain with no error
handler and `--abort-on-uncaught-exception` is used.
Finally, change the behavior of --abort-on-uncaught-exception so that,
if the domain within which the error is thrown has no error handler, but
a domain further up the domains stack has one, the process will not
abort.
Fixes #3607 and #3653.
PR: #3654
PR-URL: https://github.com/nodejs/node/pull/3654
Reviewed-By: Chris Dickinson <chris@neversaw.us>
Diffstat (limited to 'test/parallel/test-domain-abort-on-uncaught.js')
-rw-r--r-- | test/parallel/test-domain-abort-on-uncaught.js | 310 |
1 files changed, 235 insertions, 75 deletions
diff --git a/test/parallel/test-domain-abort-on-uncaught.js b/test/parallel/test-domain-abort-on-uncaught.js index f4884aa8f3..9d23046506 100644 --- a/test/parallel/test-domain-abort-on-uncaught.js +++ b/test/parallel/test-domain-abort-on-uncaught.js @@ -1,96 +1,256 @@ 'use strict'; -// Flags: --abort_on_uncaught_exception - -var common = require('../common'); -var assert = require('assert'); -var domain = require('domain'); - -var tests = [ - nextTick, - timer, - timerPlusNextTick, - netServer, - firstRun, -]; -var errors = 0; +// This test makes sure that when using --abort-on-uncaught-exception and +// when throwing an error from within a domain that has an error handler +// setup, the process _does not_ abort. -process.on('exit', function() { - assert.equal(errors, tests.length); -}); +const common = require('../common'); +const assert = require('assert'); +const domain = require('domain'); +const child_process = require('child_process'); -tests.forEach(function(test) { test(); }); +var errorHandlerCalled = false; -function nextTick() { - var d = domain.create(); +const tests = [ + function nextTick() { + const d = domain.create(); - d.once('error', function(err) { - errors += 1; - }); - d.run(function() { - process.nextTick(function() { - throw new Error('exceptional!'); + d.once('error', function(err) { + errorHandlerCalled = true; }); - }); -} -function timer() { - var d = domain.create(); + d.run(function() { + process.nextTick(function() { + throw new Error('exceptional!'); + }); + }); + }, - d.on('error', function(err) { - errors += 1; - }); - d.run(function() { - setTimeout(function() { - throw new Error('exceptional!'); - }, 33); - }); -} + function timer() { + const d = domain.create(); -function timerPlusNextTick() { - var d = domain.create(); + d.on('error', function(err) { + errorHandlerCalled = true; + }); - d.on('error', function(err) { - errors += 1; - }); - d.run(function() { - setTimeout(function() { - process.nextTick(function() { + d.run(function() { + setTimeout(function() { throw new Error('exceptional!'); + }, 33); + }); + }, + + function immediate() { + const d = domain.create(); + + d.on('error', function errorHandler() { + errorHandlerCalled = true; + }); + + d.run(function() { + setImmediate(function() { + throw new Error('boom!'); }); - }, 33); - }); -} + }); + }, -function firstRun() { - var d = domain.create(); + function timerPlusNextTick() { + const d = domain.create(); - d.on('error', function(err) { - errors += 1; - }); - d.run(function() { - throw new Error('exceptional!'); - }); -} + d.on('error', function(err) { + errorHandlerCalled = true; + }); + + d.run(function() { + setTimeout(function() { + process.nextTick(function() { + throw new Error('exceptional!'); + }); + }, 33); + }); + }, -function netServer() { - var net = require('net'); - var d = domain.create(); + function firstRun() { + const d = domain.create(); - d.on('error', function(err) { - errors += 1; - }); - d.run(function() { - var server = net.createServer(function(conn) { - conn.pipe(conn); - }); - server.listen(common.PORT, '0.0.0.0', function() { - var conn = net.connect(common.PORT, '0.0.0.0'); - conn.once('data', function() { - throw new Error('ok'); + d.on('error', function(err) { + errorHandlerCalled = true; + }); + + d.run(function() { + throw new Error('exceptional!'); + }); + }, + + function fsAsync() { + const d = domain.create(); + + d.on('error', function errorHandler() { + errorHandlerCalled = true; + }); + + d.run(function() { + var fs = require('fs'); + fs.exists('/non/existing/file', function onExists(exists) { + throw new Error('boom!'); + }); + }); + }, + + function netServer() { + const net = require('net'); + const d = domain.create(); + + d.on('error', function(err) { + errorHandlerCalled = true; + }); + + d.run(function() { + const server = net.createServer(function(conn) { + conn.pipe(conn); + }); + server.listen(common.PORT, common.localhostIPv4, function() { + const conn = net.connect(common.PORT, common.localhostIPv4); + conn.once('data', function() { + throw new Error('ok'); + }); + conn.end('ok'); + server.close(); }); - conn.end('ok'); - server.close(); + }); + }, + + function firstRunOnlyTopLevelErrorHandler() { + const d = domain.create(); + const d2 = domain.create(); + + d.on('error', function errorHandler() { + errorHandlerCalled = true; + }); + + d.run(function() { + d2.run(function() { + throw new Error('boom!'); + }); + }); + }, + + function firstRunNestedWithErrorHandler() { + const d = domain.create(); + const d2 = domain.create(); + + d2.on('error', function errorHandler() { + errorHandlerCalled = true; + }); + + d.run(function() { + d2.run(function() { + throw new Error('boom!'); + }); + }); + }, + + function timeoutNestedWithErrorHandler() { + const d = domain.create(); + const d2 = domain.create(); + + d2.on('error', function errorHandler() { + errorHandlerCalled = true; + }); + + d.run(function() { + d2.run(function() { + setTimeout(function() { + console.log('foo'); + throw new Error('boom!'); + }, 33); + }); + }); + }, + + function setImmediateNestedWithErrorHandler() { + const d = domain.create(); + const d2 = domain.create(); + + d2.on('error', function errorHandler() { + errorHandlerCalled = true; + }); + + d.run(function() { + d2.run(function() { + setImmediate(function() { + throw new Error('boom!'); + }); + }); + }); + }, + + function nextTickNestedWithErrorHandler() { + const d = domain.create(); + const d2 = domain.create(); + + d2.on('error', function errorHandler() { + errorHandlerCalled = true; + }); + + d.run(function() { + d2.run(function() { + process.nextTick(function() { + throw new Error('boom!'); + }); + }); + }); + }, + + function fsAsyncNestedWithErrorHandler() { + const d = domain.create(); + const d2 = domain.create(); + + d2.on('error', function errorHandler() { + errorHandlerCalled = true; + }); + + d.run(function() { + d2.run(function() { + var fs = require('fs'); + fs.exists('/non/existing/file', function onExists(exists) { + throw new Error('boom!'); + }); + }); + }); + } +]; + +if (process.argv[2] === 'child') { + const testIndex = +process.argv[3]; + + tests[testIndex](); + + process.on('exit', function onExit() { + assert.equal(errorHandlerCalled, true); + }); +} else { + + tests.forEach(function(test, testIndex) { + var testCmd = ''; + if (process.platform !== 'win32') { + // 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]; + testCmd += ' ' + '--abort-on-uncaught-exception'; + testCmd += ' ' + process.argv[1]; + testCmd += ' ' + 'child'; + testCmd += ' ' + testIndex; + + var child = child_process.exec(testCmd); + + child.on('exit', function onExit(code, signal) { + assert.equal(code, 0, 'Test at index ' + testIndex + + ' should have exited with exit code 0 but instead exited with code ' + + code + ' and signal ' + signal); }); }); } |