child_process: add tracing channel for spawn · nodejs/node@b771529
1+'use strict';
2+const common = require('../common');
3+const assert = require('assert');
4+const { spawn, ChildProcess } = require('child_process');
5+const dc = require('diagnostics_channel');
6+const path = require('path');
7+const fs = require('fs');
8+const tmpdir = require('../common/tmpdir');
9+10+const isChildProcess = (process) => process instanceof ChildProcess;
11+12+function testDiagnosticChannel(subscribers, test, after) {
13+dc.tracingChannel('child_process.spawn').subscribe(subscribers);
14+15+test(common.mustCall(() => {
16+dc.tracingChannel('child_process.spawn').unsubscribe(subscribers);
17+after?.();
18+}));
19+}
20+21+const testSuccessfulSpawn = common.mustCall(() => {
22+let cb;
23+24+testDiagnosticChannel(
25+{
26+start: common.mustCall(({ process: childProcess, options }) => {
27+assert.strictEqual(isChildProcess(childProcess), true);
28+assert.strictEqual(options.file, process.execPath);
29+}),
30+end: common.mustCall(({ process: childProcess }) => {
31+assert.strictEqual(isChildProcess(childProcess), true);
32+}),
33+error: common.mustNotCall(),
34+},
35+common.mustCall((callback) => {
36+cb = callback;
37+const child = spawn(process.execPath, ['-e', 'process.exit(0)']);
38+child.on('close', () => {
39+cb();
40+});
41+}),
42+testFailingSpawnENOENT
43+);
44+});
45+46+const testFailingSpawnENOENT = common.mustCall(() => {
47+testDiagnosticChannel(
48+{
49+start: common.mustCall(({ process: childProcess, options }) => {
50+assert.strictEqual(isChildProcess(childProcess), true);
51+assert.strictEqual(options.file, 'does-not-exist');
52+}),
53+end: common.mustNotCall(),
54+error: common.mustCall(({ process: childProcess, error }) => {
55+assert.strictEqual(isChildProcess(childProcess), true);
56+assert.strictEqual(error.code, 'ENOENT');
57+}),
58+},
59+common.mustCall((callback) => {
60+const child = spawn('does-not-exist');
61+child.on('error', () => {});
62+callback();
63+}),
64+common.isWindows ? undefined : testFailingSpawnEACCES,
65+);
66+});
67+68+const testFailingSpawnEACCES = !common.isWindows ? common.mustCall(() => {
69+tmpdir.refresh();
70+const noExecFile = path.join(tmpdir.path, 'no-exec');
71+fs.writeFileSync(noExecFile, '');
72+fs.chmodSync(noExecFile, 0o644);
73+74+testDiagnosticChannel(
75+{
76+start: common.mustCall(({ process: childProcess, options }) => {
77+assert.strictEqual(isChildProcess(childProcess), true);
78+assert.strictEqual(options.file, noExecFile);
79+}),
80+end: common.mustNotCall(),
81+error: common.mustCall(({ process: childProcess, error }) => {
82+assert.strictEqual(isChildProcess(childProcess), true);
83+assert.strictEqual(error.code, 'EACCES');
84+}),
85+},
86+common.mustCall((callback) => {
87+const child = spawn(noExecFile);
88+child.on('error', () => {});
89+callback();
90+}),
91+);
92+}) : undefined;
93+94+testSuccessfulSpawn();