138 lines
3.9 KiB
TypeScript
138 lines
3.9 KiB
TypeScript
import { afterEach, expect, test, vi } from 'vitest'
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks()
|
|
vi.resetModules()
|
|
vi.doUnmock('undici')
|
|
vi.doUnmock('../../src/utils')
|
|
delete process.env.E2B_API_CONNECTIONS
|
|
delete process.env.E2B_API_INFLIGHT_REQUESTS
|
|
})
|
|
|
|
test('uses undici with a bounded HTTP/2 dispatcher for API requests', async () => {
|
|
const agents: Array<{ allowH2?: boolean; connections?: number }> = []
|
|
const requests: Array<{ init?: RequestInit & { dispatcher?: unknown } }> = []
|
|
|
|
class Agent {
|
|
constructor(options: { allowH2?: boolean; connections?: number }) {
|
|
agents.push(options)
|
|
}
|
|
}
|
|
|
|
const undiciFetch = vi.fn((input, init) => {
|
|
requests.push({ init })
|
|
return Promise.resolve(new Response('ok'))
|
|
})
|
|
const loadUndici = vi.fn(() => Promise.resolve({ Agent, fetch: undiciFetch }))
|
|
|
|
const { createApiFetchForRuntime } = await import('../../src/api/http2')
|
|
|
|
const fetcher = createApiFetchForRuntime('node', {
|
|
connectionLimit: 100,
|
|
loadUndici,
|
|
})
|
|
await fetcher('https://example.com/sandboxes')
|
|
|
|
expect(loadUndici).toHaveBeenCalledOnce()
|
|
expect(agents).toEqual([{ allowH2: true, connections: 100 }])
|
|
expect(requests[0].init?.dispatcher).toBeInstanceOf(Agent)
|
|
})
|
|
|
|
test('uses a ProxyAgent dispatcher when a proxy is configured', async () => {
|
|
const proxyAgents: Array<{
|
|
uri?: string
|
|
allowH2?: boolean
|
|
connections?: number
|
|
}> = []
|
|
const agents: Array<unknown> = []
|
|
const requests: Array<{ init?: RequestInit & { dispatcher?: unknown } }> = []
|
|
|
|
class Agent {
|
|
constructor() {
|
|
agents.push(this)
|
|
}
|
|
}
|
|
|
|
class ProxyAgent {
|
|
constructor(options: {
|
|
uri?: string
|
|
allowH2?: boolean
|
|
connections?: number
|
|
}) {
|
|
proxyAgents.push(options)
|
|
}
|
|
}
|
|
|
|
const undiciFetch = vi.fn((input, init) => {
|
|
requests.push({ init })
|
|
return Promise.resolve(new Response('ok'))
|
|
})
|
|
const loadUndici = vi.fn(() =>
|
|
Promise.resolve({ Agent, ProxyAgent, fetch: undiciFetch })
|
|
)
|
|
|
|
const { createApiFetchForRuntime } = await import('../../src/api/http2')
|
|
|
|
const fetcher = createApiFetchForRuntime('node', {
|
|
connectionLimit: 100,
|
|
proxy: 'http://user:pass@127.0.0.1:8080',
|
|
loadUndici,
|
|
})
|
|
await fetcher('https://example.com/sandboxes')
|
|
|
|
expect(agents).toHaveLength(0)
|
|
expect(proxyAgents).toEqual([
|
|
{
|
|
uri: 'http://user:pass@127.0.0.1:8080',
|
|
allowH2: true,
|
|
connections: 100,
|
|
},
|
|
])
|
|
expect(requests[0].init?.dispatcher).toBeInstanceOf(ProxyAgent)
|
|
})
|
|
|
|
test('caches API fetchers per proxy', async () => {
|
|
const { createApiFetch } = await import('../../src/api/http2')
|
|
|
|
const noProxy = createApiFetch()
|
|
const proxyA = createApiFetch('http://127.0.0.1:8080')
|
|
const proxyB = createApiFetch('http://127.0.0.1:9090')
|
|
|
|
expect(createApiFetch()).toBe(noProxy)
|
|
expect(createApiFetch('http://127.0.0.1:8080')).toBe(proxyA)
|
|
expect(proxyA).not.toBe(noProxy)
|
|
expect(proxyA).not.toBe(proxyB)
|
|
})
|
|
|
|
test('getApiConnectionLimit throws on a malformed env value', async () => {
|
|
process.env.E2B_API_CONNECTIONS = 'not-a-number'
|
|
|
|
const { getApiConnectionLimit } = await import('../../src/api/http2')
|
|
|
|
expect(() => getApiConnectionLimit()).toThrow(/E2B_API_CONNECTIONS/)
|
|
})
|
|
|
|
test('getApiInflightLimit throws on a malformed env value', async () => {
|
|
process.env.E2B_API_INFLIGHT_REQUESTS = 'not-a-number'
|
|
|
|
const { getApiInflightLimit } = await import('../../src/api/http2')
|
|
|
|
expect(() => getApiInflightLimit()).toThrow(/E2B_API_INFLIGHT_REQUESTS/)
|
|
})
|
|
|
|
test('getApiInflightLimit returns 0 when explicitly disabled', async () => {
|
|
process.env.E2B_API_INFLIGHT_REQUESTS = '0'
|
|
|
|
const { getApiInflightLimit } = await import('../../src/api/http2')
|
|
|
|
expect(getApiInflightLimit()).toBe(0)
|
|
})
|
|
|
|
test('getApiInflightLimit throws on negative env value', async () => {
|
|
process.env.E2B_API_INFLIGHT_REQUESTS = '-5'
|
|
|
|
const { getApiInflightLimit } = await import('../../src/api/http2')
|
|
|
|
expect(() => getApiInflightLimit()).toThrow(/E2B_API_INFLIGHT_REQUESTS=-5/)
|
|
})
|