Upload Kmake

This commit is contained in:
Gorochu
2026-05-26 23:36:42 -07:00
parent ba051b2f74
commit 555ec72358
41615 changed files with 13344630 additions and 1 deletions

15
test/report/report.status Normal file
View File

@ -0,0 +1,15 @@
prefix report
# To mark a test as flaky, list the test name in the appropriate section
# below, without ".js", followed by ": PASS,FLAKY". Example:
# sample-test : PASS,FLAKY
[true] # This section applies to all platforms
[$system==solaris] # Also applies to SmartOS
# https://github.com/nodejs/node/issues/43457
test-report-fatal-error: PASS, FLAKY
[$system==ibmi]
# https://github.com/nodejs/node/issues/58582
test-report-exclude-network: PASS,FLAKY

View File

@ -0,0 +1,113 @@
// Flags: --report-on-fatalerror --report-on-signal --report-uncaught-exception --report-compact
'use strict';
const common = require('../common');
const assert = require('assert');
// Verify that process.report.directory behaves properly.
assert.strictEqual(process.report.directory, '');
process.report.directory = __dirname;
assert.strictEqual(process.report.directory, __dirname);
assert.throws(() => {
process.report.directory = {};
}, { code: 'ERR_INVALID_ARG_TYPE' });
assert.strictEqual(process.report.directory, __dirname);
// Verify that process.report.filename behaves properly.
assert.strictEqual(process.report.filename, '');
process.report.filename = 'test-report.json';
assert.strictEqual(process.report.filename, 'test-report.json');
assert.throws(() => {
process.report.filename = {};
}, { code: 'ERR_INVALID_ARG_TYPE' });
assert.strictEqual(process.report.filename, 'test-report.json');
// Verify that process.report.reportOnFatalError behaves properly.
assert.strictEqual(process.report.reportOnFatalError, true);
process.report.reportOnFatalError = false;
assert.strictEqual(process.report.reportOnFatalError, false);
process.report.reportOnFatalError = true;
assert.strictEqual(process.report.reportOnFatalError, true);
assert.throws(() => {
process.report.reportOnFatalError = {};
}, { code: 'ERR_INVALID_ARG_TYPE' });
assert.strictEqual(process.report.reportOnFatalError, true);
// Verify that process.report.reportOnUncaughtException behaves properly.
assert.strictEqual(process.report.reportOnUncaughtException, true);
process.report.reportOnUncaughtException = false;
assert.strictEqual(process.report.reportOnUncaughtException, false);
process.report.reportOnUncaughtException = true;
assert.strictEqual(process.report.reportOnUncaughtException, true);
assert.throws(() => {
process.report.reportOnUncaughtException = {};
}, { code: 'ERR_INVALID_ARG_TYPE' });
assert.strictEqual(process.report.reportOnUncaughtException, true);
// Verify that process.report.reportOnSignal behaves properly.
assert.strictEqual(process.report.reportOnSignal, true);
process.report.reportOnSignal = false;
assert.strictEqual(process.report.reportOnSignal, false);
process.report.reportOnSignal = true;
assert.strictEqual(process.report.reportOnSignal, true);
assert.throws(() => {
process.report.reportOnSignal = {};
}, { code: 'ERR_INVALID_ARG_TYPE' });
assert.strictEqual(process.report.reportOnSignal, true);
// Verify that process.report.reportCompact behaves properly.
assert.strictEqual(process.report.compact, true);
process.report.compact = false;
assert.strictEqual(process.report.compact, false);
process.report.compact = true;
assert.strictEqual(process.report.compact, true);
assert.throws(() => {
process.report.compact = {};
}, { code: 'ERR_INVALID_ARG_TYPE' });
assert.strictEqual(process.report.compact, true);
// Verify that process.report.excludeNetwork behaves properly.
assert.strictEqual(process.report.excludeNetwork, false);
process.report.excludeNetwork = true;
assert.strictEqual(process.report.excludeNetwork, true);
process.report.excludeNetwork = false;
assert.strictEqual(process.report.excludeNetwork, false);
assert.throws(() => {
process.report.excludeNetwork = {};
}, { code: 'ERR_INVALID_ARG_TYPE' });
assert.strictEqual(process.report.excludeNetwork, false);
if (!common.isWindows) {
// Verify that process.report.signal behaves properly.
assert.strictEqual(process.report.signal, 'SIGUSR2');
assert.throws(() => {
process.report.signal = {};
}, { code: 'ERR_INVALID_ARG_TYPE' });
assert.throws(() => {
process.report.signal = 'foo';
}, {
code: 'ERR_UNKNOWN_SIGNAL',
message: 'Unknown signal: foo',
});
assert.throws(() => {
process.report.signal = 'sigusr1';
}, {
code: 'ERR_UNKNOWN_SIGNAL',
message: 'Unknown signal: sigusr1 (signals must use all capital letters)',
});
assert.strictEqual(process.report.signal, 'SIGUSR2');
process.report.signal = 'SIGUSR1';
assert.strictEqual(process.report.signal, 'SIGUSR1');
// Verify that the interaction between reportOnSignal and signal is correct.
process.report.signal = 'SIGUSR2';
process.report.reportOnSignal = false;
assert.strictEqual(process.listenerCount('SIGUSR2'), 0);
process.report.reportOnSignal = true;
assert.strictEqual(process.listenerCount('SIGUSR2'), 1);
process.report.signal = 'SIGUSR1';
assert.strictEqual(process.listenerCount('SIGUSR2'), 0);
assert.strictEqual(process.listenerCount('SIGUSR1'), 1);
process.report.reportOnSignal = false;
assert.strictEqual(process.listenerCount('SIGUSR1'), 0);
}

