mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-13 18:32:12 +03:00
Landed with the design call resolved per the owner's pick — **option 1**: the synced store is now endpoint-agnostic (persistDiscoveredModels and managedModelImport no longer drop non-chat models at write time), and chat selectability moved to read time (auto-pool expansion in autoStrategy applies filterChatSelectableModels; the models-route projection already had its chatOnly filter). Your discovery test now passes end-to-end (3/3): /api/show capabilities persist per connection and image/embedding requests route through the advertising host. Reconciliation notes: conflicted areas merged onto the current tip (adobe discovery import, requestedModel preflight signature, resolvedProvider fast-path coexists with the synced-route override — explicit resolution wins); carried base-red drains (#10055 memoization, #11071 test variants) dropped as already-landed; the managed-model-import exclusion test was propagated to the new contract (image/video models persist; the read filter still hides them from chat pickers — pinned by a new assertion). Full battery: 205/206 focused (the one red is a confirmed periodic-timer timing flake on the loaded devbox — 20/20 isolated), autoCombo vitest 30/30, combo suites 46/46, gates + typecheck clean. Thank you @yourspraveen — the capability probe + routing design was right; it just needed the store contract opened up. Fixes #11087.
145 lines
5.1 KiB
TypeScript
145 lines
5.1 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
import { testOAuthConnection } from "../../src/app/api/providers/[id]/test/route";
|
|
|
|
// #10365 / #10499: the chat-completion path (open-sse/executors/gitlab.ts) already
|
|
// falls back to the public Code Suggestions completions endpoint when the
|
|
// `direct_access` exchange is rejected with 401 — but "Test Connection" / the
|
|
// dashboard's Retest button drove testOAuthConnection() straight against
|
|
// `direct_access` and reported the connection unhealthy on a plain 401, even though
|
|
// the exact same request would have succeeded through the real chat path via the
|
|
// fallback. These tests prove the connection-test path now applies the identical
|
|
// fallback contract before declaring the connection invalid.
|
|
|
|
const DIRECT_ACCESS_URL = "https://gitlab.example.com/api/v4/code_suggestions/direct_access";
|
|
const PUBLIC_COMPLETIONS_URL = "https://gitlab.example.com/api/v4/code_suggestions/completions";
|
|
|
|
function futureExpiresAt(): string {
|
|
return new Date(Date.now() + 60 * 60 * 1000).toISOString();
|
|
}
|
|
|
|
function baseConnection(overrides: Record<string, unknown> = {}) {
|
|
return {
|
|
provider: "gitlab-duo",
|
|
authType: "oauth",
|
|
accessToken: "oauth-access",
|
|
refreshToken: "oauth-refresh",
|
|
expiresAt: futureExpiresAt(),
|
|
providerSpecificData: { baseUrl: "https://gitlab.example.com" },
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
function mockFetch(handler: (url: string, init?: RequestInit) => Response) {
|
|
const calls: Array<{ url: string; init?: RequestInit }> = [];
|
|
const fn = (async (url: RequestInfo | URL, init?: RequestInit) => {
|
|
const u = typeof url === "string" ? url : url instanceof URL ? url.toString() : String(url);
|
|
calls.push({ url: u, init });
|
|
return handler(u, init);
|
|
}) as typeof fetch;
|
|
return { fn, calls };
|
|
}
|
|
|
|
test("gitlab-duo Retest falls back to the public completions endpoint on a direct_access 401 (#10365)", async (t) => {
|
|
const original = globalThis.fetch;
|
|
const { fn, calls } = mockFetch((url) => {
|
|
if (url === DIRECT_ACCESS_URL) {
|
|
return new Response(JSON.stringify({ error: "invalid_token" }), {
|
|
status: 401,
|
|
headers: { "content-type": "application/json" },
|
|
});
|
|
}
|
|
if (url === PUBLIC_COMPLETIONS_URL) {
|
|
return new Response(JSON.stringify({ model: { name: "code-gecko" }, choices: [] }), {
|
|
status: 200,
|
|
headers: { "content-type": "application/json" },
|
|
});
|
|
}
|
|
throw new Error(`Unexpected fetch to ${url}`);
|
|
});
|
|
globalThis.fetch = fn;
|
|
t.after(() => {
|
|
globalThis.fetch = original;
|
|
});
|
|
|
|
const result = await testOAuthConnection(baseConnection(), 5000);
|
|
|
|
assert.equal(
|
|
result.valid,
|
|
true,
|
|
"a direct_access 401 must be recovered via the public completions fallback probe, mirroring the chat path"
|
|
);
|
|
assert.deepEqual(
|
|
calls.map((c) => c.url),
|
|
[DIRECT_ACCESS_URL, PUBLIC_COMPLETIONS_URL],
|
|
"must probe direct_access first, then fall back to the public completions endpoint"
|
|
);
|
|
const fallbackHeaders = (calls[1].init?.headers ?? {}) as Record<string, string>;
|
|
assert.equal(fallbackHeaders.Authorization, "Bearer oauth-access");
|
|
});
|
|
|
|
test("gitlab-duo Retest reports invalid when BOTH direct_access and the public fallback reject the token", async (t) => {
|
|
const original = globalThis.fetch;
|
|
const { fn, calls } = mockFetch((url) => {
|
|
if (url === DIRECT_ACCESS_URL) {
|
|
return new Response(JSON.stringify({ error: "invalid_token" }), {
|
|
status: 401,
|
|
headers: { "content-type": "application/json" },
|
|
});
|
|
}
|
|
if (url === PUBLIC_COMPLETIONS_URL) {
|
|
return new Response(JSON.stringify({ error: "invalid_token" }), {
|
|
status: 401,
|
|
headers: { "content-type": "application/json" },
|
|
});
|
|
}
|
|
throw new Error(`Unexpected fetch to ${url}`);
|
|
});
|
|
globalThis.fetch = fn;
|
|
t.after(() => {
|
|
globalThis.fetch = original;
|
|
});
|
|
|
|
const result = await testOAuthConnection(baseConnection({ refreshToken: null }), 5000);
|
|
|
|
assert.equal(
|
|
result.valid,
|
|
false,
|
|
"a token rejected by BOTH endpoints is genuinely bad — the fallback must not paper over that"
|
|
);
|
|
assert.deepEqual(
|
|
calls.map((c) => c.url),
|
|
[DIRECT_ACCESS_URL, PUBLIC_COMPLETIONS_URL],
|
|
"the fallback probe must still run before giving up"
|
|
);
|
|
});
|
|
|
|
test("gitlab-duo Retest still falls back on the pre-existing 403 'direct connections are disabled' case", async (t) => {
|
|
const original = globalThis.fetch;
|
|
const { fn, calls } = mockFetch((url) => {
|
|
if (url === DIRECT_ACCESS_URL) {
|
|
return new Response("Direct connections are disabled for this instance", {
|
|
status: 403,
|
|
headers: { "content-type": "text/plain" },
|
|
});
|
|
}
|
|
if (url === PUBLIC_COMPLETIONS_URL) {
|
|
return new Response(JSON.stringify({ model: { name: "code-gecko" }, choices: [] }), {
|
|
status: 200,
|
|
headers: { "content-type": "application/json" },
|
|
});
|
|
}
|
|
throw new Error(`Unexpected fetch to ${url}`);
|
|
});
|
|
globalThis.fetch = fn;
|
|
t.after(() => {
|
|
globalThis.fetch = original;
|
|
});
|
|
|
|
const result = await testOAuthConnection(baseConnection(), 5000);
|
|
|
|
assert.equal(result.valid, true);
|
|
assert.equal(calls.length, 2);
|
|
});
|