1
0
forked from boos/BoosAPI

Add comprehensive tests for Anthropics and Gemini transformers

- Implement tests for anthropicMessagesTransformer including serialization and event handling in stream.test.ts.
- Add usage extraction tests for anthropicMessagesUsage in usage.test.ts.
- Create extensive tests for Gemini generate content aggregation and outbound usage in aggregator-outbound-usage.test.ts.
- Introduce tests for Gemini stream handling and payload parsing in stream.test.ts.
- Enhance OpenAI response serialization tests to ensure proper mapping of usage details and preservation of annotations in outbound.test.ts.
This commit is contained in:
cita
2026-03-08 16:42:41 +08:00
parent 7081be14c7
commit ede8998244
48 changed files with 6357 additions and 1110 deletions
+45
View File
@@ -40,6 +40,51 @@ describe('rebuildTokenRoutesFromAvailability', () => {
delete process.env.DATA_DIR;
});
it('creates an exact route with an account-direct channel for apikey model availability', async () => {
const site = await db.insert(schema.sites).values({
name: 'apikey-site',
url: 'https://apikey-site.example.com',
platform: 'new-api',
}).returning().get();
const account = await db.insert(schema.accounts).values({
siteId: site.id,
username: 'apikey-user',
accessToken: '',
apiToken: 'sk-apikey-route',
status: 'active',
extraConfig: JSON.stringify({ credentialMode: 'apikey' }),
}).returning().get();
await db.insert(schema.modelAvailability).values({
accountId: account.id,
modelName: 'gpt-5.2-codex',
available: true,
latencyMs: 1200,
checkedAt: '2026-03-08T08:00:00.000Z',
}).run();
const rebuild = await rebuildTokenRoutesFromAvailability();
expect(rebuild.models).toBe(1);
const route = await db.select().from(schema.tokenRoutes)
.where(eq(schema.tokenRoutes.modelPattern, 'gpt-5.2-codex'))
.get();
expect(route).toBeDefined();
const channels = await db.select().from(schema.routeChannels)
.where(and(
eq(schema.routeChannels.routeId, route!.id),
eq(schema.routeChannels.accountId, account.id),
))
.all();
expect(channels).toHaveLength(1);
expect(channels[0]?.tokenId ?? null).toBeNull();
expect(channels[0]?.manualOverride).toBe(false);
});
it('removes stale exact routes and keeps wildcard routes on rebuild', async () => {
const site = await db.insert(schema.sites).values({
name: 'site-1',
+84 -55
View File
@@ -250,8 +250,8 @@ async function refreshModelsForAllActiveAccounts() {
return results;
}
export async function rebuildTokenRoutesFromAvailability() {
const tokenRows = await db.select().from(schema.tokenModelAvailability)
export async function rebuildTokenRoutesFromAvailability() {
const tokenRows = await db.select().from(schema.tokenModelAvailability)
.innerJoin(schema.accountTokens, eq(schema.tokenModelAvailability.tokenId, schema.accountTokens.id))
.innerJoin(schema.accounts, eq(schema.accountTokens.accountId, schema.accounts.id))
.innerJoin(schema.sites, eq(schema.accounts.siteId, schema.sites.id))
@@ -262,25 +262,49 @@ export async function rebuildTokenRoutesFromAvailability() {
eq(schema.accounts.status, 'active'),
eq(schema.sites.status, 'active'),
),
)
.all();
const modelTokens = new Map<string, Map<number, number>>();
for (const row of tokenRows) {
const modelName = row.token_model_availability.modelName;
if (!modelTokens.has(modelName)) modelTokens.set(modelName, new Map<number, number>());
modelTokens.get(modelName)!.set(row.account_tokens.id, row.accounts.id);
}
const routes = await db.select().from(schema.tokenRoutes).all();
const channels = await db.select().from(schema.routeChannels).all();
)
.all();
const accountRows = await db.select().from(schema.modelAvailability)
.innerJoin(schema.accounts, eq(schema.modelAvailability.accountId, schema.accounts.id))
.innerJoin(schema.sites, eq(schema.accounts.siteId, schema.sites.id))
.where(
and(
eq(schema.modelAvailability.available, true),
eq(schema.accounts.status, 'active'),
eq(schema.sites.status, 'active'),
),
)
.all();
const modelCandidates = new Map<string, Map<string, { accountId: number; tokenId: number | null }>>();
const addModelCandidate = (modelNameRaw: string | null | undefined, accountId: number, tokenId: number | null) => {
const modelName = (modelNameRaw || '').trim();
if (!modelName) return;
if (!modelCandidates.has(modelName)) modelCandidates.set(modelName, new Map());
const candidateKey = `${accountId}:${tokenId ?? 'account'}`;
modelCandidates.get(modelName)!.set(candidateKey, { accountId, tokenId });
};
for (const row of tokenRows) {
addModelCandidate(row.token_model_availability.modelName, row.accounts.id, row.account_tokens.id);
}
for (const row of accountRows) {
if (!isApiKeyConnection(row.accounts)) continue;
if (!(row.accounts.apiToken || '').trim()) continue;
addModelCandidate(row.model_availability.modelName, row.accounts.id, null);
}
const routes = await db.select().from(schema.tokenRoutes).all();
const channels = await db.select().from(schema.routeChannels).all();
let createdRoutes = 0;
let createdChannels = 0;
let removedChannels = 0;
let removedRoutes = 0;
for (const [modelName, tokenAccountMap] of modelTokens.entries()) {
let createdChannels = 0;
let removedChannels = 0;
let removedRoutes = 0;
for (const [modelName, candidateMap] of modelCandidates.entries()) {
let route = routes.find((r) => r.modelPattern === modelName);
if (!route) {
const inserted = await db.insert(schema.tokenRoutes).values({
@@ -295,18 +319,21 @@ export async function rebuildTokenRoutesFromAvailability() {
routes.push(route);
createdRoutes++;
}
const routeChannels = channels.filter((channel) => channel.routeId === route.id);
const desiredTokenIds = new Set<number>(Array.from(tokenAccountMap.keys()));
for (const [tokenId, accountId] of tokenAccountMap.entries()) {
const exists = routeChannels.some((channel) => channel.tokenId === tokenId);
if (exists) continue;
const routeChannels = channels.filter((channel) => channel.routeId === route.id);
const desiredKeys = new Set(Array.from(candidateMap.keys()));
for (const [candidateKey, candidate] of candidateMap.entries()) {
const exists = routeChannels.some((channel) => (
channel.accountId === candidate.accountId
&& (channel.tokenId ?? null) === candidate.tokenId
));
if (exists) continue;
const inserted = await db.insert(schema.routeChannels).values({
routeId: route.id,
accountId,
tokenId,
accountId: candidate.accountId,
tokenId: candidate.tokenId,
priority: 0,
weight: 10,
enabled: true,
@@ -318,32 +345,34 @@ export async function rebuildTokenRoutesFromAvailability() {
if (!created) continue;
channels.push(created);
createdChannels++;
}
for (const channel of routeChannels) {
if (channel.tokenId && desiredTokenIds.has(channel.tokenId)) {
continue;
}
if (!channel.tokenId) {
desiredKeys.add(candidateKey);
}
for (const channel of routeChannels) {
const channelKey = `${channel.accountId}:${channel.tokenId ?? 'account'}`;
if (desiredKeys.has(channelKey)) {
continue;
}
if (!channel.tokenId) {
const preferred = await getPreferredAccountToken(channel.accountId);
if (preferred && desiredTokenIds.has(preferred.id)) {
await db.update(schema.routeChannels)
.set({ tokenId: preferred.id })
.where(eq(schema.routeChannels.id, channel.id))
.run();
continue;
if (preferred && desiredKeys.has(`${channel.accountId}:${preferred.id}`)) {
await db.update(schema.routeChannels)
.set({ tokenId: preferred.id })
.where(eq(schema.routeChannels.id, channel.id))
.run();
continue;
}
}
if (!channel.manualOverride) {
await db.delete(schema.routeChannels).where(eq(schema.routeChannels.id, channel.id)).run();
removedChannels++;
}
}
}
const latestModelNames = new Set<string>(Array.from(modelTokens.keys()));
}
}
}
const latestModelNames = new Set<string>(Array.from(modelCandidates.keys()));
for (const route of routes) {
const modelPattern = (route.modelPattern || '').trim();
if (!modelPattern || !isExactModelPattern(modelPattern) || latestModelNames.has(modelPattern)) {
@@ -367,13 +396,13 @@ export async function rebuildTokenRoutesFromAvailability() {
invalidateTokenRouterCache();
return {
models: modelTokens.size,
createdRoutes,
createdChannels,
removedChannels,
removedRoutes,
};
return {
models: modelCandidates.size,
createdRoutes,
createdChannels,
removedChannels,
removedRoutes,
};
}
export async function refreshModelsAndRebuildRoutes() {