View File

@ -0,0 +1,98 @@
'use strict';
require('../common');
const http = require('node:http');
const assert = require('node:assert');
const { spawnSync } = require('node:child_process');
const tmpdir = require('../common/tmpdir');
const { describe, it, before } = require('node:test');
const fs = require('node:fs');
const helper = require('../common/report');
function validate(pid) {
const reports = helper.findReports(pid, tmpdir.path);
assert.strictEqual(reports.length, 1);
let report = fs.readFileSync(reports[0], { encoding: 'utf8' });
report = JSON.parse(report);
assert.strictEqual(report.header.networkInterfaces, undefined);
fs.unlinkSync(reports[0]);
}
describe('report exclude network option', () => {
before(() => {
tmpdir.refresh();
process.report.directory = tmpdir.path;
});
it('should be configurable with --report-exclude-network', () => {
const args = ['--report-exclude-network', '-e', 'process.report.writeReport()'];
const child = spawnSync(process.execPath, args, { cwd: tmpdir.path });
assert.strictEqual(child.status, 0);
assert.strictEqual(child.signal, null);
validate(child.pid);
});
it('should be configurable with report.excludeNetwork', () => {
process.report.excludeNetwork = true;
process.report.writeReport();
validate(process.pid);
const report = process.report.getReport();
assert.strictEqual(report.header.networkInterfaces, undefined);
});
it('should not do DNS queries in libuv if exclude network', async () => {
const server = http.createServer(function(req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end();
});
let ipv6Available = true;
const port = await new Promise((resolve) => server.listen(0, async () => {
await Promise.all([
fetch('http://127.0.0.1:' + server.address().port),
fetch('http://[::1]:' + server.address().port).catch(() => ipv6Available = false),
]);
resolve(server.address().port);
server.close();
}));
process.report.excludeNetwork = false;
let report = process.report.getReport();
let tcp = report.libuv.filter((uv) => uv.type === 'tcp' && uv.remoteEndpoint?.port === port);
assert.strictEqual(tcp.length, ipv6Available ? 2 : 1);
const findHandle = (local, ip4 = true) => {
return tcp.find(
({ [local ? 'localEndpoint' : 'remoteEndpoint']: ep }) =>
(ep[ip4 ? 'ip4' : 'ip6'] === (ip4 ? '127.0.0.1' : '::1')),
)?.[local ? 'localEndpoint' : 'remoteEndpoint'];
};
try {
// The reverse DNS of 127.0.0.1 can be a lot of things other than localhost
// it could resolve to the server name for instance
assert.notStrictEqual(findHandle(true)?.host, '127.0.0.1');
assert.notStrictEqual(findHandle(false)?.host, '127.0.0.1');
if (ipv6Available) {
assert.notStrictEqual(findHandle(true, false)?.host, '::1');
assert.notStrictEqual(findHandle(false, false)?.host, '::1');
}
} catch (e) {
throw new Error(e?.message + ' in ' + JSON.stringify(tcp, null, 2), { cause: e });
}
process.report.excludeNetwork = true;
report = process.report.getReport();
tcp = report.libuv.filter((uv) => uv.type === 'tcp' && uv.remoteEndpoint?.port === port);
try {
assert.strictEqual(tcp.length, ipv6Available ? 2 : 1);
assert.strictEqual(findHandle(true)?.host, '127.0.0.1');
assert.strictEqual(findHandle(false)?.host, '127.0.0.1');
if (ipv6Available) {
assert.strictEqual(findHandle(true, false)?.host, '::1');
assert.strictEqual(findHandle(false, false)?.host, '::1');
}
} catch (e) {
throw new Error(e?.message + ' in ' + JSON.stringify(tcp, null, 2), { cause: e });
}
});
});

View File

