// Flags: --experimental-bench --no-warnings
'use strict';
const common = require('../common');
const { completeSample } = require('../common/bench');
const assert = require('assert');
const { createRunner } = require('node:bench');
const { setImmediate } = require('timers/promises');
async function testSynchronousSuiteFailure() {
const runner = createRunner({ yieldBetweenSamples: false });
const completion = runner.suite('outer', () => {
runner.suite('nested', () => {
runner.bench('blocked', { samples: 1 }, common.mustNotCall());
});
throw new Error('synchronous suite failure');
});
const records = await runner.run().toArray();
await completion;
const plan = records.find(
({ type }) => type === 'bench:plan').data;
const result = records.find(
({ type }) => type === 'bench:complete').data;
assert.strictEqual(plan.name, 'blocked');
assert.strictEqual(plan.selected, true);
assert.strictEqual(
records.some(({ type }) => type === 'bench:start'), false);
assert.strictEqual(result.name, 'blocked');
assert.strictEqual(result.error.message, 'synchronous suite failure');
}
async function testRunSignal() {
const runner = createRunner();
const controller = new AbortController();
let invocations = 0;
let abortPromise;
const completion = runner.bench('aborted between samples', {
samples: 3,
}, (b) => {
invocations++;
completeSample(b);
if (b.index === 0) {
abortPromise = setImmediate().then(() => {
controller.abort(new Error('run aborted'));
});
}
});
await runner.run({ signal: controller.signal }).toArray();
const result = await completion;
await abortPromise;
await setImmediate();
assert.strictEqual(result.error.code, 'ABORT_ERR');
assert.strictEqual(result.error.cause.message, 'run aborted');
assert.strictEqual(invocations, 1);
}
async function testRunSignalAfterSample() {
const runner = createRunner({ yieldBetweenSamples: false });
const controller = new AbortController();
const reason = new Error('sample aborted');
const completion = runner.bench('aborted after sample', {
samples: 2,
}, completeSample);
const stream = runner.run({ signal: controller.signal });
stream.once('bench:sample', common.mustCall(() => {
controller.abort(reason);
}));
const records = await stream.toArray();
const result = await completion;
assert.strictEqual(result.error.code, 'ABORT_ERR');
assert.strictEqual(result.error.cause, reason);
assert.strictEqual(result.samples.length, 1);
assert.strictEqual(records.at(-1).data.success, false);
}
async function testStringNamePattern() {
const runner = createRunner({ yieldBetweenSamples: false });
runner.bench('included', { samples: 1 }, completeSample);
runner.bench('excluded', { samples: 1 }, common.mustNotCall());
const records = await runner.run({ namePattern: 'included' }).toArray();
const excluded = records.find(
({ type, data }) => type === 'bench:complete' &&
data.name === 'excluded').data;
const included = records.find(
({ type, data }) => type === 'bench:complete' &&
data.name === 'included').data;
assert.strictEqual(included.error, undefined);
assert.strictEqual(included.samples.length, 1);
assert.strictEqual(excluded.skip, 'name pattern');
}
async function testTopLevelRecovery() {
const runner = createRunner({ yieldBetweenSamples: false });
const suiteCompletion = runner.suite('nested', () => {
runner.bench('listener failure', { samples: 1 }, completeSample);
});
const stream = runner.run();
const failure = new Error();
failure.message = undefined;
stream.on('bench:start', common.mustCall(() => { throw failure; }));
const records = await stream.toArray();
await suiteCompletion;
const diagnostic = records.find(
({ type }) => type === 'bench:diagnostic').data;
const summary = records.find(({ type }) => type === 'bench:summary').data;
assert.strictEqual(diagnostic.message, 'Error');
assert.strictEqual(diagnostic.file, undefined);
assert.strictEqual(diagnostic.line, undefined);
assert.strictEqual(diagnostic.column, undefined);
assert.strictEqual(summary.duration_ns, 0n);
assert.strictEqual(summary.success, false);
}
async function testRepeatedReportingFailure() {
const runner = createRunner({ yieldBetweenSamples: false });
const original = new Error('start listener failed');
const diagnostic = new Error('diagnostic listener failed');
const summary = new Error('summary listener failed');
const completion = runner.bench('reporting failures', {
samples: 1,
}, completeSample);
const stream = runner.run();
stream.on('bench:start', common.mustCall(() => { throw original; }));
stream.on('bench:diagnostic', common.mustCall(() => {
throw diagnostic;
}, 2));
stream.on('bench:summary', common.mustCall(() => { throw summary; }));
const ended = new Promise((resolve) => stream.once('end', resolve));
stream.resume();
await ended;
assert.strictEqual((await completion).error, original);
}
(async () => {
await testSynchronousSuiteFailure();
await testRunSignal();
await testRunSignalAfterSample();
await testStringNamePattern();
await testTopLevelRecovery();
await testRepeatedReportingFailure();
})().then(common.mustCall());