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