1'use strict';
2
3const common = require('../common');
4const assert = require('assert');
5const domain = require('domain');
6const EventEmitter = require('events');
7
8// Make sure that the domains stack and the active domain is setup properly when
9// a domain's error handler is called due to an error event being emitted.
10// More specifically, we want to test that:
11// - the active domain in the domain's error handler is//not* that domain,//but*
12//   the active domain is a any direct parent domain at the time the error was
13//   emitted.
14// - the domains stack in the domain's error handler does//not* include that
15//   domain, *but* it includes all parents of that domain when the error was
16//   emitted.
17const d1 = domain.create();
18const d2 = domain.create();
19const d3 = domain.create();
20
21function checkExpectedDomains(err) {
22  // First, check that domains stack and active domain is as expected when the
23  // event handler is called synchronously via ee.emit('error').
24  if (domain._stack.length !== err.expectedStackLength) {
25    console.error('expected domains stack length of %d, but instead is %d',
26                  err.expectedStackLength, domain._stack.length);
27    process.exit(1);
28  }
29
30  if (process.domain !== err.expectedActiveDomain) {
31    console.error('expected active domain to be %j, but instead is %j',
32                  err.expectedActiveDomain, process.domain);
33    process.exit(1);
34  }
35
36  // Then make sure that the domains stack and active domain is setup as
37  // expected when executing a callback scheduled via nextTick from the error
38  // handler.
39  process.nextTick(() => {
40    const expectedStackLengthInNextTickCb =
41            err.expectedStackLength > 0 ? 1 : 0;
42    if (domain._stack.length !== expectedStackLengthInNextTickCb) {
43      console.error('expected stack length in nextTick cb to be %d, ' +
44                'but instead is %d', expectedStackLengthInNextTickCb,
45                    domain._stack.length);
46      process.exit(1);
47    }
48
49    const expectedActiveDomainInNextTickCb =
50            expectedStackLengthInNextTickCb === 0 ? undefined :
51              err.expectedActiveDomain;
52    if (process.domain !== expectedActiveDomainInNextTickCb) {
53      console.error('expected active domain in nextTick cb to be %j, ' +
54                'but instead is %j', expectedActiveDomainInNextTickCb,
55                    process.domain);
56      process.exit(1);
57    }
58  });
59}
60
61d1.on('error', common.mustCall((err) => {
62  checkExpectedDomains(err);
63}, 2));
64
65d2.on('error', common.mustCall((err) => {
66  checkExpectedDomains(err);
67}, 2));
68
69d3.on('error', common.mustCall((err) => {
70  checkExpectedDomains(err);
71}, 1));
72
73d1.run(() => {
74  const ee = new EventEmitter();
75  assert.strictEqual(process.domain, d1);
76  assert.strictEqual(domain._stack.length, 1);
77
78  const err = new Error('oops');
79  err.expectedStackLength = 0;
80  err.expectedActiveDomain = null;
81  ee.emit('error', err);
82
83  assert.strictEqual(process.domain, d1);
84  assert.strictEqual(domain._stack.length, 1);
85});
86
87d1.run(() => {
88  d1.run(() => {
89    const ee = new EventEmitter();
90
91    assert.strictEqual(process.domain, d1);
92    assert.strictEqual(domain._stack.length, 2);
93
94    const err = new Error('oops');
95    err.expectedStackLength = 0;
96    err.expectedActiveDomain = null;
97    ee.emit('error', err);
98
99    assert.strictEqual(process.domain, d1);
100    assert.strictEqual(domain._stack.length, 2);
101  });
102});
103
104d1.run(() => {
105  d2.run(() => {
106    const ee = new EventEmitter();
107
108    assert.strictEqual(process.domain, d2);
109    assert.strictEqual(domain._stack.length, 2);
110
111    const err = new Error('oops');
112    err.expectedStackLength = 1;
113    err.expectedActiveDomain = d1;
114    ee.emit('error', err);
115
116    assert.strictEqual(process.domain, d2);
117    assert.strictEqual(domain._stack.length, 2);
118  });
119});
120
121d1.run(() => {
122  d2.run(() => {
123    d2.run(() => {
124      const ee = new EventEmitter();
125
126      assert.strictEqual(process.domain, d2);
127      assert.strictEqual(domain._stack.length, 3);
128
129      const err = new Error('oops');
130      err.expectedStackLength = 1;
131      err.expectedActiveDomain = d1;
132      ee.emit('error', err);
133
134      assert.strictEqual(process.domain, d2);
135      assert.strictEqual(domain._stack.length, 3);
136    });
137  });
138});
139
140d3.run(() => {
141  d1.run(() => {
142    d3.run(() => {
143      d3.run(() => {
144        const ee = new EventEmitter();
145
146        assert.strictEqual(process.domain, d3);
147        assert.strictEqual(domain._stack.length, 4);
148
149        const err = new Error('oops');
150        err.expectedStackLength = 2;
151        err.expectedActiveDomain = d1;
152        ee.emit('error', err);
153
154        assert.strictEqual(process.domain, d3);
155        assert.strictEqual(domain._stack.length, 4);
156      });
157    });
158  });
159});
160