@ -0,0 +1,39 @@
'use strict';
// Testcases for situations involving fatal errors, like Javascript heap OOM
require('../common');
const assert = require('assert');
const fs = require('fs');
const helper = require('../common/report.js');
const spawnSync = require('child_process').spawnSync;
const tmpdir = require('../common/tmpdir');
const fixtures = require('../common/fixtures');
// Common args that will cause an out-of-memory error for child process.
const ARGS = [
'--max-heap-size=20',
fixtures.path('report-oom'),
];
const REPORT_FIELDS = [
['header.trigger', 'OOMError'],
['javascriptHeap.memoryLimit', 20 * 1024 * 1024 /* 20MB */],
];
{
// Verify that --report-compact is respected when set.
tmpdir.refresh();
const args = ['--report-on-fatalerror', '--report-compact', ...ARGS];
const child = spawnSync(process.execPath, args, { cwd: tmpdir.path });
assert.notStrictEqual(child.status, 0, 'Process exited unexpectedly');
const reports = helper.findReports(child.pid, tmpdir.path);
assert.strictEqual(reports.length, 1);
const report = reports[0];
helper.validate(report, REPORT_FIELDS);
// Subtract 1 because "xx\n".split("\n") => [ 'xx', '' ].
const lines = fs.readFileSync(report, 'utf8').split('\n').length - 1;
assert.strictEqual(lines, 1);
}

View File

@ -0,0 +1,40 @@
'use strict';
// Testcases for situations involving fatal errors, like Javascript heap OOM
require('../common');
const assert = require('assert');
const fs = require('fs');
const helper = require('../common/report.js');
const spawnSync = require('child_process').spawnSync;
const tmpdir = require('../common/tmpdir');
const fixtures = require('../common/fixtures');
// Common args that will cause an out-of-memory error for child process.
const ARGS = [
'--max-heap-size=20',
fixtures.path('report-oom'),
];
const REPORT_FIELDS = [
['header.trigger', 'OOMError'],
['javascriptHeap.memoryLimit', 20 * 1024 * 1024 /* 20MB */],
];
{
// Verify that --report-directory is respected when set.
// Verify that --report-compact is respected when not set.
tmpdir.refresh();
const dir = '--report-directory=' + tmpdir.path;
const args = ['--report-on-fatalerror', dir, ...ARGS];
const child = spawnSync(process.execPath, args, { });
assert.notStrictEqual(child.status, 0, 'Process exited unexpectedly');
const reports = helper.findReports(child.pid, tmpdir.path);
assert.strictEqual(reports.length, 1);
const report = reports[0];
helper.validate(report, REPORT_FIELDS);
const lines = fs.readFileSync(report, 'utf8').split('\n').length - 1;
assert(lines > 10);
}

View File

@ -0,0 +1,42 @@
'use strict';
// Testcases for situations involving fatal errors, like Javascript heap OOM
require('../common');
const assert = require('assert');
const helper = require('../common/report.js');
const spawnSync = require('child_process').spawnSync;
const tmpdir = require('../common/tmpdir');
const fixtures = require('../common/fixtures');
// Common args that will cause an out-of-memory error for child process.
const ARGS = [
'--max-heap-size=20',
fixtures.path('report-oom'),
];
const REPORT_FIELDS = [
['header.trigger', 'OOMError'],
['javascriptHeap.memoryLimit', 20 * 1024 * 1024 /* 20MB */],
];
{
// Verify that --report-compact is respected when set.
// Verify that --report-filename is respected when set.
tmpdir.refresh();
const args = [
'--report-on-fatalerror',
'--report-compact',
'--report-filename=stderr',
...ARGS,
];
const child = spawnSync(process.execPath, args, { encoding: 'utf8' });
assert.notStrictEqual(child.status, 0, 'Process exited unexpectedly');
const reports = helper.findReports(child.pid, tmpdir.path);
assert.strictEqual(reports.length, 0);
const lines = child.stderr.split('\n');
// Skip over unavoidable free-form output and gc log from V8.
const report = lines.find((i) => i.startsWith('{'));
helper.validateContent(report, REPORT_FIELDS);
}

View File

@ -0,0 +1,26 @@
'use strict';
// Testcases for situations involving fatal errors, like Javascript heap OOM
require('../common');
const assert = require('assert');
const helper = require('../common/report.js');
const spawnSync = require('child_process').spawnSync;
const tmpdir = require('../common/tmpdir');
const fixtures = require('../common/fixtures');
// Common args that will cause an out-of-memory error for child process.
const ARGS = [
'--max-heap-size=20',
fixtures.path('report-oom'),
];
{
tmpdir.refresh();
// Verify that --report-on-fatalerror is respected when not set.
const args = ARGS;
const child = spawnSync(process.execPath, args, { cwd: tmpdir.path });
assert.notStrictEqual(child.status, 0, 'Process exited unexpectedly');
const reports = helper.findReports(child.pid, tmpdir.path);
assert.strictEqual(reports.length, 0);
}

View File

