|
1 | 1 | import { describe, expect, test } from "bun:test" |
2 | | -import { createUndiciDispatcher } from "@opencode-ai/core/util/undici-dispatcher" |
| 2 | +import { Agent } from "undici" |
| 3 | +import { resolveTimeoutMs, createUndiciDispatcher } from "@opencode-ai/core/util/undici-dispatcher" |
3 | 4 |
|
4 | | -describe("createUndiciDispatcher", () => { |
5 | | - test("positive number returns an Agent with matching headersTimeout and bodyTimeout", () => { |
6 | | - const agent = createUndiciDispatcher(600_000) as InstanceType<typeof import("undici").Agent> | undefined |
7 | | - if (!agent) return // Bun — dispatcher is always undefined |
8 | | - expect((agent as unknown as { headersTimeout: number }).headersTimeout).toBe(600_000) |
9 | | - expect((agent as unknown as { bodyTimeout: number }).bodyTimeout).toBe(600_000) |
| 5 | +describe("resolveTimeoutMs", () => { |
| 6 | + test("false → 0 (disabled)", () => { |
| 7 | + expect(resolveTimeoutMs(false)).toBe(0) |
10 | 8 | }) |
11 | 9 |
|
12 | | - test("false returns an Agent with headersTimeout and bodyTimeout set to 0", () => { |
13 | | - const agent = createUndiciDispatcher(false) as InstanceType<typeof import("undici").Agent> | undefined |
14 | | - if (!agent) return // Bun |
15 | | - expect((agent as unknown as { headersTimeout: number }).headersTimeout).toBe(0) |
16 | | - expect((agent as unknown as { bodyTimeout: number }).bodyTimeout).toBe(0) |
| 10 | + test("positive number → that value in ms", () => { |
| 11 | + expect(resolveTimeoutMs(600_000)).toBe(600_000) |
17 | 12 | }) |
18 | 13 |
|
19 | | - test("undefined returns undefined (undici defaults apply)", () => { |
20 | | - expect(createUndiciDispatcher(undefined)).toBeUndefined() |
| 14 | + test("undefined → undefined (undici defaults apply)", () => { |
| 15 | + expect(resolveTimeoutMs(undefined)).toBeUndefined() |
21 | 16 | }) |
22 | 17 |
|
23 | | - test("0 returns undefined (not a positive number)", () => { |
24 | | - expect(createUndiciDispatcher(0)).toBeUndefined() |
| 18 | + test("0 → undefined (not a positive number)", () => { |
| 19 | + expect(resolveTimeoutMs(0)).toBeUndefined() |
25 | 20 | }) |
26 | 21 |
|
27 | | - test("negative number returns undefined", () => { |
28 | | - expect(createUndiciDispatcher(-1)).toBeUndefined() |
| 22 | + test("negative number → undefined", () => { |
| 23 | + expect(resolveTimeoutMs(-1)).toBeUndefined() |
29 | 24 | }) |
30 | 25 |
|
31 | | - test("null returns undefined", () => { |
32 | | - expect(createUndiciDispatcher(null)).toBeUndefined() |
| 26 | + test("null → undefined", () => { |
| 27 | + expect(resolveTimeoutMs(null)).toBeUndefined() |
33 | 28 | }) |
34 | 29 |
|
35 | | - test("string returns undefined", () => { |
36 | | - expect(createUndiciDispatcher("300000")).toBeUndefined() |
| 30 | + test("string → undefined", () => { |
| 31 | + expect(resolveTimeoutMs("300000")).toBeUndefined() |
37 | 32 | }) |
| 33 | +}) |
38 | 34 |
|
| 35 | +describe("createUndiciDispatcher", () => { |
39 | 36 | test("Bun guard: returns undefined when process.versions.bun is set", () => { |
40 | 37 | const original = (process.versions as Record<string, string | undefined>).bun |
41 | 38 | ;(process.versions as Record<string, string | undefined>).bun = "1.0.0" |
42 | 39 | try { |
43 | 40 | expect(createUndiciDispatcher(600_000)).toBeUndefined() |
| 41 | + expect(createUndiciDispatcher(false)).toBeUndefined() |
| 42 | + } finally { |
| 43 | + if (original === undefined) delete (process.versions as Record<string, string | undefined>).bun |
| 44 | + else (process.versions as Record<string, string | undefined>).bun = original |
| 45 | + } |
| 46 | + }) |
| 47 | + |
| 48 | + test("returns undefined when no bun version and timeout resolves to undefined", () => { |
| 49 | + const original = (process.versions as Record<string, string | undefined>).bun |
| 50 | + ;(process.versions as Record<string, string | undefined>).bun = undefined |
| 51 | + try { |
| 52 | + expect(createUndiciDispatcher(undefined)).toBeUndefined() |
| 53 | + expect(createUndiciDispatcher(0)).toBeUndefined() |
| 54 | + } finally { |
| 55 | + if (original === undefined) delete (process.versions as Record<string, string | undefined>).bun |
| 56 | + else (process.versions as Record<string, string | undefined>).bun = original |
| 57 | + } |
| 58 | + }) |
| 59 | + |
| 60 | + // Under Bun, createUndiciDispatcher always returns undefined because of the |
| 61 | + // guard. The Agent construction path only runs under Node. We verify it |
| 62 | + // returns an Agent instance (not private fields) when the bun guard is |
| 63 | + // removed and a valid timeout is provided. |
| 64 | + test("returns an Agent instance under Node (bun guard bypassed)", () => { |
| 65 | + const original = (process.versions as Record<string, string | undefined>).bun |
| 66 | + ;(process.versions as Record<string, string | undefined>).bun = undefined |
| 67 | + try { |
| 68 | + const agent = createUndiciDispatcher(600_000) |
| 69 | + expect(agent).toBeInstanceOf(Agent) |
44 | 70 | } finally { |
45 | 71 | if (original === undefined) delete (process.versions as Record<string, string | undefined>).bun |
46 | 72 | else (process.versions as Record<string, string | undefined>).bun = original |
|
0 commit comments