From dacb106da8bfd55559c18076d27015ce49391c75 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Fri, 4 Sep 2026 07:56:29 +0000 Subject: [PATCH 1/6] test: ignore tunnel resets in proxy invalid-char-in-url test test-https-proxy-request-invalid-char-in-url is the only client-proxy test that asserts the proxy logged no socket errors at all. Once the last response has been read the client destroys its tunnel, and if the proxy is still relaying the upstream's TLS close_notify at that point the client answers with a reset, which the proxy records as ECONNRESET on the CONNECT socket. That has been failing the test on macOS even though every request was routed to the sanitized URL. Keep asserting on other errors but leave connection resets out. Signed-off-by: Shelley Vohr --- .../test-https-proxy-request-invalid-char-in-url.mjs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/client-proxy/test-https-proxy-request-invalid-char-in-url.mjs b/test/client-proxy/test-https-proxy-request-invalid-char-in-url.mjs index 888137b9a5a6..6f27f0775aee 100644 --- a/test/client-proxy/test-https-proxy-request-invalid-char-in-url.mjs +++ b/test/client-proxy/test-https-proxy-request-invalid-char-in-url.mjs @@ -83,7 +83,9 @@ for (const testCase of testCases) { server.close(); assert.deepStrictEqual(requests, expectedUrls); const requestLogs = logs.filter((log) => !('error' in log)); - const errors = logs.filter((log) => 'error' in log); + // The client may reset a tunnel while the proxy is still relaying + // the upstream's TLS shutdown; that says nothing about the URLs. + const errors = logs.filter((log) => 'error' in log && log.error.code !== 'ECONNRESET'); assert.deepStrictEqual(new Set(requestLogs), expectedProxyLogs); assert.deepStrictEqual(errors, []); })); From dc5de0a08690c63fccd92da38e61a2e2108e40f9 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Fri, 4 Sep 2026 08:07:27 +0000 Subject: [PATCH 2/6] test: do not dump core in external memory limit test test-external-memory-reasonable-size makes a child allocate 1.2 GB of external memory so that V8's --external-memory-max-reasonable-size check fires and the process aborts. The abort raises SIGABRT with all of that memory resident, and on hosts that write core files (the SmartOS CI machines in particular) the dump takes longer than the test timeout, so the test has been timing out there since it was added. Run the child under `ulimit -c 0` on POSIX, the same way test-abort-fatal-error and common.childShouldThrowAndAbort() handle their aborting children. Refs: https://github.com/nodejs/node/pull/65589 Signed-off-by: Shelley Vohr --- .../test-external-memory-reasonable-size.js | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/test/parallel/test-external-memory-reasonable-size.js b/test/parallel/test-external-memory-reasonable-size.js index 14e2573328ba..f9ff1af8e5a1 100644 --- a/test/parallel/test-external-memory-reasonable-size.js +++ b/test/parallel/test-external-memory-reasonable-size.js @@ -8,7 +8,7 @@ const common = require('../common'); const assert = require('assert'); -const { spawnSync } = require('child_process'); +const { execSync } = require('child_process'); const { totalmem } = require('os'); // The smallest limit V8 accepts is 1 GB, so the child has to allocate more @@ -20,14 +20,15 @@ for (const flag of [ '--external-memory-max-reasonable-size=1', '--external_memory_max_reasonable_size=1', ]) { - const child = spawnSync(process.execPath, [ - flag, '-e', 'new Float64Array(150_000_000)', - ]); - - assert.notStrictEqual( - child.status, - 0, - `${flag} was not honored, the child exited cleanly`, + // The child aborts with over a gigabyte resident, so keep it from writing a + // core file; on some hosts that dump alone outlasts the test timeout. + const [cmd, opts] = common.escapePOSIXShell`"${process.execPath}" ${flag} -e "new Float64Array(150_000_000)"`; + assert.throws( + () => execSync(common.isWindows ? cmd : `ulimit -c 0; ${cmd}`, { ...opts, stdio: 'pipe' }), + (err) => { + assert.notStrictEqual(err.status, 0, `${flag} was not honored, the child exited cleanly`); + assert.match(err.stderr.toString(), /kMaxReasonableBytes/); + return true; + }, ); - assert.match(child.stderr.toString(), /kMaxReasonableBytes/); } From 44a5ceedf0d8220240fa8d4d6e2bd9b385882b26 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Fri, 4 Sep 2026 08:22:22 +0000 Subject: [PATCH 3/6] test: only count restarts after the write in watch emit-restarted test test-run-watch-emit-restarted expected exactly one test:watch:restarted event, but it starts run({ watch: true }) right after writing the fixtures into the watched directory. Watch backends that deliver events with some latency, FSEvents on macOS most visibly, can still report those setup writes once the first run is under way, which restarts it and makes the later, intentional write the second restart. The test has been marked flaky on macOS x64 for that reason. Wait for the first drain, then require that the write is followed by a restart and a drain, ignoring whatever the setup produced before it, and drop the flaky marker. Refs: https://github.com/nodejs/node/issues/54534 Signed-off-by: Shelley Vohr --- .../test-run-watch-emit-restarted.mjs | 28 ++++++++----------- test/test-runner/test-runner.status | 1 - 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/test/test-runner/test-run-watch-emit-restarted.mjs b/test/test-runner/test-run-watch-emit-restarted.mjs index 200231c69043..fd596bd818ca 100644 --- a/test/test-runner/test-run-watch-emit-restarted.mjs +++ b/test/test-runner/test-run-watch-emit-restarted.mjs @@ -1,5 +1,5 @@ // Test run({ watch: true }) emits test:watch:restarted when file is updated -import * as common from '../common/index.mjs'; +import '../common/index.mjs'; import { run } from 'node:test'; import assert from 'node:assert'; import { writeFileSync } from 'node:fs'; @@ -11,9 +11,8 @@ import { refreshForTestRunnerWatch, skipIfNoWatch, fixtureContent } from '../com skipIfNoWatch(); refreshForTestRunnerWatch(); -let alreadyDrained = false; const events = []; -const testWatchRestarted = common.mustCall(1); +let written = false; const controller = new AbortController(); const stream = run({ @@ -21,27 +20,24 @@ const stream = run({ watch: true, signal: controller.signal, }).on('data', function({ type }) { - events.push(type); - if (type === 'test:watch:restarted') { - testWatchRestarted(); + if (type !== 'test:watch:restarted' && type !== 'test:watch:drained') { + return; } - if (type === 'test:watch:drained') { - if (alreadyDrained) { - controller.abort(); - } - alreadyDrained = true; + events.push(type); + // Watchers with latency (FSEvents) can still report the fixture setup after + // the first run has started, so only a restart after the write below counts. + if (written && type === 'test:watch:drained' && events.at(-2) === 'test:watch:restarted') { + controller.abort(); } }); await once(stream, 'test:watch:drained'); +events.length = 0; +written = true; writeFileSync(join(tmpdir.path, 'test.js'), fixtureContent['test.js']); // eslint-disable-next-line no-unused-vars for await (const _ of stream); -assert.partialDeepStrictEqual(events, [ - 'test:watch:drained', - 'test:watch:restarted', - 'test:watch:drained', -]); +assert.deepStrictEqual(events.slice(-2), ['test:watch:restarted', 'test:watch:drained']); diff --git a/test/test-runner/test-runner.status b/test/test-runner/test-runner.status index 149d6ab689cd..7d2d59d3540c 100644 --- a/test/test-runner/test-runner.status +++ b/test/test-runner/test-runner.status @@ -14,4 +14,3 @@ test-watch-create-isolation-none: SKIP # https://github.com/nodejs/node/issues/54534#issuecomment-5423551021 test-run-watch-cwd-isolation-none: PASS, FLAKY test-run-watch-cwd-isolation-none-argv: PASS, FLAKY -test-run-watch-emit-restarted: PASS, FLAKY From 944dd223c7ae469fe2565749645a015af216ed6d Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Fri, 4 Sep 2026 08:24:27 +0000 Subject: [PATCH 4/6] test: fix the thread-spawn handshake in the WASI threads fixture test-wasi-pthread fails now and then on every platform with "Assertion failed: r == 0 (c/pthread.c: main: 17)", i.e. pthread_create() itself reporting an error. The fixture implements `thread-spawn` by starting a Worker and blocking in Atomics.wait(result, 0, 0, 1000) until the worker signals that it has instantiated the module. Two things go wrong there: the worker signals success by storing 0, the value the main thread is already waiting on, so when the worker is quicker than the main thread its notify is lost and the wait runs into the timeout; and one second is not always enough for a Worker to start and instantiate a threads build on the slower CI hosts (arm debug, Windows, macOS). Either way spawn() returns -6 and wasi-libc turns that into a pthread_create() failure. Wait on a sentinel value that neither outcome writes, and give the worker a platform-scaled 30 seconds. Drop the flaky markers. Fixes: https://github.com/nodejs/node/issues/64226 Refs: https://github.com/nodejs/node/issues/59146 Signed-off-by: Shelley Vohr --- test/fixtures/wasi-preview-1.js | 5 ++++- test/wasi/wasi.status | 7 ------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/test/fixtures/wasi-preview-1.js b/test/fixtures/wasi-preview-1.js index 535bc3e5ec18..3fde5a30b759 100644 --- a/test/fixtures/wasi-preview-1.js +++ b/test/fixtures/wasi-preview-1.js @@ -68,6 +68,9 @@ assert.strictEqual(wasiPreview1.wasiImport, const name = `pthread-${tid}`; const sab = new SharedArrayBuffer(8 + 8192); const result = new Int32Array(sab); + // The thread stores 0 once it has loaded or 1 with an error; wait on a + // value neither of them writes so an early notify cannot be missed. + Atomics.store(result, 0, -1); const workerData = { name, @@ -106,7 +109,7 @@ assert.strictEqual(wasiPreview1.wasiImport, throw new Error(e); }); - const r = Atomics.wait(result, 0, 0, 1000); + const r = Atomics.wait(result, 0, -1, common.platformTimeout(30_000)); if (r === 'timed-out') { workers[tid].terminate(); delete workers[tid]; diff --git a/test/wasi/wasi.status b/test/wasi/wasi.status index 14b671b6e3b1..a26617e01367 100644 --- a/test/wasi/wasi.status +++ b/test/wasi/wasi.status @@ -15,10 +15,3 @@ test-wasi-getrusage: SKIP # Unsupported on Windows and Android test-wasi-readdir: SKIP -[$system==win32 || $system==macos] -# https://github.com/nodejs/node/issues/64226#issuecomment-5423585588 -test-wasi-pthread: PASS, FLAKY - -[$system==linux] -# https://github.com/nodejs/node/issues/59146 -test-wasi-pthread: PASS, FLAKY From 8783b15f462953bbaae7ec9ccca85f4f37836fa5 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Sat, 5 Sep 2026 17:49:59 +0000 Subject: [PATCH 5/6] test: widen the gap in the resolver maxTimeout comparison test-dns-resolver-max-timeout times a query with `{ timeout: 500, tries: 3 }` against one that also sets `maxTimeout: 500` and asserts the first took longer. c-ares only expires a try when cares_wrap's timer fires, every `timeout` ms, so each try costs one or two ticks depending on sub-millisecond ordering, and uncapped retries also get 0.5-1x jitter. That leaves the capped run anywhere in 1500-3000 ms and the uncapped one in 3000-4500 ms; on a busy rhel10-ppc64le host both came out at 3005 ms. With `timeout: 100, tries: 5` the ranges (about 600-1000 ms and 5000-7500 ms measured under load) cannot meet. Signed-off-by: Shelley Vohr --- test/parallel/test-dns-resolver-max-timeout.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/parallel/test-dns-resolver-max-timeout.js b/test/parallel/test-dns-resolver-max-timeout.js index 7abac39323e1..1a4aaef96c96 100644 --- a/test/parallel/test-dns-resolver-max-timeout.js +++ b/test/parallel/test-dns-resolver-max-timeout.js @@ -52,9 +52,11 @@ server.bind(0, common.mustCall(async () => { // Test that maxTimeout is effective. // Without maxTimeout, the timeout will keep increasing when retrying. - const timeout1 = await timeout(address, { timeout: 500, tries: 3 }); - // With maxTimeout, the timeout will always be 500 when retrying. - const timeout2 = await timeout(address, { timeout: 500, tries: 3, maxTimeout: 500 }); + // Expired tries are only noticed on the resolver's `timeout` ms timer tick, + // so use enough tries that the doubling run cannot overlap the capped one. + const timeout1 = await timeout(address, { timeout: 100, tries: 5 }); + // With maxTimeout, the timeout will always be 100 when retrying. + const timeout2 = await timeout(address, { timeout: 100, tries: 5, maxTimeout: 100 }); console.log(`timeout1: ${timeout1}, timeout2: ${timeout2}`); assert.strictEqual(timeout1 !== undefined && timeout2 !== undefined, true); assert.strictEqual(timeout1 > timeout2, true); From b26f47ea2d8a44a69618d7ed15f3f6bac6bc18ad Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Sat, 5 Sep 2026 18:16:32 +0000 Subject: [PATCH 6/6] 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 --- test/common/README.md | 16 ++++++++++++++++ test/common/bench.js | 13 +++++++++++++ test/fixtures/bench-runner/identity-child-a.cjs | 5 ++--- test/fixtures/bench-runner/identity-child-b.cjs | 5 ++--- test/fixtures/bench-runner/identity-preload.cjs | 5 ++--- test/fixtures/bench-runner/identity-shared.cjs | 5 ++--- .../load-error-after-declaration.cjs | 5 ++--- test/fixtures/bench-runner/tools.cjs | 9 ++------- test/parallel/test-bench-context-control.js | 5 ++--- test/parallel/test-bench-context-errors.js | 5 ++--- test/parallel/test-bench-create-runner.js | 17 +++++------------ test/parallel/test-bench-custom-reporter.js | 5 ++--- test/parallel/test-bench-errors.js | 15 +++++---------- test/parallel/test-bench-filtering.js | 5 ++--- test/parallel/test-bench-harness-errors.js | 17 ++++++----------- test/parallel/test-bench-hook-errors.js | 11 +++-------- test/parallel/test-bench-reporters.js | 5 ++--- test/parallel/test-bench-run-options.js | 5 ++--- test/parallel/test-bench-run.js | 9 +++------ test/parallel/test-bench-validation.js | 13 ++++--------- .../test-bench-yield-between-samples.js | 9 +++------ 21 files changed, 82 insertions(+), 102 deletions(-) create mode 100644 test/common/bench.js diff --git a/test/common/README.md b/test/common/README.md index 6c8fcf42847a..193250562972 100644 --- a/test/common/README.md +++ b/test/common/README.md @@ -28,6 +28,7 @@ several other tasks: ## Table of contents * [ArrayStream module](#arraystream-module) +* [Bench module](#bench-module) * [Benchmark module](#benchmark-module) * [Child process module](#child-process-module) * [Common module API](#common-module-api) @@ -49,6 +50,21 @@ several other tasks: * [UDP pair helper](#udp-pair-helper) * [WPT module](#wpt-module) +## Bench module + +The `bench` module has helpers for tests of `node:bench`. + +### `completeSample(b[, operations[, options]])` + +* `b` The `BenchContext` passed to a `node:bench` benchmark function. +* `operations` [\][] Passed to `b.end()`. **Default:** `1`. +* `options` [\][] Passed to `b.end()`. +* return the sample returned by `b.end()`. + +Calls `b.start()` and `b.end()` with at least one `process.hrtime.bigint()` +tick in between, so the sample has a non-zero duration on hosts whose +monotonic clock is coarse. + ## Benchmark module The `benchmark` module is used by tests to run benchmarks. diff --git a/test/common/bench.js b/test/common/bench.js new file mode 100644 index 000000000000..25d67e3a17b2 --- /dev/null +++ b/test/common/bench.js @@ -0,0 +1,13 @@ +'use strict'; + +// Records a sample with start()/end() and at least one hrtime tick in +// between, so its duration is non-zero even on hosts with a coarse clock. +function completeSample(b, operations = 1, options = undefined) { + b.start(); + const started = process.hrtime.bigint(); + let now = started; + while (now === started) now = process.hrtime.bigint(); + return b.end(operations, options); +} + +module.exports = { completeSample }; diff --git a/test/fixtures/bench-runner/identity-child-a.cjs b/test/fixtures/bench-runner/identity-child-a.cjs index 2b8c4b728b1c..ae7824d0ab7d 100644 --- a/test/fixtures/bench-runner/identity-child-a.cjs +++ b/test/fixtures/bench-runner/identity-child-a.cjs @@ -1,11 +1,10 @@ 'use strict'; +const { completeSample } = require('../../common/bench'); const { bench } = require('node:bench'); module.exports = function declareChildA() { bench('child a', { samples: 1 }, (b) => { - b.start(); - process.hrtime.bigint(); - b.end(1); + completeSample(b); }); }; diff --git a/test/fixtures/bench-runner/identity-child-b.cjs b/test/fixtures/bench-runner/identity-child-b.cjs index 249bcdcfc4f1..2841a98055e0 100644 --- a/test/fixtures/bench-runner/identity-child-b.cjs +++ b/test/fixtures/bench-runner/identity-child-b.cjs @@ -1,11 +1,10 @@ 'use strict'; +const { completeSample } = require('../../common/bench'); const { bench } = require('node:bench'); module.exports = function declareChildB() { bench('child b', { samples: 1 }, (b) => { - b.start(); - process.hrtime.bigint(); - b.end(1); + completeSample(b); }); }; diff --git a/test/fixtures/bench-runner/identity-preload.cjs b/test/fixtures/bench-runner/identity-preload.cjs index ed55e627527b..bcc9df72c410 100644 --- a/test/fixtures/bench-runner/identity-preload.cjs +++ b/test/fixtures/bench-runner/identity-preload.cjs @@ -1,9 +1,8 @@ 'use strict'; +const { completeSample } = require('../../common/bench'); const { bench } = require('node:bench'); bench('preload identity', { samples: 1 }, (b) => { - b.start(); - process.hrtime.bigint(); - b.end(1); + completeSample(b); }); diff --git a/test/fixtures/bench-runner/identity-shared.cjs b/test/fixtures/bench-runner/identity-shared.cjs index 40ce0f27be29..c47bcc954745 100644 --- a/test/fixtures/bench-runner/identity-shared.cjs +++ b/test/fixtures/bench-runner/identity-shared.cjs @@ -1,11 +1,10 @@ 'use strict'; +const { completeSample } = require('../../common/bench'); const { bench } = require('node:bench'); module.exports = function registerSharedIdentity() { bench('shared identity', { samples: 1 }, (b) => { - b.start(); - process.hrtime.bigint(); - b.end(1); + completeSample(b); }); }; diff --git a/test/fixtures/bench-runner/load-error-after-declaration.cjs b/test/fixtures/bench-runner/load-error-after-declaration.cjs index eca2188d41c5..6f2cf085742c 100644 --- a/test/fixtures/bench-runner/load-error-after-declaration.cjs +++ b/test/fixtures/bench-runner/load-error-after-declaration.cjs @@ -1,11 +1,10 @@ 'use strict'; +const { completeSample } = require('../../common/bench'); const { bench } = require('node:bench'); bench('declared before load error', { samples: 1 }, (b) => { - b.start(); - process.hrtime.bigint(); - b.end(1); + completeSample(b); }); throw new Error('load failed after declaration'); diff --git a/test/fixtures/bench-runner/tools.cjs b/test/fixtures/bench-runner/tools.cjs index 108a6f81dd63..073a090d8829 100644 --- a/test/fixtures/bench-runner/tools.cjs +++ b/test/fixtures/bench-runner/tools.cjs @@ -1,5 +1,6 @@ 'use strict'; +const { completeSample } = require('../../common/bench'); const { bench } = require('node:bench'); if (process.env.NODE_BENCH_PID_LOG !== undefined) { @@ -10,11 +11,5 @@ if (process.env.NODE_BENCH_PID_LOG !== undefined) { for (const size of [1, 2]) { bench('tools/simple.js', { params: { method: 'loop', size }, - }, (b) => { - let value = 0; - b.start(); - for (let i = 0; i < 1_000; i++) value += size; - b.end(1_000); - if (value === 0) throw new Error('unreachable'); - }); + }, (b) => completeSample(b, 1_000)); } diff --git a/test/parallel/test-bench-context-control.js b/test/parallel/test-bench-context-control.js index b847e926ffcd..6ee095f94eae 100644 --- a/test/parallel/test-bench-context-control.js +++ b/test/parallel/test-bench-context-control.js @@ -2,6 +2,7 @@ 'use strict'; const common = require('../common'); +const { completeSample } = require('../common/bench'); const assert = require('assert'); const { createRunner } = require('node:bench'); @@ -16,9 +17,7 @@ const { createRunner } = require('node:bench'); }, common.mustCall((b) => { invocations.push(`${b.phase}:${b.index}`); const detail = { index: b.index, phase: b.phase }; - b.start(); - process.hrtime.bigint(); - const sample = b.end(2, { detail }); + const sample = completeSample(b, 2, { detail }); detail.index = -1; assert.strictEqual(sample.operations, 2); diff --git a/test/parallel/test-bench-context-errors.js b/test/parallel/test-bench-context-errors.js index 9ba104443ad6..995330c5faef 100644 --- a/test/parallel/test-bench-context-errors.js +++ b/test/parallel/test-bench-context-errors.js @@ -2,15 +2,14 @@ 'use strict'; const common = require('../common'); +const { completeSample } = require('../common/bench'); const assert = require('assert'); const { createRunner } = require('node:bench'); const runner = createRunner({ yieldBetweenSamples: false }); runner.bench('done during warmup', { samples: 1, warmup: 1 }, (b) => { - b.start(); - process.hrtime.bigint(); - b.end(1); + completeSample(b); b.done(); }); runner.bench('invalid record', { samples: 1 }, (b) => b.record(null)); diff --git a/test/parallel/test-bench-create-runner.js b/test/parallel/test-bench-create-runner.js index 5540a189ad52..51474af3d99c 100644 --- a/test/parallel/test-bench-create-runner.js +++ b/test/parallel/test-bench-create-runner.js @@ -2,6 +2,7 @@ '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'); @@ -18,16 +19,12 @@ const { setImmediate } = require('timers/promises'); const firstCompletion = first.bench( 'same name', { samples: 2 }, common.mustCall((b) => { firstCalls++; - b.start(); - process.hrtime.bigint(); - b.end(1); + completeSample(b); }, 2)); const secondCompletion = second.bench( 'same name', { samples: 1 }, common.mustCall((b) => { secondCalls++; - b.start(); - process.hrtime.bigint(); - b.end(1); + completeSample(b); })); await setImmediate(); @@ -74,9 +71,7 @@ const { setImmediate } = require('timers/promises'); const retry = createRunner({ yieldBetweenSamples: false }); retry.bench('not filtered', { samples: 1 }, (b) => { - b.start(); - process.hrtime.bigint(); - b.end(1); + completeSample(b); }); assert.throws(() => retry.run({ namePattern: 'filtered', @@ -90,9 +85,7 @@ const { setImmediate } = require('timers/promises'); const reentrant = createRunner({ yieldBetweenSamples: false }); reentrant.bench('reentrant options', { samples: 1 }, (b) => { - b.start(); - process.hrtime.bigint(); - b.end(1); + completeSample(b); }); const reentrantOptions = {}; Object.defineProperty(reentrantOptions, 'samples', { diff --git a/test/parallel/test-bench-custom-reporter.js b/test/parallel/test-bench-custom-reporter.js index 9589834baf3a..1d4ec8bed191 100644 --- a/test/parallel/test-bench-custom-reporter.js +++ b/test/parallel/test-bench-custom-reporter.js @@ -2,15 +2,14 @@ 'use strict'; const common = require('../common'); +const { completeSample } = require('../common/bench'); const assert = require('assert'); const { Writable } = require('stream'); const { finished } = require('stream/promises'); const { bench, run } = require('node:bench'); bench('completed', { samples: 1 }, (b) => { - b.start(); - process.hrtime.bigint(); - b.end(1); + completeSample(b); }); bench.skip('skipped', { samples: 1 }, common.mustNotCall()); diff --git a/test/parallel/test-bench-errors.js b/test/parallel/test-bench-errors.js index 2124720fee63..e540d5d847c5 100644 --- a/test/parallel/test-bench-errors.js +++ b/test/parallel/test-bench-errors.js @@ -2,6 +2,7 @@ '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'); @@ -40,21 +41,15 @@ bench('late timeout', { samples: 1, timeout: 5 }, async (b) => { }); bench('after late timeout', options, common.mustCall((b) => { assert.strictEqual(lateTimeoutActive, false); - complete(b); + completeSample(b); })); const signal = AbortSignal.abort(new Error('stop')); bench('aborted', { samples: 1, signal }, () => {}); -function complete(b) { - b.start(); - process.hrtime.bigint(); - b.end(1); -} - -bench('duplicate', { samples: 1, params: { value: 1 } }, complete); -bench('duplicate', { samples: 1, params: { value: 1 } }, complete); -bench('continues', options, complete); +bench('duplicate', { samples: 1, params: { value: 1 } }, completeSample); +bench('duplicate', { samples: 1, params: { value: 1 } }, completeSample); +bench('continues', options, completeSample); bench('timeout', { samples: 1, timeout: 10 }, async () => { await new Promise(() => {}); }); diff --git a/test/parallel/test-bench-filtering.js b/test/parallel/test-bench-filtering.js index 39f5368d26a0..da580dcdafc0 100644 --- a/test/parallel/test-bench-filtering.js +++ b/test/parallel/test-bench-filtering.js @@ -2,6 +2,7 @@ 'use strict'; const common = require('../common'); +const { completeSample } = require('../common/bench'); const assert = require('assert'); const { bench, run, suite } = require('node:bench'); @@ -10,9 +11,7 @@ const calls = []; function complete(name) { return (b) => { calls.push(name); - b.start(); - process.hrtime.bigint(); - b.end(1); + completeSample(b); }; } diff --git a/test/parallel/test-bench-harness-errors.js b/test/parallel/test-bench-harness-errors.js index 1cb0b505689f..4fd6ec739488 100644 --- a/test/parallel/test-bench-harness-errors.js +++ b/test/parallel/test-bench-harness-errors.js @@ -2,16 +2,11 @@ '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'); -function complete(b) { - b.start(); - process.hrtime.bigint(); - b.end(1); -} - async function testSynchronousSuiteFailure() { const runner = createRunner({ yieldBetweenSamples: false }); const completion = runner.suite('outer', () => { @@ -43,7 +38,7 @@ async function testRunSignal() { samples: 3, }, (b) => { invocations++; - complete(b); + completeSample(b); if (b.index === 0) { abortPromise = setImmediate().then(() => { controller.abort(new Error('run aborted')); @@ -65,7 +60,7 @@ async function testRunSignalAfterSample() { const reason = new Error('sample aborted'); const completion = runner.bench('aborted after sample', { samples: 2, - }, complete); + }, completeSample); const stream = runner.run({ signal: controller.signal }); stream.once('bench:sample', common.mustCall(() => { controller.abort(reason); @@ -80,7 +75,7 @@ async function testRunSignalAfterSample() { async function testStringNamePattern() { const runner = createRunner({ yieldBetweenSamples: false }); - runner.bench('included', { samples: 1 }, complete); + 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( @@ -97,7 +92,7 @@ async function testStringNamePattern() { async function testTopLevelRecovery() { const runner = createRunner({ yieldBetweenSamples: false }); const suiteCompletion = runner.suite('nested', () => { - runner.bench('listener failure', { samples: 1 }, complete); + runner.bench('listener failure', { samples: 1 }, completeSample); }); const stream = runner.run(); const failure = new Error(); @@ -123,7 +118,7 @@ async function testRepeatedReportingFailure() { const summary = new Error('summary listener failed'); const completion = runner.bench('reporting failures', { samples: 1, - }, complete); + }, completeSample); const stream = runner.run(); stream.on('bench:start', common.mustCall(() => { throw original; })); stream.on('bench:diagnostic', common.mustCall(() => { diff --git a/test/parallel/test-bench-hook-errors.js b/test/parallel/test-bench-hook-errors.js index c4615419674a..f2977f241deb 100644 --- a/test/parallel/test-bench-hook-errors.js +++ b/test/parallel/test-bench-hook-errors.js @@ -2,6 +2,7 @@ 'use strict'; const common = require('../common'); +const { completeSample } = require('../common/bench'); const assert = require('assert'); const { setImmediate } = require('timers/promises'); const { @@ -14,12 +15,6 @@ const { suite, } = require('node:bench'); -function complete(b) { - b.start(); - process.hrtime.bigint(); - b.end(1); -} - suite('before failure', () => { before(() => { throw new Error('before failure'); }); after(common.mustCall()); @@ -34,7 +29,7 @@ suite('beforeEach failure', () => { suite('after failure', () => { after(() => { throw new Error('after failure'); }); - bench('completes before after', { samples: 1 }, complete); + bench('completes before after', { samples: 1 }, completeSample); }); suite('build failure', async () => { @@ -42,7 +37,7 @@ suite('build failure', async () => { throw new Error('build failure'); }); -bench('continues after suite failures', { samples: 1 }, complete); +bench('continues after suite failures', { samples: 1 }, completeSample); const completions = []; const diagnostics = []; diff --git a/test/parallel/test-bench-reporters.js b/test/parallel/test-bench-reporters.js index 44e43bd5be78..f383e2cf5213 100644 --- a/test/parallel/test-bench-reporters.js +++ b/test/parallel/test-bench-reporters.js @@ -2,6 +2,7 @@ 'use strict'; const common = require('../common'); +const { completeSample } = require('../common/bench'); const assert = require('assert'); const { Readable } = require('stream'); const { bench, run } = require('node:bench'); @@ -11,9 +12,7 @@ bench('json completed', { params: { size: 'small' }, samples: 1, }, (b) => { - b.start(); - process.hrtime.bigint(); - b.end(1); + completeSample(b); }); bench('json failed', { samples: 1 }, () => { diff --git a/test/parallel/test-bench-run-options.js b/test/parallel/test-bench-run-options.js index e04bc15ef335..bbb89f5fdc99 100644 --- a/test/parallel/test-bench-run-options.js +++ b/test/parallel/test-bench-run-options.js @@ -2,6 +2,7 @@ 'use strict'; const common = require('../common'); +const { completeSample } = require('../common/bench'); const assert = require('assert'); const { bench, run } = require('node:bench'); @@ -9,9 +10,7 @@ let invocations = 0; const timeout = common.platformTimeout(1000); bench('overridden', { samples: 8, timeout, warmup: 8 }, (b) => { invocations++; - b.start(); - process.hrtime.bigint(); - b.end(invocations); + completeSample(b, invocations); }); const plans = []; diff --git a/test/parallel/test-bench-run.js b/test/parallel/test-bench-run.js index 0e152342bcaa..e79411f83e1d 100644 --- a/test/parallel/test-bench-run.js +++ b/test/parallel/test-bench-run.js @@ -2,6 +2,7 @@ 'use strict'; const common = require('../common'); +const { completeSample } = require('../common/bench'); const assert = require('assert'); const { setImmediate } = require('timers/promises'); const { @@ -42,9 +43,7 @@ const suiteCompletion = suite('group', { tags: ['Group'] }, async () => { contexts.add(b); calls.push('sync sample'); assert.deepStrictEqual(b.params, { __proto__: null, a: true, z: 2 }); - b.start(); - process.hrtime.bigint(); - b.end(1); + completeSample(b); active = false; }, 3)); @@ -54,9 +53,7 @@ const suiteCompletion = suite('group', { tags: ['Group'] }, async () => { contexts.add(b); calls.push('async sample'); await setImmediate(); - b.start(); - process.hrtime.bigint(); - b.end(1); + completeSample(b); await setImmediate(); active = false; }, 2)); diff --git a/test/parallel/test-bench-validation.js b/test/parallel/test-bench-validation.js index fa7a579aa60c..39edc5d411cc 100644 --- a/test/parallel/test-bench-validation.js +++ b/test/parallel/test-bench-validation.js @@ -2,6 +2,7 @@ 'use strict'; const common = require('../common'); +const { completeSample } = require('../common/bench'); const assert = require('assert'); const { bench, createRunner, run } = require('node:bench'); @@ -11,17 +12,13 @@ let objectOverloadCalls = 0; function functionOverload(b) { functionOverloadCalls++; - b.start(); - process.hrtime.bigint(); - b.end(1); + completeSample(b); b.done(); } function objectOverload(b) { objectOverloadCalls++; - b.start(); - process.hrtime.bigint(); - b.end(1); + completeSample(b); } assert.throws(() => bench('', noop), { code: 'ERR_INVALID_ARG_VALUE' }); @@ -69,9 +66,7 @@ bench(functionOverload); bench({ samples: 1 }, objectOverload); bench('valid', { samples: 1 }, (b) => { - b.start(); - process.hrtime.bigint(); - b.end(1); + completeSample(b); }); const stream = run(); diff --git a/test/parallel/test-bench-yield-between-samples.js b/test/parallel/test-bench-yield-between-samples.js index 7d08318a027a..aceb381d1a57 100644 --- a/test/parallel/test-bench-yield-between-samples.js +++ b/test/parallel/test-bench-yield-between-samples.js @@ -2,6 +2,7 @@ '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'); @@ -16,9 +17,7 @@ async function observe(factoryOptions, runOptions) { runner.bench('yielding', { samples: 2 }, (b) => { observed.push(turnOccurred); - b.start(); - process.hrtime.bigint(); - b.end(1); + completeSample(b); }); await runner.run(runOptions).toArray(); @@ -55,9 +54,7 @@ async function observeAfterEachTimeout() { samples: 1, timeout: 5, }, (b) => { - b.start(); - process.hrtime.bigint(); - b.end(1); + completeSample(b); }); await runner.run().toArray(); const result = await completion;