refactor: share auth overview and fetch test helpers

This commit is contained in:
Peter Steinberger 2026-03-13 18:55:54 +00:00
parent 985be2a864
commit 94e748086c
2 changed files with 47 additions and 81 deletions

View File

@ -1,7 +1,28 @@
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { NON_ENV_SECRETREF_MARKER } from "../../agents/model-auth-markers.js"; import { NON_ENV_SECRETREF_MARKER } from "../../agents/model-auth-markers.js";
import { withEnv } from "../../test-utils/env.js";
import { resolveProviderAuthOverview } from "./list.auth-overview.js"; import { resolveProviderAuthOverview } from "./list.auth-overview.js";
function resolveOpenAiOverview(apiKey: string) {
return resolveProviderAuthOverview({
provider: "openai",
cfg: {
models: {
providers: {
openai: {
baseUrl: "https://api.openai.com/v1",
api: "openai-completions",
apiKey,
models: [],
},
},
},
} as never,
store: { version: 1, profiles: {} } as never,
modelsPath: "/tmp/models.json",
});
}
describe("resolveProviderAuthOverview", () => { describe("resolveProviderAuthOverview", () => {
it("does not throw when token profile only has tokenRef", () => { it("does not throw when token profile only has tokenRef", () => {
const overview = resolveProviderAuthOverview({ const overview = resolveProviderAuthOverview({
@ -24,23 +45,9 @@ describe("resolveProviderAuthOverview", () => {
}); });
it("renders marker-backed models.json auth as marker detail", () => { it("renders marker-backed models.json auth as marker detail", () => {
const overview = resolveProviderAuthOverview({ const overview = withEnv({ OPENAI_API_KEY: undefined }, () =>
provider: "openai", resolveOpenAiOverview(NON_ENV_SECRETREF_MARKER),
cfg: { );
models: {
providers: {
openai: {
baseUrl: "https://api.openai.com/v1",
api: "openai-completions",
apiKey: NON_ENV_SECRETREF_MARKER,
models: [],
},
},
},
} as never,
store: { version: 1, profiles: {} } as never,
modelsPath: "/tmp/models.json",
});
expect(overview.effective.kind).toBe("missing"); expect(overview.effective.kind).toBe("missing");
expect(overview.effective.detail).toBe("missing"); expect(overview.effective.detail).toBe("missing");
@ -48,23 +55,9 @@ describe("resolveProviderAuthOverview", () => {
}); });
it("keeps env-var-shaped models.json values masked to avoid accidental plaintext exposure", () => { it("keeps env-var-shaped models.json values masked to avoid accidental plaintext exposure", () => {
const overview = resolveProviderAuthOverview({ const overview = withEnv({ OPENAI_API_KEY: undefined }, () =>
provider: "openai", resolveOpenAiOverview("OPENAI_API_KEY"),
cfg: { );
models: {
providers: {
openai: {
baseUrl: "https://api.openai.com/v1",
api: "openai-completions",
apiKey: "OPENAI_API_KEY", // pragma: allowlist secret
models: [],
},
},
},
} as never,
store: { version: 1, profiles: {} } as never,
modelsPath: "/tmp/models.json",
});
expect(overview.effective.kind).toBe("missing"); expect(overview.effective.kind).toBe("missing");
expect(overview.effective.detail).toBe("missing"); expect(overview.effective.detail).toBe("missing");
@ -76,23 +69,7 @@ describe("resolveProviderAuthOverview", () => {
const prior = process.env.OPENAI_API_KEY; const prior = process.env.OPENAI_API_KEY;
process.env.OPENAI_API_KEY = "sk-openai-from-env"; // pragma: allowlist secret process.env.OPENAI_API_KEY = "sk-openai-from-env"; // pragma: allowlist secret
try { try {
const overview = resolveProviderAuthOverview({ const overview = resolveOpenAiOverview("OPENAI_API_KEY");
provider: "openai",
cfg: {
models: {
providers: {
openai: {
baseUrl: "https://api.openai.com/v1",
api: "openai-completions",
apiKey: "OPENAI_API_KEY", // pragma: allowlist secret
models: [],
},
},
},
} as never,
store: { version: 1, profiles: {} } as never,
modelsPath: "/tmp/models.json",
});
expect(overview.effective.kind).toBe("env"); expect(overview.effective.kind).toBe("env");
expect(overview.effective.detail).not.toContain("OPENAI_API_KEY"); expect(overview.effective.detail).not.toContain("OPENAI_API_KEY");
} finally { } finally {

View File

@ -3,9 +3,22 @@ import { botCtorSpy } from "./bot.create-telegram-bot.test-harness.js";
import { createTelegramBot } from "./bot.js"; import { createTelegramBot } from "./bot.js";
import { getTelegramNetworkErrorOrigin } from "./network-errors.js"; import { getTelegramNetworkErrorOrigin } from "./network-errors.js";
function createWrappedTelegramClientFetch(proxyFetch: typeof fetch) {
const shutdown = new AbortController();
botCtorSpy.mockClear();
createTelegramBot({
token: "tok",
fetchAbortSignal: shutdown.signal,
proxyFetch,
});
const clientFetch = (botCtorSpy.mock.calls.at(-1)?.[1] as { client?: { fetch?: unknown } })
?.client?.fetch as (input: RequestInfo | URL, init?: RequestInit) => Promise<unknown>;
expect(clientFetch).toBeTypeOf("function");
return { clientFetch, shutdown };
}
describe("createTelegramBot fetch abort", () => { describe("createTelegramBot fetch abort", () => {
it("aborts wrapped client fetch when fetchAbortSignal aborts", async () => { it("aborts wrapped client fetch when fetchAbortSignal aborts", async () => {
const shutdown = new AbortController();
const fetchSpy = vi.fn( const fetchSpy = vi.fn(
(_input: RequestInfo | URL, init?: RequestInit) => (_input: RequestInfo | URL, init?: RequestInit) =>
new Promise<AbortSignal>((resolve) => { new Promise<AbortSignal>((resolve) => {
@ -13,15 +26,9 @@ describe("createTelegramBot fetch abort", () => {
signal.addEventListener("abort", () => resolve(signal), { once: true }); signal.addEventListener("abort", () => resolve(signal), { once: true });
}), }),
); );
botCtorSpy.mockClear(); const { clientFetch, shutdown } = createWrappedTelegramClientFetch(
createTelegramBot({ fetchSpy as unknown as typeof fetch,
token: "tok", );
fetchAbortSignal: shutdown.signal,
proxyFetch: fetchSpy as unknown as typeof fetch,
});
const clientFetch = (botCtorSpy.mock.calls.at(-1)?.[1] as { client?: { fetch?: unknown } })
?.client?.fetch as (input: RequestInfo | URL, init?: RequestInit) => Promise<unknown>;
expect(clientFetch).toBeTypeOf("function");
const observedSignalPromise = clientFetch("https://example.test"); const observedSignalPromise = clientFetch("https://example.test");
shutdown.abort(new Error("shutdown")); shutdown.abort(new Error("shutdown"));
@ -32,7 +39,6 @@ describe("createTelegramBot fetch abort", () => {
}); });
it("tags wrapped Telegram fetch failures with the Bot API method", async () => { it("tags wrapped Telegram fetch failures with the Bot API method", async () => {
const shutdown = new AbortController();
const fetchError = Object.assign(new TypeError("fetch failed"), { const fetchError = Object.assign(new TypeError("fetch failed"), {
cause: Object.assign(new Error("connect timeout"), { cause: Object.assign(new Error("connect timeout"), {
code: "UND_ERR_CONNECT_TIMEOUT", code: "UND_ERR_CONNECT_TIMEOUT",
@ -41,15 +47,7 @@ describe("createTelegramBot fetch abort", () => {
const fetchSpy = vi.fn(async () => { const fetchSpy = vi.fn(async () => {
throw fetchError; throw fetchError;
}); });
botCtorSpy.mockClear(); const { clientFetch } = createWrappedTelegramClientFetch(fetchSpy as unknown as typeof fetch);
createTelegramBot({
token: "tok",
fetchAbortSignal: shutdown.signal,
proxyFetch: fetchSpy as unknown as typeof fetch,
});
const clientFetch = (botCtorSpy.mock.calls.at(-1)?.[1] as { client?: { fetch?: unknown } })
?.client?.fetch as (input: RequestInfo | URL, init?: RequestInit) => Promise<unknown>;
expect(clientFetch).toBeTypeOf("function");
await expect(clientFetch("https://api.telegram.org/bot123456:ABC/getUpdates")).rejects.toBe( await expect(clientFetch("https://api.telegram.org/bot123456:ABC/getUpdates")).rejects.toBe(
fetchError, fetchError,
@ -61,7 +59,6 @@ describe("createTelegramBot fetch abort", () => {
}); });
it("preserves the original fetch error when tagging cannot attach metadata", async () => { it("preserves the original fetch error when tagging cannot attach metadata", async () => {
const shutdown = new AbortController();
const frozenError = Object.freeze( const frozenError = Object.freeze(
Object.assign(new TypeError("fetch failed"), { Object.assign(new TypeError("fetch failed"), {
cause: Object.assign(new Error("connect timeout"), { cause: Object.assign(new Error("connect timeout"), {
@ -72,15 +69,7 @@ describe("createTelegramBot fetch abort", () => {
const fetchSpy = vi.fn(async () => { const fetchSpy = vi.fn(async () => {
throw frozenError; throw frozenError;
}); });
botCtorSpy.mockClear(); const { clientFetch } = createWrappedTelegramClientFetch(fetchSpy as unknown as typeof fetch);
createTelegramBot({
token: "tok",
fetchAbortSignal: shutdown.signal,
proxyFetch: fetchSpy as unknown as typeof fetch,
});
const clientFetch = (botCtorSpy.mock.calls.at(-1)?.[1] as { client?: { fetch?: unknown } })
?.client?.fetch as (input: RequestInfo | URL, init?: RequestInit) => Promise<unknown>;
expect(clientFetch).toBeTypeOf("function");
await expect(clientFetch("https://api.telegram.org/bot123456:ABC/getUpdates")).rejects.toBe( await expect(clientFetch("https://api.telegram.org/bot123456:ABC/getUpdates")).rejects.toBe(
frozenError, frozenError,