@ -0,0 +1,34 @@
'use strict';
// Testcases for situations involving fatal errors, like Javascript heap OOM
require('../common');
const assert = require('assert');
const helper = require('../common/report.js');
const spawnSync = require('child_process').spawnSync;
const tmpdir = require('../common/tmpdir');
const fixtures = require('../common/fixtures');
// Common args that will cause an out-of-memory error for child process.
const ARGS = [
'--max-heap-size=20',
fixtures.path('report-oom'),
];
const REPORT_FIELDS = [
['header.trigger', 'OOMError'],
['javascriptHeap.memoryLimit', 20 * 1024 * 1024 /* 20MB */],
];
{
// Verify that --report-on-fatalerror is respected when set.
tmpdir.refresh();
const args = ['--report-on-fatalerror', ...ARGS];
const child = spawnSync(process.execPath, args, { cwd: tmpdir.path });
assert.notStrictEqual(child.status, 0, 'Process exited unexpectedly');
const reports = helper.findReports(child.pid, tmpdir.path);
assert.strictEqual(reports.length, 1);
const report = reports[0];
helper.validate(report, REPORT_FIELDS);
}

View File

@ -0,0 +1,38 @@
'use strict';
require('../common');
const assert = require('assert');
const helper = require('../common/report');
{
// Test with no arguments.
helper.validateContent(process.report.getReport());
assert.deepStrictEqual(helper.findReports(process.pid, process.cwd()), []);
}
{
// Test with an error argument.
helper.validateContent(process.report.getReport(new Error('test error')));
assert.deepStrictEqual(helper.findReports(process.pid, process.cwd()), []);
}
{
// Test with an error with one line stack
const error = new Error();
error.stack = 'only one line';
helper.validateContent(process.report.getReport(error));
assert.deepStrictEqual(helper.findReports(process.pid, process.cwd()), []);
}
{
const error = new Error();
error.foo = 'goo';
helper.validateContent(process.report.getReport(error),
[['javascriptStack.errorProperties.foo', 'goo']]);
}
// Test with an invalid error argument.
[null, 1, Symbol(), function() {}, 'foo'].forEach((error) => {
assert.throws(() => {
process.report.getReport(error);
}, { code: 'ERR_INVALID_ARG_TYPE' });
});

View File

@ -0,0 +1,37 @@
// Flags: --report-on-signal
'use strict';
// Test producing a report via signal.
const common = require('../common');
if (common.isWindows) {
return common.skip('Unsupported on Windows.');
}
const { isMainThread } = require('worker_threads');
if (!isMainThread) {
common.skip('Signal reporting is only supported in the main thread');
}
const assert = require('assert');
const helper = require('../common/report');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();
process.report.directory = tmpdir.path;
assert.strictEqual(process.listenerCount('SIGUSR2'), 1);
process.kill(process.pid, 'SIGUSR2');
// Asynchronously wait for the report. In development, a single setImmediate()
// appears to be enough. Use an async loop to be a bit more robust in case
// platform or machine differences throw off the timing.
(function validate() {
const reports = helper.findReports(process.pid, tmpdir.path);
if (reports.length === 0)
return setImmediate(validate);
assert.strictEqual(reports.length, 1);
helper.validate(reports[0]);
})();

View File

@ -0,0 +1,32 @@
'use strict';
// Test producing a report on uncaught exception.
const common = require('../common');
const assert = require('assert');
const childProcess = require('child_process');
const helper = require('../common/report');
const tmpdir = require('../common/tmpdir');
if (process.argv[2] === 'child') {
throw new Error('test error');
}
tmpdir.refresh();
const child = childProcess.spawn(process.execPath, [
'--report-uncaught-exception',
'--report-compact',
__filename,
'child',
], {
cwd: tmpdir.path,
});
child.on('exit', common.mustCall((code) => {
assert.strictEqual(code, 1);
const reports = helper.findReports(child.pid, tmpdir.path);
assert.strictEqual(reports.length, 1);
helper.validate(reports[0], [
['header.event', 'Exception'],
['header.trigger', 'Exception'],
['javascriptStack.message', 'Error: test error'],
]);
}));

View File

@ -0,0 +1,23 @@
// Flags: --report-uncaught-exception
'use strict';
// Test report is suppressed on uncaught exception hook.
const common = require('../common');
const assert = require('assert');
const helper = require('../common/report');
const tmpdir = require('../common/tmpdir');
const error = new Error('test error');
tmpdir.refresh();
process.report.directory = tmpdir.path;
// Make sure the uncaughtException listener is called.
process.on('uncaughtException', common.mustCall());
process.on('exit', (code) => {
assert.strictEqual(code, 0);
// Make sure no reports are generated.
const reports = helper.findReports(process.pid, tmpdir.path);
assert.strictEqual(reports.length, 0);
});
throw error;

View File

