1'use strict';
2
3const common = require('../common');
4const assert = require('assert');
5const { spawn } = require('child_process');
6const fixtures = require('../common/fixtures');
7
8const aliveScript = fixtures.path('child-process-stay-alive-forever.js');
9{
10  // Verify that passing an AbortSignal works
11  const controller = new AbortController();
12  const { signal } = controller;
13
14  const cp = spawn(process.execPath, [aliveScript], {
15    signal,
16  });
17
18  cp.on('exit', common.mustCall((code, killSignal) => {
19    assert.strictEqual(code, null);
20    assert.strictEqual(killSignal, 'SIGTERM');
21  }));
22
23  cp.on('error', common.mustCall((e) => {
24    assert.strictEqual(e.name, 'AbortError');
25  }));
26
27  controller.abort();
28}
29
30{
31  // Verify that passing an AbortSignal with custom abort error works
32  const controller = new AbortController();
33  const { signal } = controller;
34  const cp = spawn(process.execPath, [aliveScript], {
35    signal,
36  });
37
38  cp.on('exit', common.mustCall((code, killSignal) => {
39    assert.strictEqual(code, null);
40    assert.strictEqual(killSignal, 'SIGTERM');
41  }));
42
43  cp.on('error', common.mustCall((e) => {
44    assert.strictEqual(e.name, 'AbortError');
45    assert.strictEqual(e.cause.name, 'Error');
46    assert.strictEqual(e.cause.message, 'boom');
47  }));
48
49  controller.abort(new Error('boom'));
50}
51
52{
53  const controller = new AbortController();
54  const { signal } = controller;
55  const cp = spawn(process.execPath, [aliveScript], {
56    signal,
57  });
58
59  cp.on('exit', common.mustCall((code, killSignal) => {
60    assert.strictEqual(code, null);
61    assert.strictEqual(killSignal, 'SIGTERM');
62  }));
63
64  cp.on('error', common.mustCall((e) => {
65    assert.strictEqual(e.name, 'AbortError');
66    assert.strictEqual(e.cause, 'boom');
67  }));
68
69  controller.abort('boom');
70}
71
72{
73  // Verify that passing an already-aborted signal works.
74  const signal = AbortSignal.abort();
75
76  const cp = spawn(process.execPath, [aliveScript], {
77    signal,
78  });
79  cp.on('exit', common.mustCall((code, killSignal) => {
80    assert.strictEqual(code, null);
81    assert.strictEqual(killSignal, 'SIGTERM');
82  }));
83
84  cp.on('error', common.mustCall((e) => {
85    assert.strictEqual(e.name, 'AbortError');
86  }));
87}
88
89{
90  // Verify that passing an already-aborted signal with custom abort error
91  // works.
92  const signal = AbortSignal.abort(new Error('boom'));
93  const cp = spawn(process.execPath, [aliveScript], {
94    signal,
95  });
96  cp.on('exit', common.mustCall((code, killSignal) => {
97    assert.strictEqual(code, null);
98    assert.strictEqual(killSignal, 'SIGTERM');
99  }));
100
101  cp.on('error', common.mustCall((e) => {
102    assert.strictEqual(e.name, 'AbortError');
103    assert.strictEqual(e.cause.name, 'Error');
104    assert.strictEqual(e.cause.message, 'boom');
105  }));
106}
107
108{
109  const signal = AbortSignal.abort('boom');
110  const cp = spawn(process.execPath, [aliveScript], {
111    signal,
112  });
113  cp.on('exit', common.mustCall((code, killSignal) => {
114    assert.strictEqual(code, null);
115    assert.strictEqual(killSignal, 'SIGTERM');
116  }));
117
118  cp.on('error', common.mustCall((e) => {
119    assert.strictEqual(e.name, 'AbortError');
120    assert.strictEqual(e.cause, 'boom');
121  }));
122}
123
124{
125  // Verify that waiting a bit and closing works
126  const controller = new AbortController();
127  const { signal } = controller;
128
129  const cp = spawn(process.execPath, [aliveScript], {
130    signal,
131  });
132
133  cp.on('exit', common.mustCall((code, killSignal) => {
134    assert.strictEqual(code, null);
135    assert.strictEqual(killSignal, 'SIGTERM');
136  }));
137
138  cp.on('error', common.mustCall((e) => {
139    assert.strictEqual(e.name, 'AbortError');
140  }));
141
142  setTimeout(() => controller.abort(), 1);
143}
144
145{
146  // Test passing a different killSignal
147  const controller = new AbortController();
148  const { signal } = controller;
149
150  const cp = spawn(process.execPath, [aliveScript], {
151    signal,
152    killSignal: 'SIGKILL',
153  });
154
155  cp.on('exit', common.mustCall((code, killSignal) => {
156    assert.strictEqual(code, null);
157    assert.strictEqual(killSignal, 'SIGKILL');
158  }));
159
160  cp.on('error', common.mustCall((e) => {
161    assert.strictEqual(e.name, 'AbortError');
162  }));
163
164  setTimeout(() => controller.abort(), 1);
165}
166
167{
168  // Test aborting a cp before close but after exit
169  const controller = new AbortController();
170  const { signal } = controller;
171
172  const cp = spawn(process.execPath, [aliveScript], {
173    signal,
174  });
175
176  cp.on('exit', common.mustCall(() => {
177    controller.abort();
178  }));
179
180  cp.on('error', common.mustNotCall());
181
182  setTimeout(() => cp.kill(), 1);
183}
184