mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 10:15:07 +08:00
Signed-off-by: James M Snell <jasnell@gmail.com> Assisted-by: Opencode PR-URL: https://github.com/nodejs/node/pull/65920 Reviewed-By: Jordan Harband <ljharb@gmail.com> Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com> Reviewed-By: Vinícius Lourenço Claro Cardoso <contact@viniciusl.com.br> Reviewed-By: Xuguang Mei <meixuguang@gmail.com> Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com> Reviewed-By: Filip Skokan <panva.ip@gmail.com>
261 lines
8.4 KiB
JavaScript
261 lines
8.4 KiB
JavaScript
'use strict';
|
|
|
|
const common = require('../common');
|
|
const assert = require('assert');
|
|
const { spawnSync } = require('child_process');
|
|
const fixtures = require('../common/fixtures');
|
|
|
|
const spawnTimeout = common.platformTimeout(30_000);
|
|
|
|
function spawnNode(args, options = undefined) {
|
|
const result = spawnSync(process.execPath, args, {
|
|
__proto__: null,
|
|
encoding: 'utf8',
|
|
timeout: spawnTimeout,
|
|
...options,
|
|
});
|
|
assert.ifError(result.error);
|
|
assert.strictEqual(result.signal, null);
|
|
return result;
|
|
}
|
|
|
|
function spawnBench(args, options = undefined) {
|
|
return spawnNode([
|
|
'--no-warnings', '--experimental-bench', '--bench', ...args,
|
|
], options);
|
|
}
|
|
|
|
function parseRecords(result) {
|
|
assert.strictEqual(result.stderr, '');
|
|
return parseOutput(result.stdout);
|
|
}
|
|
|
|
function parseOutput(output) {
|
|
return output.trim().split('\n').map((line) => JSON.parse(line));
|
|
}
|
|
|
|
{
|
|
const result = spawnBench([
|
|
'--bench-reporter=json',
|
|
fixtures.path('bench-runner/error.cjs'),
|
|
]);
|
|
assert.strictEqual(result.status, 1);
|
|
const records = parseRecords(result);
|
|
const failure = records.find(
|
|
({ type }) => type === 'bench:complete').data;
|
|
assert.deepStrictEqual(failure.params, { kind: 'structured-error' });
|
|
assert.strictEqual(failure.error.name, 'Error');
|
|
assert.strictEqual(failure.error.message, 'benchmark fixture failed');
|
|
assert.strictEqual(failure.error.code, 'ERR_BENCHMARK_FIXTURE');
|
|
assert.deepStrictEqual(failure.error.cause, { value: '42' });
|
|
assert.match(failure.error.stack, /error\.cjs/);
|
|
assert.strictEqual(records.at(-1).data.success, false);
|
|
}
|
|
|
|
{
|
|
const result = spawnBench([
|
|
'--bench-isolation=none',
|
|
'--bench-reporter=json',
|
|
fixtures.path('bench-runner/throws-null.cjs'),
|
|
]);
|
|
assert.strictEqual(result.status, 1);
|
|
const records = parseRecords(result);
|
|
const diagnostic = records.find(
|
|
({ type }) => type === 'bench:diagnostic').data;
|
|
assert.strictEqual(diagnostic.message, 'null');
|
|
assert.strictEqual(records.at(-1).data.success, false);
|
|
}
|
|
|
|
for (const isolation of ['process', 'none']) {
|
|
const result = spawnBench([
|
|
`--bench-isolation=${isolation}`,
|
|
'--bench-reporter=json',
|
|
fixtures.path('bench-runner/load-error-after-declaration.cjs'),
|
|
]);
|
|
assert.strictEqual(result.status, 1);
|
|
const records = parseRecords(result);
|
|
assert(records.some(({ type, data }) =>
|
|
type === 'bench:diagnostic' &&
|
|
data.message === 'load failed after declaration'));
|
|
const plan = records.find(({ type }) => type === 'bench:plan').data;
|
|
const completion = records.find(
|
|
({ type }) => type === 'bench:complete').data;
|
|
assert.strictEqual(plan.name, 'declared before load error');
|
|
assert.strictEqual(plan.selected, true);
|
|
assert.strictEqual(completion.name, plan.name);
|
|
assert.strictEqual(completion.error, undefined);
|
|
assert.strictEqual(completion.samples.length, 1);
|
|
assert.strictEqual(records.at(-1).data.counts.completed, 1);
|
|
}
|
|
|
|
{
|
|
const result = spawnBench([
|
|
'--bench-reporter=json',
|
|
fixtures.path('bench-runner/recorded-detail.cjs'),
|
|
]);
|
|
assert.strictEqual(result.status, 0);
|
|
const records = parseRecords(result);
|
|
const completion = records.find(
|
|
({ type }) => type === 'bench:complete').data;
|
|
assert.strictEqual(completion.samples.length, 1);
|
|
const { rate, ...sample } = completion.samples[0];
|
|
assert.deepStrictEqual(sample, {
|
|
detail: { index: 0, phase: 'measurement', value: '42' },
|
|
duration_ns: '4',
|
|
operations: 2,
|
|
});
|
|
assert(Math.abs(rate - 500_000_000) < 1);
|
|
}
|
|
|
|
{
|
|
const result = spawnBench([
|
|
'--bench-reporter=json',
|
|
fixtures.path('bench-runner/diagnostic.cjs'),
|
|
]);
|
|
assert.strictEqual(result.status, 0);
|
|
const records = parseRecords(result);
|
|
const diagnostic = records.find(
|
|
({ type }) => type === 'bench:diagnostic').data;
|
|
const completion = records.find(
|
|
({ type }) => type === 'bench:complete').data;
|
|
assert.deepStrictEqual(diagnostic.message, {
|
|
name: 'node:bench:test:diagnostic',
|
|
message: { value: '42' },
|
|
});
|
|
assert.strictEqual(diagnostic.level, 'info');
|
|
assert.strictEqual(diagnostic.phase, 'measurement');
|
|
assert.strictEqual(diagnostic.index, 0);
|
|
assert.strictEqual(diagnostic.detail, undefined);
|
|
assert.strictEqual(diagnostic.benchId, completion.benchId);
|
|
assert.strictEqual(diagnostic.fileRunId, completion.fileRunId);
|
|
assert.strictEqual(completion.error, undefined);
|
|
}
|
|
|
|
for (const { kind, message } of [
|
|
{ kind: 'sequence', message: /valid record sequence/ },
|
|
{ kind: 'record', message: /not a valid benchmark record/ },
|
|
{ kind: 'identity', message: /not a valid benchmark record/ },
|
|
{ kind: 'name-path', message: /not a valid benchmark record/ },
|
|
{ kind: 'plan', message: /not a valid benchmark plan/ },
|
|
{ kind: 'timeout', message: /not a valid benchmark plan/ },
|
|
{ kind: 'diagnostic', message: /not a valid benchmark diagnostic/ },
|
|
{ kind: 'diagnostic-order', message: /valid lifecycle sequence/ },
|
|
{ kind: 'summary', message: /not a valid benchmark summary/ },
|
|
]) {
|
|
const result = spawnBench([
|
|
'--bench-reporter=json',
|
|
fixtures.path('bench-runner/malformed-record.cjs'),
|
|
], {
|
|
env: {
|
|
__proto__: null,
|
|
...process.env,
|
|
NODE_BENCH_MALFORMED_RECORD: kind,
|
|
},
|
|
});
|
|
assert.strictEqual(result.status, 1);
|
|
const records = parseRecords(result);
|
|
const diagnostics = records.filter(
|
|
({ type }) => type === 'bench:diagnostic');
|
|
assert(diagnostics.some(({ data }) => message.test(data.message)));
|
|
assert.strictEqual(records.at(-1).data.success, false);
|
|
}
|
|
|
|
{
|
|
const result = spawnBench([
|
|
'--bench-reporter=json',
|
|
fixtures.path('bench-runner/malformed-plan-order.mjs'),
|
|
]);
|
|
assert.strictEqual(result.status, 1);
|
|
const records = parseRecords(result);
|
|
const diagnostics = records.filter(
|
|
({ type }) => type === 'bench:diagnostic');
|
|
assert(diagnostics.some(
|
|
({ data }) => /valid lifecycle sequence/.test(data.message)));
|
|
assert.strictEqual(records.at(-1).data.success, false);
|
|
}
|
|
|
|
{
|
|
const result = spawnBench([
|
|
'--bench-isolation=none',
|
|
'--bench-reporter=json',
|
|
fixtures.path('bench-runner/a.cjs'),
|
|
fixtures.path('bench-runner/exit-code.cjs'),
|
|
]);
|
|
assert.strictEqual(result.status, 1);
|
|
const records = parseRecords(result);
|
|
const diagnostic = records.find(({ type, data }) =>
|
|
type === 'bench:diagnostic' && /set exit code/.test(data.message)).data;
|
|
assert.strictEqual(diagnostic.entryFile, null);
|
|
assert.strictEqual(diagnostic.fileRunId, null);
|
|
assert.strictEqual(diagnostic.file, null);
|
|
}
|
|
|
|
for (const { mode, message } of [
|
|
{ mode: 'code', message: /failed with exit code 2/ },
|
|
{ mode: 'late', message: /failed with exit code 2/ },
|
|
...common.isWindows ? [] : [
|
|
{ mode: 'signal', message: /failed with signal SIGTERM/ },
|
|
],
|
|
]) {
|
|
const result = spawnBench([
|
|
'--bench-reporter=json',
|
|
fixtures.path('bench-runner/abrupt-exit.cjs'),
|
|
], {
|
|
env: {
|
|
__proto__: null,
|
|
...process.env,
|
|
NODE_BENCH_EXIT_MODE: mode,
|
|
},
|
|
});
|
|
assert.strictEqual(result.status, 1);
|
|
const records = parseRecords(result);
|
|
const diagnostics = records.filter(
|
|
({ type }) => type === 'bench:diagnostic');
|
|
assert(diagnostics.some(({ data }) => message.test(data.message)));
|
|
}
|
|
|
|
for (const mode of ['callback', 'throw']) {
|
|
const result = spawnBench([
|
|
'--bench-reporter=json',
|
|
fixtures.path('bench-runner/send-error.cjs'),
|
|
], {
|
|
env: {
|
|
__proto__: null,
|
|
...process.env,
|
|
NODE_BENCH_SEND_ERROR: mode,
|
|
},
|
|
});
|
|
assert.strictEqual(result.status, 1);
|
|
const records = parseRecords(result);
|
|
const diagnostics = records.filter(
|
|
({ type }) => type === 'bench:diagnostic');
|
|
const messages = diagnostics.map(({ data }) => data.message).join('');
|
|
assert.match(messages, /benchmark send/);
|
|
}
|
|
|
|
{
|
|
const result = spawnBench([
|
|
'--bench-reporter=json',
|
|
fixtures.path('bench-runner/run.cjs'),
|
|
]);
|
|
assert.strictEqual(result.status, 1);
|
|
const records = parseRecords(result);
|
|
const diagnostic = records.find(
|
|
({ type }) => type === 'bench:diagnostic');
|
|
assert.match(diagnostic.data.message,
|
|
/run\(\) cannot be called from a file run with --bench/);
|
|
assert.strictEqual(records.at(-1).data.success, false);
|
|
}
|
|
|
|
{
|
|
const result = spawnBench([
|
|
'--bench-reporter=json',
|
|
fixtures.path('bench-runner/exit-code.cjs'),
|
|
]);
|
|
assert.strictEqual(result.status, 1);
|
|
const records = parseRecords(result);
|
|
assert(records.some(({ type, data }) =>
|
|
type === 'bench:diagnostic' && /set exit code/.test(data.message)));
|
|
assert.strictEqual(records.at(-1).data.success, false);
|
|
}
|