FreeLLMAPI / server /src /__tests__ /routes /fallback.test.ts
Nryn215's picture
Upload folder using huggingface_hub
077865a verified
Raw
History Blame Contribute Delete
5.16 kB
import { describe, it, expect, beforeAll } from 'vitest';
import type { Express } from 'express';
import { createApp } from '../../app.js';
import { initDb } from '../../db/index.js';
import { mintDashboardToken, isGatedApiPath } from '../helpers/auth.js';
let dashToken = '';
async function request(app: Express, method: string, path: string, body?: any) {
const server = app.listen(0);
const addr = server.address() as any;
const url = `http://127.0.0.1:${addr.port}${path}`;
const res = await fetch(url, {
method,
headers: {
...(body ? { 'Content-Type': 'application/json' } : {}),
...(isGatedApiPath(path) ? { Authorization: `Bearer ${dashToken}` } : {}),
},
body: body ? JSON.stringify(body) : undefined,
});
const data = await res.json().catch(() => null);
server.close();
return { status: res.status, body: data };
}
describe('Fallback API', () => {
let app: Express;
beforeAll(() => {
process.env.ENCRYPTION_KEY = '0'.repeat(64);
initDb(':memory:');
app = createApp();
dashToken = mintDashboardToken();
});
it('GET /api/fallback returns fallback chain', async () => {
const { status, body } = await request(app, 'GET', '/api/fallback');
expect(status).toBe(200);
expect(Array.isArray(body)).toBe(true);
expect(body.length).toBeGreaterThan(0);
// Should be sorted by priority
for (let i = 1; i < body.length; i++) {
expect(body[i].priority).toBeGreaterThanOrEqual(body[i - 1].priority);
}
});
it('GET /api/fallback entries have expected fields', async () => {
const { body } = await request(app, 'GET', '/api/fallback');
const first = body[0];
expect(first).toHaveProperty('modelDbId');
expect(first).toHaveProperty('priority');
expect(first).toHaveProperty('enabled');
expect(first).toHaveProperty('platform');
expect(first).toHaveProperty('displayName');
expect(first).toHaveProperty('intelligenceRank');
});
it('PUT /api/fallback updates order', async () => {
const { body: original } = await request(app, 'GET', '/api/fallback');
// Reverse the order
const reversed = original.map((e: any, i: number) => ({
modelDbId: e.modelDbId,
priority: original.length - i,
enabled: e.enabled,
}));
const { status } = await request(app, 'PUT', '/api/fallback', reversed);
expect(status).toBe(200);
// Verify order changed
const { body: after } = await request(app, 'GET', '/api/fallback');
expect(after[0].modelDbId).toBe(original[original.length - 1].modelDbId);
// Restore original order
const restore = original.map((e: any, i: number) => ({
modelDbId: e.modelDbId,
priority: i + 1,
enabled: e.enabled,
}));
await request(app, 'PUT', '/api/fallback', restore);
});
it('POST /api/fallback/sort/intelligence sorts by cross-provider tier, then rank', async () => {
const { status } = await request(app, 'POST', '/api/fallback/sort/intelligence');
expect(status).toBe(200);
const { body } = await request(app, 'GET', '/api/fallback');
// intelligence_rank is per-provider, so the sort normalizes on the
// cross-provider capability tier (size_label) first (issue #135).
const tier: Record<string, number> = { Frontier: 1, Large: 2, Medium: 3, Small: 4 };
const tierOf = (label: string) => tier[label] ?? 5;
for (let i = 1; i < body.length; i++) {
const prevTier = tierOf(body[i - 1].sizeLabel);
const curTier = tierOf(body[i].sizeLabel);
// Capability tier never decreases...
expect(curTier).toBeGreaterThanOrEqual(prevTier);
// ...and within the same tier, per-provider rank breaks the tie.
if (curTier === prevTier) {
expect(body[i].intelligenceRank).toBeGreaterThanOrEqual(body[i - 1].intelligenceRank);
}
}
});
it('intelligence sort never places a weaker tier above a Frontier model (#135)', async () => {
await request(app, 'POST', '/api/fallback/sort/intelligence');
const { body } = await request(app, 'GET', '/api/fallback');
// The last Frontier model must come before the first non-Frontier model —
// i.e. no "Intel #1 from a weaker provider" leaks above the frontier tier.
const lastFrontier = body.map((m: any) => m.sizeLabel).lastIndexOf('Frontier');
const firstNonFrontier = body.findIndex((m: any) => m.sizeLabel !== 'Frontier');
if (lastFrontier !== -1 && firstNonFrontier !== -1) {
expect(lastFrontier).toBeLessThan(firstNonFrontier);
}
});
it('POST /api/fallback/sort/speed sorts by speed', async () => {
const { status } = await request(app, 'POST', '/api/fallback/sort/speed');
expect(status).toBe(200);
const { body } = await request(app, 'GET', '/api/fallback');
// Should be sorted ascending by speed rank
for (let i = 1; i < body.length; i++) {
expect(body[i].speedRank).toBeGreaterThanOrEqual(body[i - 1].speedRank);
}
});
it('POST /api/fallback/sort/invalid returns 400', async () => {
const { status } = await request(app, 'POST', '/api/fallback/sort/invalid');
expect(status).toBe(400);
});
});