@ -0,0 +1,24 @@
// Flags: --report-uncaught-exception
'use strict';
// Test report is suppressed on uncaught exception hook.
const common = require('../common');
const assert = require('assert');
const helper = require('../common/report');
const tmpdir = require('../common/tmpdir');
const error = new Error('test error');
tmpdir.refresh();
process.report.directory = tmpdir.path;
// First, install an uncaught exception hook.
process.setUncaughtExceptionCaptureCallback(common.mustCall());
// Do not install process uncaughtException handler.
process.on('exit', (code) => {
assert.strictEqual(code, 0);
// Make sure no reports are generated.
const reports = helper.findReports(process.pid, tmpdir.path);
assert.strictEqual(reports.length, 0);
});
throw error;

View File

@ -0,0 +1,32 @@
'use strict';
// Test producing a report on uncaught exception.
const common = require('../common');
const assert = require('assert');
const childProcess = require('child_process');
const helper = require('../common/report');
const tmpdir = require('../common/tmpdir');
if (process.argv[2] === 'child') {
// eslint-disable-next-line no-throw-literal
throw 1;
}
tmpdir.refresh();
const child = childProcess.spawn(process.execPath, [
'--report-uncaught-exception',
__filename,
'child',
], {
cwd: tmpdir.path,
});
child.on('exit', common.mustCall((code) => {
assert.strictEqual(code, 1);
const reports = helper.findReports(child.pid, tmpdir.path);
assert.strictEqual(reports.length, 1);
helper.validate(reports[0], [
['header.event', 'Exception'],
['header.trigger', 'Exception'],
['javascriptStack.message', '1'],
]);
}));

View File

@ -0,0 +1,31 @@
'use strict';
// Test producing a report on uncaught exception.
const common = require('../common');
const assert = require('assert');
const childProcess = require('child_process');
const helper = require('../common/report');
const tmpdir = require('../common/tmpdir');
if (process.argv[2] === 'child') {
throw Symbol('foobar');
}
tmpdir.refresh();
const child = childProcess.spawn(process.execPath, [
'--report-uncaught-exception',
__filename,
'child',
], {
cwd: tmpdir.path,
});
child.on('exit', common.mustCall((code) => {
assert.strictEqual(code, 1);
const reports = helper.findReports(child.pid, tmpdir.path);
assert.strictEqual(reports.length, 1);
helper.validate(reports[0], [
['header.event', 'Exception'],
['header.trigger', 'Exception'],
['javascriptStack.message', 'Symbol(foobar)'],
]);
}));

View File

@ -0,0 +1,31 @@
'use strict';
// Test producing a report on uncaught exception.
const common = require('../common');
const assert = require('assert');
const childProcess = require('child_process');
const helper = require('../common/report');
const tmpdir = require('../common/tmpdir');
if (process.argv[2] === 'child') {
throw new Error('test error');
}
tmpdir.refresh();
const child = childProcess.spawn(process.execPath, [
'--report-uncaught-exception',
__filename,
'child',
], {
cwd: tmpdir.path,
});
child.on('exit', common.mustCall((code) => {
assert.strictEqual(code, 1);
const reports = helper.findReports(child.pid, tmpdir.path);
assert.strictEqual(reports.length, 1);
helper.validate(reports[0], [
['header.event', 'Exception'],
['header.trigger', 'Exception'],
['javascriptStack.message', 'Error: test error'],
]);
}));

View File

