• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2const common = require('../common');
3const assert = require('assert');
4const { AsyncLocalStorage } = require('async_hooks');
5const vm = require('vm');
6
7// err1 is emitted sync as a control - no events
8// err2 is emitted after a timeout - uncaughtExceptionMonitor
9//                                 + uncaughtException
10// err3 is emitted after some awaits -  unhandledRejection
11// err4 is emitted during handling err3 - uncaughtExceptionMonitor
12// err5 is emitted after err4 from a VM lacking hooks - unhandledRejection
13//                                                    + uncaughtException
14
15const asyncLocalStorage = new AsyncLocalStorage();
16const callbackToken = { callbackToken: true };
17const awaitToken = { awaitToken: true };
18
19let i = 0;
20
21// Redefining the uncaughtExceptionHandler is a bit odd, so we just do this
22// so we can track total invocations
23let underlyingExceptionHandler;
24const exceptionHandler = common.mustCall(function(...args) {
25  return underlyingExceptionHandler.call(this, ...args);
26}, 2);
27process.setUncaughtExceptionCaptureCallback(exceptionHandler);
28
29const exceptionMonitor = common.mustCall((err, origin) => {
30  if (err.message === 'err2') {
31    assert.strictEqual(origin, 'uncaughtException');
32    assert.strictEqual(asyncLocalStorage.getStore(), callbackToken);
33  } else if (err.message === 'err4') {
34    assert.strictEqual(origin, 'unhandledRejection');
35    assert.strictEqual(asyncLocalStorage.getStore(), awaitToken);
36  } else {
37    assert.fail('unknown error ' + err);
38  }
39}, 2);
40process.on('uncaughtExceptionMonitor', exceptionMonitor);
41
42function fireErr1() {
43  underlyingExceptionHandler = common.mustCall(function(err) {
44    ++i;
45    assert.strictEqual(err.message, 'err2');
46    assert.strictEqual(asyncLocalStorage.getStore(), callbackToken);
47  }, 1);
48  try {
49    asyncLocalStorage.run(callbackToken, () => {
50      setTimeout(fireErr2, 0);
51      throw new Error('err1');
52    });
53  } catch (e) {
54    assert.strictEqual(e.message, 'err1');
55    assert.strictEqual(asyncLocalStorage.getStore(), undefined);
56  }
57}
58
59function fireErr2() {
60  process.nextTick(() => {
61    assert.strictEqual(i, 1);
62    fireErr3();
63  });
64  throw new Error('err2');
65}
66
67function fireErr3() {
68  assert.strictEqual(asyncLocalStorage.getStore(), callbackToken);
69  const rejectionHandler3 = common.mustCall((err) => {
70    assert.strictEqual(err.message, 'err3');
71    assert.strictEqual(asyncLocalStorage.getStore(), awaitToken);
72    process.off('unhandledRejection', rejectionHandler3);
73
74    fireErr4();
75  }, 1);
76  process.on('unhandledRejection', rejectionHandler3);
77  async function awaitTest() {
78    await null;
79    throw new Error('err3');
80  }
81  asyncLocalStorage.run(awaitToken, awaitTest);
82}
83
84const uncaughtExceptionHandler4 = common.mustCall(
85  function(err) {
86    assert.strictEqual(err.message, 'err4');
87    assert.strictEqual(asyncLocalStorage.getStore(), awaitToken);
88    fireErr5();
89  }, 1);
90function fireErr4() {
91  assert.strictEqual(asyncLocalStorage.getStore(), awaitToken);
92  underlyingExceptionHandler = uncaughtExceptionHandler4;
93  // re-entrant check
94  Promise.reject(new Error('err4'));
95}
96
97function fireErr5() {
98  assert.strictEqual(asyncLocalStorage.getStore(), awaitToken);
99  underlyingExceptionHandler = () => {};
100  const rejectionHandler5 = common.mustCall((err) => {
101    assert.strictEqual(err.message, 'err5');
102    assert.strictEqual(asyncLocalStorage.getStore(), awaitToken);
103    process.off('unhandledRejection', rejectionHandler5);
104  }, 1);
105  process.on('unhandledRejection', rejectionHandler5);
106  const makeOrphan = vm.compileFunction(`(${String(() => {
107    async function main() {
108      await null;
109      Promise.resolve().then(() => {
110        throw new Error('err5');
111      });
112    }
113    main();
114  })})()`);
115  makeOrphan();
116}
117
118fireErr1();
119