Files
node/test/parallel/test-bench-validation.js
T
Shelley Vohr 7991140d5b test: make node:bench test samples survive a coarse clock
Most node:bench tests record a sample with `b.start();
process.hrtime.bigint(); b.end(1)`, counting on the extra clock read to
make end() see a later timestamp than start(). On a debian12-x64 CI
host the monotonic clock is coarse enough that all three reads returned
the same value, so end() threw ERR_INVALID_STATE ("insufficient clock
precision for benchmark sample") and test-bench-harness-errors failed;
every test using the idiom can fail the same way there.

Add test/common/bench.js with completeSample(), which spins until
process.hrtime.bigint() moves between start() and end(), and use it at
all of those sites, bench-runner fixtures included.

Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/65780
Fixes: https://github.com/nodejs/node/issues/64226
Refs: https://github.com/nodejs/node/issues/59146
Refs: https://github.com/nodejs/node/issues/54534
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
2026-09-06 08:43:54 +00:00

81 lines
3.0 KiB
JavaScript

// Flags: --no-warnings
'use strict';
const common = require('../common');
const { completeSample } = require('../common/bench');
const assert = require('assert');
const { bench, createRunner, run } = require('node:bench');
const noop = () => {};
let functionOverloadCalls = 0;
let objectOverloadCalls = 0;
function functionOverload(b) {
functionOverloadCalls++;
completeSample(b);
b.done();
}
function objectOverload(b) {
objectOverloadCalls++;
completeSample(b);
}
assert.throws(() => bench('', noop), { code: 'ERR_INVALID_ARG_VALUE' });
assert.throws(() => bench('name', null), { code: 'ERR_INVALID_ARG_TYPE' });
assert.throws(() => bench('name', { samples: 0 }, noop),
{ code: 'ERR_OUT_OF_RANGE' });
assert.throws(() => bench('name', { warmup: -1 }, noop),
{ code: 'ERR_OUT_OF_RANGE' });
assert.throws(() => bench('name', { timeout: -1 }, noop),
{ code: 'ERR_OUT_OF_RANGE' });
assert.throws(() => bench('name', { signal: {} }, noop),
{ code: 'ERR_INVALID_ARG_TYPE' });
assert.throws(() => bench('name', { diagnosticChannels: 'channel' }, noop),
{ code: 'ERR_INVALID_ARG_TYPE' });
assert.throws(() => bench('name', { diagnosticChannels: [1] }, noop),
{ code: 'ERR_INVALID_ARG_TYPE' });
assert.throws(() => bench('name', { tags: 'fast' }, noop),
{ code: 'ERR_INVALID_ARG_TYPE' });
assert.throws(() => bench('name', { tags: [''] }, noop),
{ code: 'ERR_INVALID_ARG_VALUE' });
assert.throws(() => bench('name', { params: { value: null } }, noop),
{ code: 'ERR_INVALID_ARG_TYPE' });
assert.throws(() => bench('name', { params: { value: NaN } }, noop),
{ code: 'ERR_OUT_OF_RANGE' });
assert.throws(() => bench('name', { only: 'yes' }, noop),
{ code: 'ERR_INVALID_ARG_TYPE' });
assert.throws(() => bench('name', { skip: 1 }, noop),
{ code: 'ERR_INVALID_ARG_TYPE' });
assert.throws(() => run({ namePattern: 1 }),
{ code: 'ERR_INVALID_ARG_TYPE' });
assert.throws(() => run({ samples: 0 }),
{ code: 'ERR_OUT_OF_RANGE' });
assert.throws(() => run({ warmup: -1 }),
{ code: 'ERR_OUT_OF_RANGE' });
assert.throws(() => run({ yieldBetweenSamples: 1 }),
{ code: 'ERR_INVALID_ARG_TYPE' });
assert.throws(() => createRunner(null),
{ code: 'ERR_INVALID_ARG_TYPE' });
assert.throws(() => createRunner({ yieldBetweenSamples: 1 }),
{ code: 'ERR_INVALID_ARG_TYPE' });
assert.throws(() => createRunner({ yieldBetweenSamples: null }),
{ code: 'ERR_INVALID_ARG_TYPE' });
bench(functionOverload);
bench({ samples: 1 }, objectOverload);
bench('valid', { samples: 1 }, (b) => {
completeSample(b);
});
const stream = run();
stream.on('bench:start', common.mustCall(() => {
assert.throws(() => bench('late', noop), { code: 'ERR_INVALID_STATE' });
}, 3));
stream.on('end', common.mustCall(() => {
assert.strictEqual(functionOverloadCalls, 1);
assert.strictEqual(objectOverloadCalls, 1);
}));
stream.resume();