proxy-fetch.test.ts 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. import { afterEach, describe, expect, it, vi } from "vitest";
  2. const proxyAgentMock = vi.fn((url: string) => ({ kind: "proxy-agent", url }));
  3. vi.mock("undici", () => ({
  4. ProxyAgent: proxyAgentMock,
  5. }));
  6. describe("proxy fetch helpers", () => {
  7. afterEach(() => {
  8. vi.unstubAllGlobals();
  9. vi.clearAllMocks();
  10. });
  11. it("prefers explicit llm proxyUrl over environment proxy variables", async () => {
  12. const { fetchWithProxy, resolveProxyUrl } = await import("../utils/proxy-fetch.js");
  13. const fetchMock = vi.fn().mockResolvedValue({ ok: true });
  14. vi.stubGlobal("fetch", fetchMock);
  15. const env = {
  16. INKOS_LLM_PROXY_URL: "http://inkos-env-proxy:9910",
  17. HTTPS_PROXY: "http://standard-proxy:9910",
  18. };
  19. expect(resolveProxyUrl("http://explicit-proxy:9910", env)).toBe("http://explicit-proxy:9910");
  20. await fetchWithProxy("https://api.example/v1/chat/completions", { method: "POST" }, "http://explicit-proxy:9910", env);
  21. expect(proxyAgentMock).toHaveBeenCalledWith("http://explicit-proxy:9910");
  22. expect(fetchMock).toHaveBeenCalledWith(
  23. "https://api.example/v1/chat/completions",
  24. expect.objectContaining({
  25. method: "POST",
  26. dispatcher: { kind: "proxy-agent", url: "http://explicit-proxy:9910" },
  27. }),
  28. );
  29. });
  30. it("uses INKOS_LLM_PROXY_URL before standard HTTPS_PROXY/HTTP_PROXY env vars", async () => {
  31. const { fetchWithProxy, resolveProxyUrl } = await import("../utils/proxy-fetch.js");
  32. const fetchMock = vi.fn().mockResolvedValue({ ok: true });
  33. vi.stubGlobal("fetch", fetchMock);
  34. const env = {
  35. INKOS_LLM_PROXY_URL: "http://inkos-proxy:9910",
  36. HTTPS_PROXY: "http://standard-proxy:9910",
  37. HTTP_PROXY: "http://http-proxy:9910",
  38. };
  39. expect(resolveProxyUrl(undefined, env)).toBe("http://inkos-proxy:9910");
  40. await fetchWithProxy("https://api.example/v1/models", {}, undefined, env);
  41. expect(proxyAgentMock).toHaveBeenCalledWith("http://inkos-proxy:9910");
  42. expect(fetchMock).toHaveBeenCalledWith(
  43. "https://api.example/v1/models",
  44. expect.objectContaining({
  45. dispatcher: { kind: "proxy-agent", url: "http://inkos-proxy:9910" },
  46. }),
  47. );
  48. });
  49. it("does not attach a dispatcher when no proxy is configured", async () => {
  50. const { fetchWithProxy, resolveProxyUrl } = await import("../utils/proxy-fetch.js");
  51. const fetchMock = vi.fn().mockResolvedValue({ ok: true });
  52. vi.stubGlobal("fetch", fetchMock);
  53. expect(resolveProxyUrl(undefined, {})).toBeUndefined();
  54. await fetchWithProxy("https://api.example/v1/models", { headers: { Authorization: "Bearer test" } }, undefined, {});
  55. expect(proxyAgentMock).not.toHaveBeenCalled();
  56. expect(fetchMock).toHaveBeenCalledWith(
  57. "https://api.example/v1/models",
  58. { headers: { Authorization: "Bearer test" } },
  59. );
  60. });
  61. });