mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 12:15:57 +00:00
201 lines
6.9 KiB
TypeScript
201 lines
6.9 KiB
TypeScript
import { afterEach, describe, expect, it, mock } from 'bun:test';
|
|
import { ensureManagedModelPrefixes } from '../../../src/cliproxy/managed-model-prefixes';
|
|
|
|
const originalFetch = global.fetch;
|
|
|
|
interface MockAuthFileRecord {
|
|
account_type?: string;
|
|
name: string;
|
|
provider?: string;
|
|
type?: string;
|
|
}
|
|
|
|
interface DownloadResponse {
|
|
body: string;
|
|
status?: number;
|
|
}
|
|
|
|
function jsonResponse(body: unknown, status = 200): Response {
|
|
return new Response(JSON.stringify(body), {
|
|
status,
|
|
headers: { 'Content-Type': 'application/json' },
|
|
});
|
|
}
|
|
|
|
function textResponse(body: string, status = 200): Response {
|
|
return new Response(body, {
|
|
status,
|
|
headers: { 'Content-Type': 'application/json' },
|
|
});
|
|
}
|
|
|
|
function installFetchMock(options: {
|
|
files: MockAuthFileRecord[];
|
|
downloads?: Record<string, DownloadResponse | Error>;
|
|
patchStatuses?: Record<string, number>;
|
|
}) {
|
|
const requests: Array<{ url: string; method: string; body: string | undefined }> = [];
|
|
|
|
global.fetch = mock((input: string | URL | Request, init?: RequestInit) => {
|
|
const url =
|
|
typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url;
|
|
const method = init?.method ?? 'GET';
|
|
const body = typeof init?.body === 'string' ? init.body : undefined;
|
|
|
|
requests.push({ url, method, body });
|
|
|
|
if (url.endsWith('/v0/management/auth-files') && method === 'GET') {
|
|
return Promise.resolve(jsonResponse({ files: options.files }));
|
|
}
|
|
|
|
if (url.includes('/v0/management/auth-files/download') && method === 'GET') {
|
|
const name = new URL(url).searchParams.get('name');
|
|
if (!name) {
|
|
return Promise.reject(new Error(`Missing auth file name for ${url}`));
|
|
}
|
|
|
|
const response = options.downloads?.[name];
|
|
if (response instanceof Error) {
|
|
return Promise.reject(response);
|
|
}
|
|
if (!response) {
|
|
return Promise.resolve(textResponse('{}', 404));
|
|
}
|
|
|
|
return Promise.resolve(textResponse(response.body, response.status ?? 200));
|
|
}
|
|
|
|
if (url.endsWith('/v0/management/auth-files/fields') && method === 'PATCH') {
|
|
const payload = JSON.parse(body ?? '{}') as { name?: string };
|
|
const status = (payload.name && options.patchStatuses?.[payload.name]) ?? 200;
|
|
return Promise.resolve(jsonResponse({ ok: status < 400 }, status));
|
|
}
|
|
|
|
return Promise.reject(new Error(`Unexpected fetch ${method} ${url}`));
|
|
}) as typeof fetch;
|
|
|
|
return requests;
|
|
}
|
|
|
|
afterEach(() => {
|
|
global.fetch = originalFetch;
|
|
});
|
|
|
|
describe('ensureManagedModelPrefixes', () => {
|
|
it('patches missing managed prefixes for matching oauth providers', async () => {
|
|
const requests = installFetchMock({
|
|
files: [
|
|
{ account_type: 'oauth', name: 'gemini-main', provider: 'gemini' },
|
|
{ account_type: 'oauth', name: 'agy-main', provider: 'antigravity' },
|
|
{ account_type: 'apikey', name: 'gemini-key', provider: 'gemini' },
|
|
],
|
|
downloads: {
|
|
'gemini-main': { body: JSON.stringify({ prefix: null, provider: 'gemini' }) },
|
|
'agy-main': { body: JSON.stringify({ prefix: null, provider: 'antigravity' }) },
|
|
},
|
|
});
|
|
|
|
const result = await ensureManagedModelPrefixes(['gemini']);
|
|
|
|
expect(result).toEqual({ checked: 1, updated: 1 });
|
|
|
|
const patchRequest = requests.find(
|
|
(request) =>
|
|
request.url.endsWith('/v0/management/auth-files/fields') && request.method === 'PATCH'
|
|
);
|
|
expect(patchRequest?.body).toBe(JSON.stringify({ name: 'gemini-main', prefix: 'gcli' }));
|
|
|
|
const downloadedNames = requests
|
|
.filter((request) => request.url.includes('/v0/management/auth-files/download'))
|
|
.map((request) => new URL(request.url).searchParams.get('name'));
|
|
expect(downloadedNames).toEqual(['gemini-main']);
|
|
});
|
|
|
|
it('returns immediately when called for providers without managed prefixes', async () => {
|
|
const fetchMock = mock(() => Promise.reject(new Error('should not fetch')));
|
|
global.fetch = fetchMock as typeof fetch;
|
|
|
|
const result = await ensureManagedModelPrefixes(['codex']);
|
|
|
|
expect(result).toEqual({ checked: 0, updated: 0 });
|
|
expect(fetchMock).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('skips files that already have the managed prefix or a different custom prefix', async () => {
|
|
const requests = installFetchMock({
|
|
files: [
|
|
{ account_type: 'oauth', name: 'gemini-managed', provider: 'gemini' },
|
|
{ account_type: 'oauth', name: 'gemini-custom', provider: 'gemini' },
|
|
],
|
|
downloads: {
|
|
'gemini-managed': { body: JSON.stringify({ prefix: 'gcli', provider: 'gemini' }) },
|
|
'gemini-custom': { body: JSON.stringify({ prefix: 'team-a', provider: 'gemini' }) },
|
|
},
|
|
});
|
|
|
|
const result = await ensureManagedModelPrefixes(['gemini']);
|
|
|
|
expect(result).toEqual({ checked: 2, updated: 0 });
|
|
expect(
|
|
requests.some(
|
|
(request) =>
|
|
request.url.endsWith('/v0/management/auth-files/fields') && request.method === 'PATCH'
|
|
)
|
|
).toBe(false);
|
|
});
|
|
|
|
it('skips patching when the downloaded auth file belongs to a different provider', async () => {
|
|
const requests = installFetchMock({
|
|
files: [{ account_type: 'oauth', name: 'gemini-shadowed', provider: 'gemini' }],
|
|
downloads: {
|
|
'gemini-shadowed': {
|
|
body: JSON.stringify({ prefix: null, provider: 'antigravity' }),
|
|
},
|
|
},
|
|
});
|
|
|
|
const result = await ensureManagedModelPrefixes(['gemini']);
|
|
|
|
expect(result).toEqual({ checked: 1, updated: 0 });
|
|
expect(
|
|
requests.some(
|
|
(request) =>
|
|
request.url.endsWith('/v0/management/auth-files/fields') && request.method === 'PATCH'
|
|
)
|
|
).toBe(false);
|
|
});
|
|
|
|
it('swallows read and patch failures so later files can still be repaired', async () => {
|
|
const requests = installFetchMock({
|
|
files: [
|
|
{ account_type: 'oauth', name: 'gemini-unreadable', provider: 'gemini' },
|
|
{ account_type: 'oauth', name: 'gemini-patch-fails', provider: 'gemini' },
|
|
{ account_type: 'oauth', name: 'gemini-success', provider: 'gemini' },
|
|
],
|
|
downloads: {
|
|
'gemini-unreadable': new Error('network down'),
|
|
'gemini-patch-fails': { body: JSON.stringify({ prefix: null, provider: 'gemini' }) },
|
|
'gemini-success': { body: JSON.stringify({ prefix: null, provider: 'gemini' }) },
|
|
},
|
|
patchStatuses: {
|
|
'gemini-patch-fails': 500,
|
|
},
|
|
});
|
|
|
|
const result = await ensureManagedModelPrefixes(['gemini']);
|
|
|
|
expect(result).toEqual({ checked: 3, updated: 1 });
|
|
|
|
const patchPayloads = requests
|
|
.filter(
|
|
(request) =>
|
|
request.url.endsWith('/v0/management/auth-files/fields') && request.method === 'PATCH'
|
|
)
|
|
.map((request) => request.body);
|
|
expect(patchPayloads).toEqual([
|
|
JSON.stringify({ name: 'gemini-patch-fails', prefix: 'gcli' }),
|
|
JSON.stringify({ name: 'gemini-success', prefix: 'gcli' }),
|
|
]);
|
|
});
|
|
});
|