Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 24 additions & 12 deletions test/imf.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,15 +195,18 @@ describe("registry", () => {
const indexUrl = `http://127.0.0.1:${port}/index.yaml`
indexBody = `version: 1\nmodels:\n tiny-1.0:\n filename: tiny.zip\n url: http://127.0.0.1:${port}/tiny.zip\n sha256: ${sha}\n`

const store = new Map<string, Response>()
// store raw bytes: Response.clone() stream semantics differ across
// undici versions (node 20 vs 24) and are irrelevant to the contract
const store = new Map<string, Uint8Array>()
const fakeCache = {
async match(req: RequestInfo) {
const key = String(req instanceof Request ? req.url : req)
return store.get(key)?.clone()
const bytes = store.get(key)
return bytes === undefined ? undefined : new Response(bytes)
},
async put(req: RequestInfo, res: Response) {
const key = String(req instanceof Request ? req.url : req)
store.set(key, res.clone())
store.set(key, new Uint8Array(await res.arrayBuffer()))
},
async delete(req: RequestInfo) {
const key = String(req instanceof Request ? req.url : req)
Expand All @@ -212,29 +215,38 @@ describe("registry", () => {
}
const g = globalThis as Record<string, unknown>
g["caches"] = { open: async () => fakeCache }
// simulate a browser host: no Node fs, so the Cache API path runs
const versions = process.versions as { node?: string }
const realNode = versions.node
delete versions.node
// Simulate a browser host by swapping the globalThis.process
// reference (the registry detects Node via globalThis). Deleting
// process.versions.node instead breaks node 20's bundled undici,
// which splits it inside fetch().
const realProcess = globalThis.process
const withBrowserHost = async <T>(fn: () => Promise<T>): Promise<T> => {
const gg = globalThis as { process?: unknown }
gg.process = { env: {}, versions: {} }
try {
return await fn()
} finally {
gg.process = realProcess
}
}
try {
process.env["SECRYST_CACHE"] = undefined
const first = await resolve("tiny-1.0", indexUrl)
const first = await withBrowserHost(() => resolve("tiny-1.0", indexUrl))
expect([...first.bytes]).toEqual([...fixtureZip])
expect(store.size).toBe(1)

// channel dies; the cached copy serves, still sha-verified
channelUp = false
const second = await resolve("tiny-1.0", indexUrl)
const second = await withBrowserHost(() => resolve("tiny-1.0", indexUrl))
expect([...second.bytes]).toEqual([...fixtureZip])

// a corrupted cache entry falls through to a fresh download
channelUp = true
const key = store.keys().next().value as string
store.set(key, new Response(new Uint8Array([1, 2, 3])))
const third = await resolve("tiny-1.0", indexUrl)
store.set(key, new Uint8Array([1, 2, 3]))
const third = await withBrowserHost(() => resolve("tiny-1.0", indexUrl))
expect([...third.bytes]).toEqual([...fixtureZip])
} finally {
if (realNode !== undefined) versions.node = realNode
delete g["caches"]
delete process.env["SECRYST_CACHE"]
await new Promise<void>((r) => server.close(() => r()))
Expand Down
Loading