@ -0,0 +1,284 @@
'use strict';
// Testcase to check reporting of uv handles.
const common = require('../common');
const tmpdir = require('../common/tmpdir');
const path = require('path');
if (common.isIBMi)
common.skip('IBMi does not support fs.watch()');
// This is quite similar to common.PIPE except that it uses an extended prefix
// of "\\?\pipe" on windows.
const PIPE = (() => {
const localRelative = path.relative(process.cwd(), `${tmpdir.path}/`);
const pipePrefix = common.isWindows ? '\\\\?\\pipe\\' : localRelative;
const pipeName = `node-test.${process.pid}.sock`;
return path.join(pipePrefix, pipeName);
})();
function createFsHandle(childData) {
const fs = require('fs');
// Watching files should result in fs_event/fs_poll uv handles.
let watcher;
try {
watcher = fs.watch(__filename);
} catch {
// fs.watch() unavailable
}
fs.watchFile(__filename, () => {});
childData.skip_fs_watch = watcher === undefined;
return () => {
if (watcher) watcher.close();
fs.unwatchFile(__filename);
};
}
function createChildProcessHandle(childData) {
const spawn = require('child_process').spawn;
// Child should exist when this returns as child_process.pid must be set.
const cp = spawn(process.execPath,
['-e', "process.stdin.on('data', (x) => " +
'console.log(x.toString()));']);
childData.pid = cp.pid;
return () => {
cp.kill();
};
}
function createTimerHandle() {
const timeout = setInterval(() => {}, 1000);
// Make sure the timer doesn't keep the test alive and let
// us check we detect unref'd handles correctly.
timeout.unref();
return () => {
clearInterval(timeout);
};
}
function createTcpHandle(childData) {
const http = require('http');
return new Promise((resolve) => {
// Simple server/connection to create tcp uv handles.
const server = http.createServer((req, res) => {
req.on('end', () => {
resolve(() => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end();
server.close();
});
});
req.resume();
});
server.listen(() => {
childData.tcp_address = server.address();
http.get({ port: server.address().port });
});
});
}
function createUdpHandle(childData) {
// Datagram socket for udp uv handles.
const dgram = require('dgram');
const udpSocket = dgram.createSocket('udp4');
const connectedUdpSocket = dgram.createSocket('udp4');
return new Promise((resolve) => {
udpSocket.bind({}, common.mustCall(() => {
connectedUdpSocket.connect(udpSocket.address().port);
childData.udp_address = udpSocket.address();
resolve(() => {
connectedUdpSocket.close();
udpSocket.close();
});
}));
});
}
function createNamedPipeHandle(childData) {
const net = require('net');
const sockPath = PIPE;
return new Promise((resolve) => {
const server = net.createServer((socket) => {
childData.pipe_sock_path = server.address();
resolve(() => {
socket.end();
server.close();
});
});
server.listen(
sockPath,
() => {
net.connect(sockPath, (socket) => {});
});
});
}
async function child() {
// Exit on loss of parent process
const exit = () => process.exit(2);
process.on('disconnect', exit);
const childData = {};
const disposes = await Promise.all([
createFsHandle(childData),
createChildProcessHandle(childData),
createTimerHandle(childData),
createTcpHandle(childData),
createUdpHandle(childData),
createNamedPipeHandle(childData),
]);
process.send(childData);
// Generate the report while the connection is active.
console.log(JSON.stringify(process.report.getReport(), null, 2));
// Tidy up to allow process to exit cleanly.
disposes.forEach((it) => {
it();
});
process.removeListener('disconnect', exit);
}
if (process.argv[2] === 'child') {
child();
} else {
const helper = require('../common/report.js');
const fork = require('child_process').fork;
const assert = require('assert');
tmpdir.refresh();
const options = { encoding: 'utf8', silent: true, cwd: tmpdir.path };
const child = fork(__filename, ['child'], options);
let child_data;
child.on('message', (data) => { child_data = data; });
let stderr = '';
child.stderr.on('data', (chunk) => { stderr += chunk; });
let stdout = '';
const report_msg = 'Report files were written: unexpectedly';
child.stdout.on('data', (chunk) => { stdout += chunk; });
child.on('exit', common.mustCall((code, signal) => {
assert.strictEqual(stderr.trim(), '');
assert.strictEqual(code, 0, 'Process exited unexpectedly with code: ' +
`${code}`);
assert.strictEqual(signal, null, 'Process should have exited cleanly,' +
` but did not: ${signal}`);
const reports = helper.findReports(child.pid, tmpdir.path);
assert.deepStrictEqual(reports, [], report_msg, reports);
// Test libuv handle key order
{
const get_libuv = /"libuv":\s\[([\s\S]*?)\]/g;
const get_handle_inner = /{([\s\S]*?),*?}/g;
const libuv_handles_str = get_libuv.exec(stdout)[1];
const libuv_handles_array = libuv_handles_str.match(get_handle_inner);
for (const i of libuv_handles_array) {
// Exclude nested structure
if (i.includes('type')) {
const handle_keys = i.match(/(".*"):/g);
assert(handle_keys[0], 'type');
assert(handle_keys[1], 'is_active');
}
}
}
const report = JSON.parse(stdout);
const prefix = common.isWindows ? '\\\\?\\' : '';
const expected_filename = `${prefix}${__filename}`;
const found_tcp = [];
const found_udp = [];
const found_named_pipe = [];
// Functions are named to aid debugging when they are not called.
const validators = {
fs_event: common.mustCall(function fs_event_validator(handle) {
if (!child_data.skip_fs_watch) {
assert.strictEqual(handle.filename, expected_filename);
assert(handle.is_referenced);
}
}),
fs_poll: common.mustCall(function fs_poll_validator(handle) {
assert.strictEqual(handle.filename, expected_filename);
assert(handle.is_referenced);
}),
loop: common.mustCall(function loop_validator(handle) {
assert.strictEqual(typeof handle.loopIdleTimeSeconds, 'number');
}),
pipe: common.mustCallAtLeast(function pipe_validator(handle) {
assert(handle.is_referenced);
// Pipe handles. The report should contain three pipes:
// 1. The server's listening pipe.
// 2. The inbound pipe making the request.
// 3. The outbound pipe sending the response.
//
// There is no way to distinguish inbound and outbound in a cross
// platform manner, so we just check inbound here.
const sockPath = child_data.pipe_sock_path;
if (handle.localEndpoint === sockPath) {
if (handle.writable === false) {
found_named_pipe.push('listening');
}
} else if (handle.remoteEndpoint === sockPath) {
found_named_pipe.push('inbound');
}
}),
process: common.mustCall(function process_validator(handle) {
assert.strictEqual(handle.pid, child_data.pid);
assert(handle.is_referenced);
}),
tcp: common.mustCall(function tcp_validator(handle) {
// TCP handles. The report should contain three sockets:
// 1. The server's listening socket.
// 2. The inbound socket making the request.
// 3. The outbound socket sending the response.
const port = child_data.tcp_address.port;
if (handle.localEndpoint.port === port) {
if (handle.remoteEndpoint === null) {
found_tcp.push('listening');
} else {
found_tcp.push('inbound');
}
} else if (handle.remoteEndpoint.port === port) {
found_tcp.push('outbound');
}
assert(handle.is_referenced);
}, 3),
timer: common.mustCallAtLeast(function timer_validator(handle) {
assert(!handle.is_referenced);
assert.strictEqual(handle.repeat, 0);
}),
udp: common.mustCall(function udp_validator(handle) {
if (handle.remoteEndpoint === null) {
assert.strictEqual(handle.localEndpoint.port,
child_data.udp_address.port);
found_udp.push('unconnected');
} else {
assert.strictEqual(handle.remoteEndpoint.port,
child_data.udp_address.port);
found_udp.push('connected');
}
assert(handle.is_referenced);
assert.strictEqual(handle.writeQueueSize, 0);
assert.strictEqual(handle.writeQueueCount, 0);
}, 2),
};
for (const entry of report.libuv) {
if (validators[entry.type]) validators[entry.type](entry);
}
for (const socket of ['listening', 'inbound', 'outbound']) {
assert(found_tcp.includes(socket), `${socket} TCP socket was not found`);
}
for (const socket of ['connected', 'unconnected']) {
assert(found_udp.includes(socket), `${socket} UDP socket was not found`);
}
for (const socket of ['listening', 'inbound']) {
assert(found_named_pipe.includes(socket), `${socket} named pipe socket was not found`);
}
// Common report tests.
helper.validateContent(stdout);
}));
}

