11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ci// The goal of this test is to make sure that errors thrown within domains
41cb0ef41Sopenharmony_ci// are handled correctly. It checks that the process' 'uncaughtException' event
51cb0ef41Sopenharmony_ci// is emitted when appropriate, and not emitted when it shouldn't. It also
61cb0ef41Sopenharmony_ci// checks that the proper domain error handlers are called when they should
71cb0ef41Sopenharmony_ci// be called, and not called when they shouldn't.
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ciconst common = require('../common');
101cb0ef41Sopenharmony_ciconst assert = require('assert');
111cb0ef41Sopenharmony_ciconst domain = require('domain');
121cb0ef41Sopenharmony_ciconst child_process = require('child_process');
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_ciconst tests = [];
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_cifunction test1() {
171cb0ef41Sopenharmony_ci  // Throwing from an async callback from within a domain that doesn't have
181cb0ef41Sopenharmony_ci  // an error handler must result in emitting the process' uncaughtException
191cb0ef41Sopenharmony_ci  // event.
201cb0ef41Sopenharmony_ci  const d = domain.create();
211cb0ef41Sopenharmony_ci  d.run(function() {
221cb0ef41Sopenharmony_ci    setTimeout(function onTimeout() {
231cb0ef41Sopenharmony_ci      throw new Error('boom!');
241cb0ef41Sopenharmony_ci    }, 1);
251cb0ef41Sopenharmony_ci  });
261cb0ef41Sopenharmony_ci}
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_citests.push({
291cb0ef41Sopenharmony_ci  fn: test1,
301cb0ef41Sopenharmony_ci  expectedMessages: ['uncaughtException']
311cb0ef41Sopenharmony_ci});
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_cifunction test2() {
341cb0ef41Sopenharmony_ci  // Throwing from from within a domain that doesn't have an error handler must
351cb0ef41Sopenharmony_ci  // result in emitting the process' uncaughtException event.
361cb0ef41Sopenharmony_ci  const d2 = domain.create();
371cb0ef41Sopenharmony_ci  d2.run(function() {
381cb0ef41Sopenharmony_ci    throw new Error('boom!');
391cb0ef41Sopenharmony_ci  });
401cb0ef41Sopenharmony_ci}
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_citests.push({
431cb0ef41Sopenharmony_ci  fn: test2,
441cb0ef41Sopenharmony_ci  expectedMessages: ['uncaughtException']
451cb0ef41Sopenharmony_ci});
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_cifunction test3() {
481cb0ef41Sopenharmony_ci  // This test creates two nested domains: d3 and d4. d4 doesn't register an
491cb0ef41Sopenharmony_ci  // error handler, but d3 does. The error is handled by the d3 domain and thus
501cb0ef41Sopenharmony_ci  // an 'uncaughtException' event should _not_ be emitted.
511cb0ef41Sopenharmony_ci  const d3 = domain.create();
521cb0ef41Sopenharmony_ci  const d4 = domain.create();
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_ci  d3.on('error', function onErrorInD3Domain() {
551cb0ef41Sopenharmony_ci    process.send('errorHandledByDomain');
561cb0ef41Sopenharmony_ci  });
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci  d3.run(function() {
591cb0ef41Sopenharmony_ci    d4.run(function() {
601cb0ef41Sopenharmony_ci      throw new Error('boom!');
611cb0ef41Sopenharmony_ci    });
621cb0ef41Sopenharmony_ci  });
631cb0ef41Sopenharmony_ci}
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_citests.push({
661cb0ef41Sopenharmony_ci  fn: test3,
671cb0ef41Sopenharmony_ci  expectedMessages: ['errorHandledByDomain']
681cb0ef41Sopenharmony_ci});
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_cifunction test4() {
711cb0ef41Sopenharmony_ci  // This test creates two nested domains: d5 and d6. d6 doesn't register an
721cb0ef41Sopenharmony_ci  // error handler. When the timer's callback is called, because async
731cb0ef41Sopenharmony_ci  // operations like timer callbacks are bound to the domain that was active
741cb0ef41Sopenharmony_ci  // at the time of their creation, and because both d5 and d6 domains have
751cb0ef41Sopenharmony_ci  // exited by the time the timer's callback is called, its callback runs with
761cb0ef41Sopenharmony_ci  // only d6 on the domains stack. Since d6 doesn't register an error handler,
771cb0ef41Sopenharmony_ci  // the process' uncaughtException event should be emitted.
781cb0ef41Sopenharmony_ci  const d5 = domain.create();
791cb0ef41Sopenharmony_ci  const d6 = domain.create();
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci  d5.on('error', function onErrorInD2Domain() {
821cb0ef41Sopenharmony_ci    process.send('errorHandledByDomain');
831cb0ef41Sopenharmony_ci  });
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_ci  d5.run(function() {
861cb0ef41Sopenharmony_ci    d6.run(function() {
871cb0ef41Sopenharmony_ci      setTimeout(function onTimeout() {
881cb0ef41Sopenharmony_ci        throw new Error('boom!');
891cb0ef41Sopenharmony_ci      }, 1);
901cb0ef41Sopenharmony_ci    });
911cb0ef41Sopenharmony_ci  });
921cb0ef41Sopenharmony_ci}
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_citests.push({
951cb0ef41Sopenharmony_ci  fn: test4,
961cb0ef41Sopenharmony_ci  expectedMessages: ['uncaughtException']
971cb0ef41Sopenharmony_ci});
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_cifunction test5() {
1001cb0ef41Sopenharmony_ci  // This test creates two nested domains: d7 and d8. d8 _does_ register an
1011cb0ef41Sopenharmony_ci  // error handler, so throwing within that domain should not emit an uncaught
1021cb0ef41Sopenharmony_ci  // exception.
1031cb0ef41Sopenharmony_ci  const d7 = domain.create();
1041cb0ef41Sopenharmony_ci  const d8 = domain.create();
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ci  d8.on('error', function onErrorInD3Domain() {
1071cb0ef41Sopenharmony_ci    process.send('errorHandledByDomain');
1081cb0ef41Sopenharmony_ci  });
1091cb0ef41Sopenharmony_ci
1101cb0ef41Sopenharmony_ci  d7.run(function() {
1111cb0ef41Sopenharmony_ci    d8.run(function() {
1121cb0ef41Sopenharmony_ci      throw new Error('boom!');
1131cb0ef41Sopenharmony_ci    });
1141cb0ef41Sopenharmony_ci  });
1151cb0ef41Sopenharmony_ci}
1161cb0ef41Sopenharmony_citests.push({
1171cb0ef41Sopenharmony_ci  fn: test5,
1181cb0ef41Sopenharmony_ci  expectedMessages: ['errorHandledByDomain']
1191cb0ef41Sopenharmony_ci});
1201cb0ef41Sopenharmony_ci
1211cb0ef41Sopenharmony_cifunction test6() {
1221cb0ef41Sopenharmony_ci  // This test creates two nested domains: d9 and d10. d10 _does_ register an
1231cb0ef41Sopenharmony_ci  // error handler, so throwing within that domain in an async callback should
1241cb0ef41Sopenharmony_ci  // _not_ emit an uncaught exception.
1251cb0ef41Sopenharmony_ci  //
1261cb0ef41Sopenharmony_ci  const d9 = domain.create();
1271cb0ef41Sopenharmony_ci  const d10 = domain.create();
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci  d10.on('error', function onErrorInD2Domain() {
1301cb0ef41Sopenharmony_ci    process.send('errorHandledByDomain');
1311cb0ef41Sopenharmony_ci  });
1321cb0ef41Sopenharmony_ci
1331cb0ef41Sopenharmony_ci  d9.run(function() {
1341cb0ef41Sopenharmony_ci    d10.run(function() {
1351cb0ef41Sopenharmony_ci      setTimeout(function onTimeout() {
1361cb0ef41Sopenharmony_ci        throw new Error('boom!');
1371cb0ef41Sopenharmony_ci      }, 1);
1381cb0ef41Sopenharmony_ci    });
1391cb0ef41Sopenharmony_ci  });
1401cb0ef41Sopenharmony_ci}
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_citests.push({
1431cb0ef41Sopenharmony_ci  fn: test6,
1441cb0ef41Sopenharmony_ci  expectedMessages: ['errorHandledByDomain']
1451cb0ef41Sopenharmony_ci});
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_ciif (process.argv[2] === 'child') {
1481cb0ef41Sopenharmony_ci  const testIndex = process.argv[3];
1491cb0ef41Sopenharmony_ci  process.on('uncaughtException', function onUncaughtException() {
1501cb0ef41Sopenharmony_ci    process.send('uncaughtException');
1511cb0ef41Sopenharmony_ci  });
1521cb0ef41Sopenharmony_ci
1531cb0ef41Sopenharmony_ci  tests[testIndex].fn();
1541cb0ef41Sopenharmony_ci} else {
1551cb0ef41Sopenharmony_ci  // Run each test's function in a child process. Listen on
1561cb0ef41Sopenharmony_ci  // messages sent by each child process and compare expected
1571cb0ef41Sopenharmony_ci  // messages defined for each test with the actual received messages.
1581cb0ef41Sopenharmony_ci  tests.forEach(function doTest(test, testIndex) {
1591cb0ef41Sopenharmony_ci    const testProcess = child_process.fork(__filename, ['child', testIndex]);
1601cb0ef41Sopenharmony_ci
1611cb0ef41Sopenharmony_ci    testProcess.on('message', function onMsg(msg) {
1621cb0ef41Sopenharmony_ci      if (test.messagesReceived === undefined)
1631cb0ef41Sopenharmony_ci        test.messagesReceived = [];
1641cb0ef41Sopenharmony_ci
1651cb0ef41Sopenharmony_ci      test.messagesReceived.push(msg);
1661cb0ef41Sopenharmony_ci    });
1671cb0ef41Sopenharmony_ci
1681cb0ef41Sopenharmony_ci    testProcess.on('disconnect', common.mustCall(function onExit() {
1691cb0ef41Sopenharmony_ci      // Make sure that all expected messages were sent from the
1701cb0ef41Sopenharmony_ci      // child process
1711cb0ef41Sopenharmony_ci      test.expectedMessages.forEach(function(expectedMessage) {
1721cb0ef41Sopenharmony_ci        const msgs = test.messagesReceived;
1731cb0ef41Sopenharmony_ci        if (msgs === undefined || !msgs.includes(expectedMessage)) {
1741cb0ef41Sopenharmony_ci          assert.fail(`test ${test.fn.name} should have sent message: ${
1751cb0ef41Sopenharmony_ci            expectedMessage} but didn't`);
1761cb0ef41Sopenharmony_ci        }
1771cb0ef41Sopenharmony_ci      });
1781cb0ef41Sopenharmony_ci
1791cb0ef41Sopenharmony_ci      if (test.messagesReceived) {
1801cb0ef41Sopenharmony_ci        test.messagesReceived.forEach(function(receivedMessage) {
1811cb0ef41Sopenharmony_ci          if (!test.expectedMessages.includes(receivedMessage)) {
1821cb0ef41Sopenharmony_ci            assert.fail(`test ${test.fn.name} should not have sent message: ${
1831cb0ef41Sopenharmony_ci              receivedMessage} but did`);
1841cb0ef41Sopenharmony_ci          }
1851cb0ef41Sopenharmony_ci        });
1861cb0ef41Sopenharmony_ci      }
1871cb0ef41Sopenharmony_ci    }));
1881cb0ef41Sopenharmony_ci  });
1891cb0ef41Sopenharmony_ci}
190