Skip to content

Commit 49ecaaf

Browse files
committed
fix(test): stub performance.now via defineProperty for Node 18 compat
`performance.now` is a non-writable prototype property on Node 18, so the existing `performance.now = () => ...` assignment threw `TypeError: Cannot assign to read only property 'now'` and all three initialPerformanceCheckup tests failed in the 18.x CI leg (20.x/22.x were silently masked by the matrix fail-fast). Install an own property via `Object.defineProperty` instead — it shadows the prototype method on all supported Node versions — and restore by deleting the own property. https://claude.ai/code/session_01AKDapjnZknLi5YXv6tnb94
1 parent fd41754 commit 49ecaaf

1 file changed

Lines changed: 25 additions & 12 deletions

File tree

test/embedder-performance.test.js

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,35 @@ import assert from 'node:assert/strict'
33
import os from 'os'
44
import { Embedder } from '../src/embedder.js'
55

6+
// `performance.now` lives on a non-writable prototype property in Node 18,
7+
// so plain assignment (`performance.now = ...`) throws. Installing an own
8+
// property via defineProperty shadows it; deleting the own property restores
9+
// access to the original prototype method. Works on Node 18, 20, 22.
10+
function stubPerformanceNow(impl) {
11+
Object.defineProperty(performance, 'now', {
12+
configurable: true,
13+
writable: true,
14+
value: impl,
15+
})
16+
return () => { delete performance.now }
17+
}
18+
619
describe('Embedder performance heuristics', () => {
720
test('initialPerformanceCheckup (CPU) low TPS -> batchSize 32, concurrency 1', async () => {
821
const origInit = Embedder.prototype.initialize
922
const origEmbed = Embedder.prototype.embed
1023
const origDestroy = Embedder.prototype.destroy
11-
const origPerf = performance.now
24+
let restorePerf
1225
try {
1326
Embedder.prototype.initialize = async function () {}
1427
Embedder.prototype.embed = async function (sample) { return sample.map(() => [0]) }
1528
Embedder.prototype.destroy = async function () {}
1629

1730
let calls = 0
18-
performance.now = () => {
31+
restorePerf = stubPerformanceNow(() => {
1932
calls += 1
2033
return calls === 1 ? 0 : 1000
21-
}
34+
})
2235

2336
const cfg = await Embedder.initialPerformanceCheckup({ device: 'cpu', sampleSize: 50, modelName: 'test-model' })
2437
assert.equal(cfg.batchSize, 32)
@@ -28,25 +41,25 @@ describe('Embedder performance heuristics', () => {
2841
Embedder.prototype.initialize = origInit
2942
Embedder.prototype.embed = origEmbed
3043
Embedder.prototype.destroy = origDestroy
31-
performance.now = origPerf
44+
restorePerf?.()
3245
}
3346
})
3447

3548
test('initialPerformanceCheckup (CPU) high TPS -> batchSize 64, concurrency <= 2', async () => {
3649
const origInit = Embedder.prototype.initialize
3750
const origEmbed = Embedder.prototype.embed
3851
const origDestroy = Embedder.prototype.destroy
39-
const origPerf = performance.now
52+
let restorePerf
4053
try {
4154
Embedder.prototype.initialize = async function () {}
4255
Embedder.prototype.embed = async function (sample) { return sample.map(() => [0]) }
4356
Embedder.prototype.destroy = async function () {}
4457

4558
let calls = 0
46-
performance.now = () => {
59+
restorePerf = stubPerformanceNow(() => {
4760
calls += 1
4861
return calls === 1 ? 0 : 1 // tiny elapsed -> very high TPS
49-
}
62+
})
5063

5164
const cfg = await Embedder.initialPerformanceCheckup({ device: 'cpu', sampleSize: 50, modelName: 'test-model' })
5265
assert.equal(cfg.batchSize, 64)
@@ -56,25 +69,25 @@ describe('Embedder performance heuristics', () => {
5669
Embedder.prototype.initialize = origInit
5770
Embedder.prototype.embed = origEmbed
5871
Embedder.prototype.destroy = origDestroy
59-
performance.now = origPerf
72+
restorePerf?.()
6073
}
6174
})
6275

6376
test('initialPerformanceCheckup (GPU) high TPS -> batchSize 128, concurrency 1, dtype fp32', async () => {
6477
const origInit = Embedder.prototype.initialize
6578
const origEmbed = Embedder.prototype.embed
6679
const origDestroy = Embedder.prototype.destroy
67-
const origPerf = performance.now
80+
let restorePerf
6881
try {
6982
Embedder.prototype.initialize = async function () {}
7083
Embedder.prototype.embed = async function (sample) { return sample.map(() => [0]) }
7184
Embedder.prototype.destroy = async function () {}
7285

7386
let calls = 0
74-
performance.now = () => {
87+
restorePerf = stubPerformanceNow(() => {
7588
calls += 1
7689
return calls === 1 ? 0 : 1
77-
}
90+
})
7891

7992
const cfg = await Embedder.initialPerformanceCheckup({ device: 'gpu', sampleSize: 50, modelName: 'test-model' })
8093
assert.equal(cfg.batchSize, 128)
@@ -84,7 +97,7 @@ describe('Embedder performance heuristics', () => {
8497
Embedder.prototype.initialize = origInit
8598
Embedder.prototype.embed = origEmbed
8699
Embedder.prototype.destroy = origDestroy
87-
performance.now = origPerf
100+
restorePerf?.()
88101
}
89102
})
90103

0 commit comments

Comments
 (0)