Files
node/test/parallel/test-bench-errors.js
T
Filip Skokan 20b3a690e9 test: deflake test-bench-errors
The 10ms timeout can expire before the benchmark callback starts.
There is then no unsettled work to abort the rest of the run.

Abort from inside the callback to guarantee pending work. Cover timeout
errors separately with a zero timeout.

Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Assisted-by: Codex
PR-URL: https://github.com/nodejs/node/pull/66153
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Xuguang Mei <meixuguang@gmail.com>
2026-09-21 21:44:24 +00:00

130 lines
4.6 KiB
JavaScript

// Flags: --experimental-bench --no-warnings
'use strict';
const common = require('../common');
const { completeSample } = require('../common/bench');
const assert = require('assert');
const { bench, run, suite } = require('node:bench');
const { setTimeout } = require('timers/promises');
const options = { samples: 1 };
bench('missing start', options, () => {});
bench('missing end', options, (b) => b.start());
bench('end before start', options, (b) => b.end(1));
bench('duplicate start', options, (b) => {
b.start();
b.start();
});
bench('duplicate end', options, (b) => {
b.start();
b.end(1);
b.end(1);
});
bench('invalid operations', options, (b) => {
b.start();
b.end(0);
});
bench('throws', options, () => {
throw new Error('benchmark failure');
});
let lateTimeoutActive = false;
bench('late timeout', { samples: 1, timeout: 5 }, async (b) => {
lateTimeoutActive = true;
try {
b.start();
await setTimeout(30);
b.end(1);
} finally {
lateTimeoutActive = false;
}
});
bench('after late timeout', options, common.mustCall((b) => {
assert.strictEqual(lateTimeoutActive, false);
completeSample(b);
}));
const signal = AbortSignal.abort(new Error('stop'));
bench('aborted', { samples: 1, signal }, () => {});
bench('duplicate', { samples: 1, params: { value: 1 } }, completeSample);
bench('duplicate', { samples: 1, params: { value: 1 } }, completeSample);
bench('timeout', { samples: 1, timeout: 0 }, common.mustNotCall());
bench('continues', options, completeSample);
// Aborting from the callback guarantees that there is unsettled work.
const controller = new AbortController();
bench('unsettled abort', { samples: 1, signal: controller.signal }, common.mustCall(async () => {
controller.abort(new Error('stop unsettled work'));
await new Promise(() => {});
}));
const suiteCompletion = suite('after unsettled abort suite', () => {
bench('after unsettled abort', options, common.mustNotCall());
bench.skip('skipped after unsettled abort', options, common.mustNotCall());
});
suiteCompletion.then(common.mustCall());
const completions = [];
const sampleNames = [];
let summary;
const stream = run();
stream.on('bench:complete', (result) => completions.push(result));
stream.on('bench:sample', (sample) => sampleNames.push(sample.name));
stream.on('bench:summary', (result) => { summary = result; });
stream.on('end', common.mustCall(() => {
assert.strictEqual(completions.length, 17);
assert.deepStrictEqual(summary.counts, {
__proto__: null,
completed: 3,
failed: 13,
skipped: 1,
total: 17,
});
assert.strictEqual(summary.success, false);
const byName = new Map();
for (const result of completions) {
const values = byName.get(result.name) ?? [];
values.push(result);
byName.set(result.name, values);
}
assert.match(byName.get('missing start')[0].error.message,
/did not call start/);
assert.match(byName.get('missing end')[0].error.message,
/did not call end/);
assert.match(byName.get('end before start')[0].error.message,
/before start/);
assert.strictEqual(byName.get('duplicate start')[0].error.code,
'ERR_INVALID_STATE');
assert.strictEqual(byName.get('duplicate end')[0].error.code,
'ERR_INVALID_STATE');
assert.strictEqual(byName.get('invalid operations')[0].error.code,
'ERR_OUT_OF_RANGE');
assert.strictEqual(byName.get('throws')[0].error.message,
'benchmark failure');
assert.strictEqual(byName.get('timeout')[0].error.code,
'ERR_OPERATION_FAILED');
assert.strictEqual(byName.get('late timeout')[0].error.code,
'ERR_OPERATION_FAILED');
assert.strictEqual(byName.get('after late timeout')[0].error, undefined);
assert.strictEqual(byName.get('aborted')[0].error.code, 'ABORT_ERR');
const duplicates = byName.get('duplicate');
assert.strictEqual(duplicates[0].error, undefined);
assert.match(duplicates[1].error.message, /duplicate benchmark identity/);
assert.strictEqual(byName.get('continues')[0].error, undefined);
const aborted = byName.get('unsettled abort')[0].error;
assert.strictEqual(aborted.code, 'ABORT_ERR');
assert.deepStrictEqual(aborted.cause, controller.signal.reason);
const unsettled = byName.get('after unsettled abort')[0].error;
assert.strictEqual(unsettled.code, 'ABORT_ERR');
assert.deepStrictEqual(unsettled.cause, aborted);
assert.strictEqual(
byName.get('skipped after unsettled abort')[0].skip, true);
setTimeout(40).then(common.mustCall(() => {
assert.strictEqual(sampleNames.includes('late timeout'), false);
}));
}));
stream.resume();