Files
technitium-console/hub/upstream.test.ts
T
DenozordecandClaude Opus 5.5 18d98449b2
Hub / check (push) Successful in 58s
Hub / image (push) Successful in 1m46s
Hub: gzip and long cache for the console, clearer and faster upstream failures
- Static text files are gzipped and the hashed files under assets/ are
  cached for a year; the 1.6 MB bundle was sent whole on every visit.
- A proxy's error page (502 Bad Gateway) is reported as its HTTP status
  instead of a JSON parse error.
- Reads asked at the same time share one upstream request.
- After a timeout, reads of that server fail at once for 10 s instead of
  each waiting the full timeout.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-07 10:07:22 +07:00

42 lines
1.8 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { Upstream } from './upstream.ts'
import type { HubConfig } from './config.ts'
const server = { id: 'a', url: 'http://a.test', token: 't' }
const config = { cacheSeconds: 15, timeoutMs: 20 } as HubConfig
const ok = () => new Response(JSON.stringify({ status: 'ok', response: { n: 1 } }), { headers: { 'content-type': 'application/json' } })
describe('Upstream', () => {
it('shares one request among reads asked at the same time', async () => {
let calls = 0
const up = new Upstream(config, (async () => {
calls++
return ok()
}) as typeof fetch)
await Promise.all([up.call(server, 'x'), up.call(server, 'x'), up.call(server, 'x')])
expect(calls).toBe(1)
})
it('names the HTTP status when a proxy answers with a page', async () => {
const up = new Upstream(config, (async () =>
new Response('Bad Gateway', { status: 502, statusText: 'Bad Gateway', headers: { 'content-type': 'text/plain' } })) as typeof fetch)
await expect(up.call(server, 'x')).rejects.toThrow('HTTP 502 Bad Gateway')
})
it('after a timeout, fails reads of that server at once for a while', async () => {
let now = 0
let calls = 0
const hang = ((_url: string, init: RequestInit) => {
calls++
return new Promise((_resolve, reject) => init.signal?.addEventListener('abort', () => reject(Object.assign(new Error('aborted'), { name: 'AbortError' }))))
}) as unknown as typeof fetch
const up = new Upstream(config, hang, () => now)
await expect(up.call(server, 'x')).rejects.toThrow('timed out after 20 ms')
await expect(up.call(server, 'y')).rejects.toThrow('timed out')
expect(calls).toBe(1)
now = 11_000
await expect(up.call(server, 'y')).rejects.toThrow('timed out')
expect(calls).toBe(2)
})
})