View File

@ -0,0 +1,49 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const { Worker } = require('worker_threads');
const { once } = require('events');
const helper = require('../common/report');
async function basic() {
// Test that the report includes basic information about Worker threads.
const w = new Worker(`
const { parentPort } = require('worker_threads');
parentPort.once('message', () => {
/* Wait for message to stop the Worker */
});
`, { eval: true });
await once(w, 'online');
const report = process.report.getReport();
helper.validateContent(report);
assert.strictEqual(report.workers.length, 1);
helper.validateContent(report.workers[0]);
assert.strictEqual(report.workers[0].header.threadId, w.threadId);
w.postMessage({});
await once(w, 'exit');
}
async function interruptingJS() {
// Test that the report also works when Worker threads are busy in JS land.
const w = new Worker('while (true);', { eval: true });
await once(w, 'online');
const report = process.report.getReport();
helper.validateContent(report);
assert.strictEqual(report.workers.length, 1);
helper.validateContent(report.workers[0]);
await w.terminate();
}
(async function() {
await basic();
await interruptingJS();
})().then(common.mustCall());

View File

@ -0,0 +1,80 @@
// Flags: --report-exclude-env
'use strict';
// Test producing a report via API call, using the no-hooks/no-signal interface.
require('../common');
const assert = require('assert');
const fs = require('fs');
const path = require('path');
const helper = require('../common/report');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();
process.report.directory = tmpdir.path;
function validate() {
const reports = helper.findReports(process.pid, tmpdir.path);
assert.strictEqual(reports.length, 1);
helper.validate(reports[0], arguments[0]);
fs.unlinkSync(reports[0]);
return reports[0];
}
{
// Test with no arguments.
process.report.writeReport();
validate();
}
{
// Test with an error argument.
process.report.writeReport(new Error('test error'));
validate();
}
{
// Test with an error with one line stack
const error = new Error();
error.stack = 'only one line';
process.report.writeReport(error);
validate();
}
{
const error = new Error();
error.foo = 'goo';
process.report.writeReport(error);
validate([['javascriptStack.errorProperties.foo', 'goo']]);
}
{
// Test with a file argument.
const file = process.report.writeReport('custom-name-1.json');
const absolutePath = tmpdir.resolve(file);
assert.strictEqual(helper.findReports(process.pid, tmpdir.path).length, 0);
assert.strictEqual(file, 'custom-name-1.json');
helper.validate(absolutePath);
fs.unlinkSync(absolutePath);
}
{
// Test with file and error arguments.
const file = process.report.writeReport('custom-name-2.json',
new Error('test error'));
const absolutePath = tmpdir.resolve(file);
assert.strictEqual(helper.findReports(process.pid, tmpdir.path).length, 0);
assert.strictEqual(file, 'custom-name-2.json');
helper.validate(absolutePath);
fs.unlinkSync(absolutePath);
}
{
// Test with a filename option.
process.report.filename = 'custom-name-3.json';
const file = process.report.writeReport();
assert.strictEqual(helper.findReports(process.pid, tmpdir.path).length, 0);
const filename = path.join(process.report.directory, 'custom-name-3.json');
assert.strictEqual(file, process.report.filename);
helper.validate(filename);
fs.unlinkSync(filename);
}

