Files
OmniRoute/tests/integration/_comboRoutingHarness.ts
Diego Rodrigues de Sa e Souza 25ef8d05c0 test(combo): classify dispatches by host and close the auto test pool
providerFromUrl() classified the upstream by URL path shape. With hundreds of
providers in the catalog that is wrong in both directions: '/chat/completions'
matched every OpenAI-compatible upstream (opencode.ai/zen was being reported as
'openai'), while OpenAI's own GPT-5.6 dispatches go to '/v1/responses' and came
back 'unknown'. Classify by hostname instead, and return 'host:<hostname>' for
unrecognised hosts so an unexpected dispatch names itself in the failure message.

combo-matrix/auto.test.ts additionally assumed the auto pool contained only the
connections it seeded, but no-auth providers (#6557/#7622) legitimately join the
pool without a seeded connection. Block those in beforeEach so the pool is closed
to the seeded connections — preserving what the assertions are actually about
(LKGP pinning, variant pool resolution) rather than relaxing them to accept
whatever an open pool picks.

Verified: auto.test.ts 2/2, and all 9 combo-matrix files 27/27 with no
regressions (no test was passing on the old helper's false 'openai' label).
2026-07-19 16:10:12 -03:00

109 lines
3.8 KiB
TypeScript

// tests/integration/_comboRoutingHarness.ts
// Recording-fetch helper for combo routing-decision tests.
// Wraps the chat pipeline harness so each strategy test can assert WHICH
// provider/model was dispatched, in what order, without writing a fetch mock.
import { createChatPipelineHarness } from "./_chatPipelineHarness.ts";
// Map an upstream request URL to the provider id it targets.
//
// Classification is by HOST, not by path shape. Path shapes are ambiguous in
// both directions now that the catalog has hundreds of providers:
// - `/chat/completions` is served by dozens of OpenAI-compatible upstreams
// (e.g. https://opencode.ai/zen/v1/chat/completions), so matching on it
// mislabelled other providers as "openai";
// - OpenAI itself dispatches the GPT-5.6 family to `/v1/responses`, so its
// own calls stopped matching and came back "unknown".
// The host is what actually identifies the upstream, so we key on that.
//
// Unrecognised hosts return `host:<hostname>` rather than a bare "unknown", so
// an unexpected dispatch names itself in the assertion message instead of
// forcing a debugging round-trip.
const PROVIDER_BY_HOST: Record<string, string> = {
"api.openai.com": "openai",
"api.anthropic.com": "claude",
"generativelanguage.googleapis.com": "gemini",
"chatgpt.com": "codex",
"auth.openai.com": "codex",
};
export function providerFromUrl(url: string): string {
let host: string;
try {
host = new URL(url).hostname;
} catch {
return "unknown";
}
return PROVIDER_BY_HOST[host] ?? `host:${host}`;
}
export type DispatchCall = {
index: number;
provider: string;
url: string;
authorization: string | undefined;
model: string | undefined;
};
// A scripted response decides, per call index or provider, whether the upstream
// call succeeds or returns a failure status. Default: every call succeeds (200).
export type ResponseScript = (call: DispatchCall) => Response | undefined;
export async function createComboRoutingHarness(prefix: string) {
const base = await createChatPipelineHarness(prefix);
// Records every upstream call in dispatch order.
const calls: DispatchCall[] = [];
function readModel(init: any): string | undefined {
try {
const body = typeof init?.body === "string" ? JSON.parse(init.body) : init?.body;
return body?.model;
} catch {
return undefined;
}
}
// Install a recording fetch. `script` may return a Response to override the
// default success (e.g. a 503 to force failover); returning undefined uses the
// provider's default success response.
function installRecordingFetch(script: ResponseScript = () => undefined) {
calls.length = 0;
globalThis.fetch = async (url: any, init: any = {}) => {
const u = String(url);
const provider = providerFromUrl(u);
const headers = base.toPlainHeaders(init.headers);
const call: DispatchCall = {
index: calls.length,
provider,
url: u,
authorization: headers.authorization,
model: readModel(init),
};
calls.push(call);
const override = script(call);
if (override) return override;
if (provider === "claude") return base.buildClaudeResponse("ok");
if (provider === "gemini") return base.buildGeminiResponse("ok");
return base.buildOpenAIResponse("ok");
};
}
// Convenience: a failure Response with a given status.
function failure(status: number, message = "scripted failure"): Response {
return new Response(JSON.stringify({ error: { message } }), {
status,
headers: { "Content-Type": "application/json" },
});
}
return {
...base,
calls,
installRecordingFetch,
failure,
providersSeen: () => calls.map((c) => c.provider),
authKeysSeen: () => calls.map((c) => c.authorization),
};
}