11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst common = require('../common');
41cb0ef41Sopenharmony_ciconst assert = require('assert');
51cb0ef41Sopenharmony_ciconst fs = require('fs');
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci// The goal of this test is to make sure that:
81cb0ef41Sopenharmony_ci//
91cb0ef41Sopenharmony_ci// - Even if --abort_on_uncaught_exception is passed on the command line,
101cb0ef41Sopenharmony_ci// setting up a top-level domain error handler and throwing an error
111cb0ef41Sopenharmony_ci// within this domain does *not* make the process abort. The process exits
121cb0ef41Sopenharmony_ci// gracefully.
131cb0ef41Sopenharmony_ci//
141cb0ef41Sopenharmony_ci// - When passing --abort_on_uncaught_exception on the command line and
151cb0ef41Sopenharmony_ci// setting up a top-level domain error handler, an error thrown
161cb0ef41Sopenharmony_ci// within this domain's error handler *does* make the process abort.
171cb0ef41Sopenharmony_ci//
181cb0ef41Sopenharmony_ci// - When *not* passing --abort_on_uncaught_exception on the command line and
191cb0ef41Sopenharmony_ci// setting up a top-level domain error handler, an error thrown within this
201cb0ef41Sopenharmony_ci// domain's error handler does *not* make the process abort, but makes it exit
211cb0ef41Sopenharmony_ci// with the proper failure exit code.
221cb0ef41Sopenharmony_ci//
231cb0ef41Sopenharmony_ci// - When throwing an error within the top-level domain's error handler
241cb0ef41Sopenharmony_ci// within a try/catch block, the process should exit gracefully, whether or
251cb0ef41Sopenharmony_ci// not --abort_on_uncaught_exception is passed on the command line.
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_ciconst domainErrHandlerExMessage = 'exception from domain error handler';
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ciif (process.argv[2] === 'child') {
301cb0ef41Sopenharmony_ci  const domain = require('domain');
311cb0ef41Sopenharmony_ci  const d = domain.create();
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_ci  process.on('uncaughtException', function onUncaughtException() {
341cb0ef41Sopenharmony_ci    // The process' uncaughtException event must not be emitted when
351cb0ef41Sopenharmony_ci    // an error handler is setup on the top-level domain.
361cb0ef41Sopenharmony_ci    // Exiting with exit code of 42 here so that it would assert when
371cb0ef41Sopenharmony_ci    // the parent checks the child exit code.
381cb0ef41Sopenharmony_ci    process.exit(42);
391cb0ef41Sopenharmony_ci  });
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_ci  d.on('error', function(err) {
421cb0ef41Sopenharmony_ci    // Swallowing the error on purpose if 'throwInDomainErrHandler' is not
431cb0ef41Sopenharmony_ci    // set
441cb0ef41Sopenharmony_ci    if (process.argv.includes('throwInDomainErrHandler')) {
451cb0ef41Sopenharmony_ci      // If useTryCatch is set, wrap the throw in a try/catch block.
461cb0ef41Sopenharmony_ci      // This is to make sure that a caught exception does not trigger
471cb0ef41Sopenharmony_ci      // an abort.
481cb0ef41Sopenharmony_ci      if (process.argv.includes('useTryCatch')) {
491cb0ef41Sopenharmony_ci        try {
501cb0ef41Sopenharmony_ci          throw new Error(domainErrHandlerExMessage);
511cb0ef41Sopenharmony_ci        } catch {
521cb0ef41Sopenharmony_ci          // Continue regardless of error.
531cb0ef41Sopenharmony_ci        }
541cb0ef41Sopenharmony_ci      } else {
551cb0ef41Sopenharmony_ci        throw new Error(domainErrHandlerExMessage);
561cb0ef41Sopenharmony_ci      }
571cb0ef41Sopenharmony_ci    }
581cb0ef41Sopenharmony_ci  });
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_ci  d.run(function doStuff() {
611cb0ef41Sopenharmony_ci    // Throwing from within different types of callbacks as each of them
621cb0ef41Sopenharmony_ci    // handles domains differently
631cb0ef41Sopenharmony_ci    process.nextTick(function() {
641cb0ef41Sopenharmony_ci      throw new Error('Error from nextTick callback');
651cb0ef41Sopenharmony_ci    });
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci    fs.exists('/non/existing/file', function onExists(exists) {
681cb0ef41Sopenharmony_ci      throw new Error('Error from fs.exists callback');
691cb0ef41Sopenharmony_ci    });
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci    setImmediate(function onSetImmediate() {
721cb0ef41Sopenharmony_ci      throw new Error('Error from setImmediate callback');
731cb0ef41Sopenharmony_ci    });
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ci    setTimeout(function onTimeout() {
761cb0ef41Sopenharmony_ci      throw new Error('Error from setTimeout callback');
771cb0ef41Sopenharmony_ci    }, 0);
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ci    throw new Error('Error from domain.run callback');
801cb0ef41Sopenharmony_ci  });
811cb0ef41Sopenharmony_ci} else {
821cb0ef41Sopenharmony_ci  const exec = require('child_process').exec;
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ci  function testDomainExceptionHandling(cmdLineOption, options) {
851cb0ef41Sopenharmony_ci    if (typeof cmdLineOption === 'object') {
861cb0ef41Sopenharmony_ci      options = cmdLineOption;
871cb0ef41Sopenharmony_ci      cmdLineOption = undefined;
881cb0ef41Sopenharmony_ci    }
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci    let throwInDomainErrHandlerOpt;
911cb0ef41Sopenharmony_ci    if (options.throwInDomainErrHandler)
921cb0ef41Sopenharmony_ci      throwInDomainErrHandlerOpt = 'throwInDomainErrHandler';
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_ci    let cmdToExec = '';
951cb0ef41Sopenharmony_ci    if (!common.isWindows) {
961cb0ef41Sopenharmony_ci      // Do not create core files, as it can take a lot of disk space on
971cb0ef41Sopenharmony_ci      // continuous testing and developers' machines
981cb0ef41Sopenharmony_ci      cmdToExec += 'ulimit -c 0 && ';
991cb0ef41Sopenharmony_ci    }
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ci    let useTryCatchOpt;
1021cb0ef41Sopenharmony_ci    if (options.useTryCatch)
1031cb0ef41Sopenharmony_ci      useTryCatchOpt = 'useTryCatch';
1041cb0ef41Sopenharmony_ci
1051cb0ef41Sopenharmony_ci    cmdToExec += `"${process.argv[0]}" ${cmdLineOption ? cmdLineOption : ''} "${
1061cb0ef41Sopenharmony_ci      process.argv[1]}" child ${throwInDomainErrHandlerOpt} ${useTryCatchOpt}`;
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_ci    const child = exec(cmdToExec);
1091cb0ef41Sopenharmony_ci
1101cb0ef41Sopenharmony_ci    if (child) {
1111cb0ef41Sopenharmony_ci      child.on('exit', function onChildExited(exitCode, signal) {
1121cb0ef41Sopenharmony_ci        // When throwing errors from the top-level domain error handler
1131cb0ef41Sopenharmony_ci        // outside of a try/catch block, the process should not exit gracefully
1141cb0ef41Sopenharmony_ci        if (!options.useTryCatch && options.throwInDomainErrHandler) {
1151cb0ef41Sopenharmony_ci          if (cmdLineOption === '--abort_on_uncaught_exception') {
1161cb0ef41Sopenharmony_ci            assert(common.nodeProcessAborted(exitCode, signal),
1171cb0ef41Sopenharmony_ci                   'process should have aborted, but did not');
1181cb0ef41Sopenharmony_ci          } else {
1191cb0ef41Sopenharmony_ci            // By default, uncaught exceptions make node exit with an exit
1201cb0ef41Sopenharmony_ci            // code of 7.
1211cb0ef41Sopenharmony_ci            assert.strictEqual(exitCode, 7);
1221cb0ef41Sopenharmony_ci            assert.strictEqual(signal, null);
1231cb0ef41Sopenharmony_ci          }
1241cb0ef41Sopenharmony_ci        } else {
1251cb0ef41Sopenharmony_ci          // If the top-level domain's error handler does not throw,
1261cb0ef41Sopenharmony_ci          // the process must exit gracefully, whether or not
1271cb0ef41Sopenharmony_ci          // --abort_on_uncaught_exception was passed on the command line
1281cb0ef41Sopenharmony_ci          assert.strictEqual(exitCode, 0);
1291cb0ef41Sopenharmony_ci          assert.strictEqual(signal, null);
1301cb0ef41Sopenharmony_ci        }
1311cb0ef41Sopenharmony_ci      });
1321cb0ef41Sopenharmony_ci    }
1331cb0ef41Sopenharmony_ci  }
1341cb0ef41Sopenharmony_ci
1351cb0ef41Sopenharmony_ci  testDomainExceptionHandling('--abort_on_uncaught_exception', {
1361cb0ef41Sopenharmony_ci    throwInDomainErrHandler: false,
1371cb0ef41Sopenharmony_ci    useTryCatch: false
1381cb0ef41Sopenharmony_ci  });
1391cb0ef41Sopenharmony_ci
1401cb0ef41Sopenharmony_ci  testDomainExceptionHandling('--abort_on_uncaught_exception', {
1411cb0ef41Sopenharmony_ci    throwInDomainErrHandler: false,
1421cb0ef41Sopenharmony_ci    useTryCatch: true
1431cb0ef41Sopenharmony_ci  });
1441cb0ef41Sopenharmony_ci
1451cb0ef41Sopenharmony_ci  testDomainExceptionHandling('--abort_on_uncaught_exception', {
1461cb0ef41Sopenharmony_ci    throwInDomainErrHandler: true,
1471cb0ef41Sopenharmony_ci    useTryCatch: false
1481cb0ef41Sopenharmony_ci  });
1491cb0ef41Sopenharmony_ci
1501cb0ef41Sopenharmony_ci  testDomainExceptionHandling('--abort_on_uncaught_exception', {
1511cb0ef41Sopenharmony_ci    throwInDomainErrHandler: true,
1521cb0ef41Sopenharmony_ci    useTryCatch: true
1531cb0ef41Sopenharmony_ci  });
1541cb0ef41Sopenharmony_ci
1551cb0ef41Sopenharmony_ci  testDomainExceptionHandling({
1561cb0ef41Sopenharmony_ci    throwInDomainErrHandler: false
1571cb0ef41Sopenharmony_ci  });
1581cb0ef41Sopenharmony_ci
1591cb0ef41Sopenharmony_ci  testDomainExceptionHandling({
1601cb0ef41Sopenharmony_ci    throwInDomainErrHandler: false,
1611cb0ef41Sopenharmony_ci    useTryCatch: false
1621cb0ef41Sopenharmony_ci  });
1631cb0ef41Sopenharmony_ci
1641cb0ef41Sopenharmony_ci  testDomainExceptionHandling({
1651cb0ef41Sopenharmony_ci    throwInDomainErrHandler: true,
1661cb0ef41Sopenharmony_ci    useTryCatch: true
1671cb0ef41Sopenharmony_ci  });
1681cb0ef41Sopenharmony_ci}
169