View File

@ -0,0 +1,131 @@
'use strict';
// Test producing a report via API call, using the no-hooks/no-signal interface.
require('../common');
const assert = require('assert');
const { spawnSync } = require('child_process');
const fs = require('fs');
const path = require('path');
const helper = require('../common/report');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();
process.report.directory = tmpdir.path;
function validate() {
const reports = helper.findReports(process.pid, tmpdir.path);
assert.strictEqual(reports.length, 1);
helper.validate(reports[0], arguments[0]);
fs.unlinkSync(reports[0]);
return reports[0];
}
{
// Test with no arguments.
process.report.writeReport();
validate();
}
{
// Test with an error argument.
process.report.writeReport(new Error('test error'));
validate();
}
{
// Test with an error with one line stack
const error = new Error();
error.stack = 'only one line';
process.report.writeReport(error);
validate();
}
{
const error = new Error();
error.foo = 'goo';
process.report.writeReport(error);
validate([['javascriptStack.errorProperties.foo', 'goo']]);
}
{
// Test with a file argument.
const file = process.report.writeReport('custom-name-1.json');
const absolutePath = tmpdir.resolve(file);
assert.strictEqual(helper.findReports(process.pid, tmpdir.path).length, 0);
assert.strictEqual(file, 'custom-name-1.json');
helper.validate(absolutePath);
fs.unlinkSync(absolutePath);
}
{
// Test with file and error arguments.
const file = process.report.writeReport('custom-name-2.json',
new Error('test error'));
const absolutePath = tmpdir.resolve(file);
assert.strictEqual(helper.findReports(process.pid, tmpdir.path).length, 0);
assert.strictEqual(file, 'custom-name-2.json');
helper.validate(absolutePath);
fs.unlinkSync(absolutePath);
}
{
// Test with a filename option.
process.report.filename = 'custom-name-3.json';
const file = process.report.writeReport();
assert.strictEqual(helper.findReports(process.pid, tmpdir.path).length, 0);
const filename = path.join(process.report.directory, 'custom-name-3.json');
assert.strictEqual(file, process.report.filename);
helper.validate(filename);
fs.unlinkSync(filename);
}
// Test with an invalid file argument.
[null, 1, Symbol(), function() {}].forEach((file) => {
assert.throws(() => {
process.report.writeReport(file);
}, { code: 'ERR_INVALID_ARG_TYPE' });
});
// Test with an invalid error argument.
[null, 1, Symbol(), function() {}, 'foo'].forEach((error) => {
assert.throws(() => {
process.report.writeReport('file', error);
}, { code: 'ERR_INVALID_ARG_TYPE' });
});
{
// Test the special "stdout" filename.
const args = ['-e', 'process.report.writeReport("stdout")'];
const child = spawnSync(process.execPath, args, { cwd: tmpdir.path });
assert.strictEqual(child.status, 0);
assert.strictEqual(child.signal, null);
assert.strictEqual(helper.findReports(child.pid, tmpdir.path).length, 0);
helper.validateContent(child.stdout.toString());
}
{
// Test the special "stderr" filename.
const args = ['-e', 'process.report.writeReport("stderr")'];
const child = spawnSync(process.execPath, args, { cwd: tmpdir.path });
assert.strictEqual(child.status, 0);
assert.strictEqual(child.signal, null);
assert.strictEqual(child.stdout.toString().trim(), '');
assert.strictEqual(helper.findReports(child.pid, tmpdir.path).length, 0);
const report = child.stderr.toString().split('Node.js report completed')[0];
helper.validateContent(report);
}
{
// Test the case where the report file cannot be opened.
const reportDir = tmpdir.resolve('does', 'not', 'exist');
const args = [`--report-directory=${reportDir}`,
'-e',
'process.report.writeReport()'];
const child = spawnSync(process.execPath, args, { cwd: tmpdir.path });
assert.strictEqual(child.status, 0);
assert.strictEqual(child.signal, null);
assert.strictEqual(child.stdout.toString().trim(), '');
const stderr = child.stderr.toString();
assert(stderr.includes('Failed to open Node.js report file:'));
}

6
test/report/testcfg.py Normal file
View File

@ -0,0 +1,6 @@
import sys, os
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import testpy
def GetConfiguration(context, root):
return testpy.ParallelTestConfiguration(context, root, 'report')