1'use strict'; 2 3// This test makes sure that when throwing an error from a domain, and then 4// handling that error in an uncaughtException handler by throwing an error 5// again, the exit code, signal and error messages are the ones we expect with 6// and without using --abort-on-uncaught-exception. 7 8const common = require('../common'); 9const assert = require('assert'); 10const child_process = require('child_process'); 11const domain = require('domain'); 12 13const uncaughtExceptionHandlerErrMsg = 'boom from uncaughtException handler'; 14const domainErrMsg = 'boom from domain'; 15 16const RAN_UNCAUGHT_EXCEPTION_HANDLER_EXIT_CODE = 42; 17 18if (process.argv[2] === 'child') { 19 process.on('uncaughtException', common.mustCall(function onUncaught() { 20 if (process.execArgv.includes('--abort-on-uncaught-exception')) { 21 // When passing --abort-on-uncaught-exception to the child process, 22 // we want to make sure that this handler (the process' uncaughtException 23 // event handler) wasn't called. Unfortunately we can't parse the child 24 // process' output to do that, since on Windows the standard error output 25 // is not properly flushed in V8's Isolate::Throw right before the 26 // process aborts due to an uncaught exception, and thus the error 27 // message representing the error that was thrown cannot be read by the 28 // parent process. So instead of parsing the child process' standard 29 // error, the parent process will check that in the case 30 // --abort-on-uncaught-exception was passed, the process did not exit 31 // with exit code RAN_UNCAUGHT_EXCEPTION_HANDLER_EXIT_CODE. 32 process.exit(RAN_UNCAUGHT_EXCEPTION_HANDLER_EXIT_CODE); 33 } else { 34 // On the other hand, when not passing --abort-on-uncaught-exception to 35 // the node process, we want to throw in this event handler to make sure 36 // that the proper error message, exit code and signal are the ones we 37 // expect. 38 throw new Error(uncaughtExceptionHandlerErrMsg); 39 } 40 })); 41 42 const d = domain.create(); 43 d.run(common.mustCall(function() { 44 throw new Error(domainErrMsg); 45 })); 46} else { 47 runTestWithoutAbortOnUncaughtException(); 48 runTestWithAbortOnUncaughtException(); 49} 50 51function runTestWithoutAbortOnUncaughtException() { 52 child_process.exec( 53 createTestCmdLine(), 54 function onTestDone(err, stdout, stderr) { 55 // When _not_ passing --abort-on-uncaught-exception, the process' 56 // uncaughtException handler _must_ be called, and thus the error 57 // message must include only the message of the error thrown from the 58 // process' uncaughtException handler. 59 assert(stderr.includes(uncaughtExceptionHandlerErrMsg), 60 'stderr output must include proper uncaughtException ' + 61 'handler\'s error\'s message'); 62 assert(!stderr.includes(domainErrMsg), 63 'stderr output must not include domain\'s error\'s message'); 64 65 assert.notStrictEqual(err.code, 0, 66 'child process should have exited with a ' + 67 'non-zero exit code, but did not'); 68 } 69 ); 70} 71 72function runTestWithAbortOnUncaughtException() { 73 child_process.exec(createTestCmdLine({ 74 withAbortOnUncaughtException: true 75 }), function onTestDone(err, stdout, stderr) { 76 assert.notStrictEqual(err.code, RAN_UNCAUGHT_EXCEPTION_HANDLER_EXIT_CODE, 77 'child process should not have run its ' + 78 'uncaughtException event handler'); 79 assert(common.nodeProcessAborted(err.code, err.signal), 80 'process should have aborted, but did not'); 81 }); 82} 83 84function createTestCmdLine(options) { 85 let testCmd = ''; 86 87 if (!common.isWindows) { 88 // Do not create core files, as it can take a lot of disk space on 89 // continuous testing and developers' machines 90 testCmd += 'ulimit -c 0 && '; 91 } 92 93 testCmd += `"${process.argv[0]}"`; 94 95 if (options && options.withAbortOnUncaughtException) { 96 testCmd += ' --abort-on-uncaught-exception'; 97 } 98 99 testCmd += ` "${process.argv[1]}" child`; 100 101 return testCmd; 102} 103