| import { describe, it, expect } from 'vitest';
|
| import Database from 'better-sqlite3';
|
| import { initDb } from '../../db/index.js';
|
|
|
| |
| |
| |
|
|
| describe('Migration idempotency', () => {
|
| it('initDb on a fresh in-memory DB then re-run produces identical row counts', () => {
|
| process.env.ENCRYPTION_KEY = '0'.repeat(64);
|
|
|
| const tmpPath = `/tmp/freeapi-idempotency-${Date.now()}.db`;
|
|
|
| const db1 = initDb(tmpPath);
|
| const before = {
|
| models: (db1.prepare('SELECT COUNT(*) AS c FROM models').get() as { c: number }).c,
|
| fallback: (db1.prepare('SELECT COUNT(*) AS c FROM fallback_config').get() as { c: number }).c,
|
| enabledModels: (db1.prepare('SELECT COUNT(*) AS c FROM models WHERE enabled = 1').get() as { c: number }).c,
|
| disabledModels: (db1.prepare('SELECT COUNT(*) AS c FROM models WHERE enabled = 0').get() as { c: number }).c,
|
| orphanFallbacks: (db1.prepare(`
|
| SELECT COUNT(*) AS c FROM fallback_config f
|
| LEFT JOIN models m ON f.model_db_id = m.id
|
| WHERE m.id IS NULL
|
| `).get() as { c: number }).c,
|
| };
|
| db1.close();
|
|
|
|
|
| const db2 = initDb(tmpPath);
|
| const after = {
|
| models: (db2.prepare('SELECT COUNT(*) AS c FROM models').get() as { c: number }).c,
|
| fallback: (db2.prepare('SELECT COUNT(*) AS c FROM fallback_config').get() as { c: number }).c,
|
| enabledModels: (db2.prepare('SELECT COUNT(*) AS c FROM models WHERE enabled = 1').get() as { c: number }).c,
|
| disabledModels: (db2.prepare('SELECT COUNT(*) AS c FROM models WHERE enabled = 0').get() as { c: number }).c,
|
| orphanFallbacks: (db2.prepare(`
|
| SELECT COUNT(*) AS c FROM fallback_config f
|
| LEFT JOIN models m ON f.model_db_id = m.id
|
| WHERE m.id IS NULL
|
| `).get() as { c: number }).c,
|
| };
|
| db2.close();
|
|
|
| expect(after).toEqual(before);
|
| expect(after.orphanFallbacks).toBe(0);
|
| });
|
|
|
| it('every catalog row has exactly one fallback_config entry', () => {
|
| process.env.ENCRYPTION_KEY = '0'.repeat(64);
|
| const db = initDb(':memory:');
|
|
|
| const rows = db.prepare(`
|
| SELECT m.id, COUNT(f.id) AS fb_count
|
| FROM models m
|
| LEFT JOIN fallback_config f ON m.id = f.model_db_id
|
| GROUP BY m.id
|
| HAVING COUNT(f.id) <> 1
|
| `).all() as { id: number; fb_count: number }[];
|
|
|
| expect(rows).toEqual([]);
|
| });
|
|
|
| it('UNIQUE(platform, model_id) constraint holds — no duplicate catalog rows', () => {
|
| process.env.ENCRYPTION_KEY = '0'.repeat(64);
|
| const db = initDb(':memory:');
|
|
|
| const dups = db.prepare(`
|
| SELECT platform, model_id, COUNT(*) AS c FROM models
|
| GROUP BY platform, model_id
|
| HAVING COUNT(*) > 1
|
| `).all();
|
|
|
| expect(dups).toEqual([]);
|
| });
|
|
|
| it('V12: dead OR :free rows are absent and the four new rows are present', () => {
|
| process.env.ENCRYPTION_KEY = '0'.repeat(64);
|
| const db = initDb(':memory:');
|
|
|
| const dead = db.prepare(`
|
| SELECT model_id FROM models
|
| WHERE platform = 'openrouter'
|
| AND model_id IN ('inclusionai/ling-2.6-1t:free', 'tencent/hy3-preview:free')
|
| `).all();
|
| expect(dead).toEqual([]);
|
|
|
|
|
| const pruned = db.prepare(`
|
| SELECT model_id FROM models
|
| WHERE platform = 'openrouter'
|
| AND model_id IN (
|
| 'arcee-ai/trinity-large-thinking:free',
|
| 'minimax/minimax-m2.5:free',
|
| 'baidu/cobuddy:free'
|
| )
|
| `).all();
|
| expect(pruned).toEqual([]);
|
|
|
| const live = db.prepare(`
|
| SELECT model_id FROM models
|
| WHERE platform = 'openrouter'
|
| AND model_id IN (
|
| 'openrouter/owl-alpha',
|
| 'nousresearch/hermes-3-llama-3.1-405b:free'
|
| )
|
| ORDER BY model_id
|
| `).all() as { model_id: string }[];
|
| expect(live.map(r => r.model_id)).toEqual([
|
| 'nousresearch/hermes-3-llama-3.1-405b:free',
|
| 'openrouter/owl-alpha',
|
| ]);
|
|
|
| const widened = db.prepare(`
|
| SELECT model_id, context_window FROM models
|
| WHERE platform = 'openrouter'
|
| AND model_id IN ('nvidia/nemotron-3-super-120b-a12b:free', 'qwen/qwen3-coder:free')
|
| ORDER BY model_id
|
| `).all() as { model_id: string; context_window: number }[];
|
| expect(widened).toEqual([
|
| { model_id: 'nvidia/nemotron-3-super-120b-a12b:free', context_window: 1000000 },
|
| { model_id: 'qwen/qwen3-coder:free', context_window: 1048576 },
|
| ]);
|
| });
|
|
|
| it('V13: cross-provider catalog refresh applies cleanly', () => {
|
| process.env.ENCRYPTION_KEY = '0'.repeat(64);
|
| const db = initDb(':memory:');
|
|
|
|
|
| const disabled = db.prepare(`
|
| SELECT platform, model_id, enabled FROM models
|
| WHERE (platform = 'google' AND model_id = 'gemini-3.1-pro-preview')
|
| OR (platform = 'ollama' AND model_id IN ('kimi-k2-thinking', 'mistral-large-3:675b', 'deepseek-v3.2'))
|
| ORDER BY platform, model_id
|
| `).all() as { platform: string; model_id: string; enabled: number }[];
|
| expect(disabled).toHaveLength(4);
|
| for (const row of disabled) expect(row.enabled).toBe(0);
|
|
|
|
|
| const removed = db.prepare(`
|
| SELECT model_id FROM models
|
| WHERE (platform = 'sambanova' AND model_id = 'DeepSeek-V3.1-cb')
|
| OR (platform = 'cloudflare' AND model_id = '@cf/moonshotai/kimi-k2.5')
|
| `).all();
|
| expect(removed).toEqual([]);
|
|
|
|
|
| const additions = db.prepare(`
|
| SELECT platform, model_id FROM models
|
| WHERE (platform, model_id) IN (VALUES
|
| ('groq', 'openai/gpt-oss-safeguard-20b'),
|
| ('cloudflare', '@cf/nvidia/nemotron-3-120b-a12b'),
|
| ('cloudflare', '@cf/google/gemma-4-26b-a4b-it'),
|
| ('google', 'gemini-3.5-flash'),
|
| ('nvidia', 'deepseek-ai/deepseek-v4-flash'),
|
| ('nvidia', 'z-ai/glm-5.1'),
|
| ('nvidia', 'qwen/qwen3-coder-480b-a35b-instruct'),
|
| ('mistral', 'mistral-small-latest'),
|
| ('mistral', 'ministral-8b-latest'),
|
| ('cohere', 'command-a-reasoning-08-2025'),
|
| ('cohere', 'command-r-08-2024'),
|
| ('ollama', 'qwen3-coder-next'),
|
| ('huggingface', 'deepseek-ai/DeepSeek-V4-Flash'),
|
| ('huggingface', 'moonshotai/Kimi-K2.6'),
|
| ('huggingface', 'Qwen/Qwen3-Coder-Next')
|
| )
|
| `).all();
|
| expect(additions).toHaveLength(15);
|
|
|
|
|
| const cerebrasLimits = db.prepare(`
|
| SELECT rpm_limit, rpd_limit, tpm_limit, tpd_limit FROM models
|
| WHERE platform = 'cerebras' AND model_id = 'qwen-3-235b-a22b-instruct-2507'
|
| `).get() as { rpm_limit: number; rpd_limit: number; tpm_limit: number; tpd_limit: number };
|
| expect(cerebrasLimits).toEqual({ rpm_limit: 5, rpd_limit: 2400, tpm_limit: 30000, tpd_limit: 1000000 });
|
|
|
| const sambanovaCtx = (db.prepare(`
|
| SELECT context_window FROM models WHERE platform = 'sambanova' AND model_id = 'DeepSeek-V3.2'
|
| `).get() as { context_window: number }).context_window;
|
| expect(sambanovaCtx).toBe(32768);
|
|
|
| const cfFp8Ctx = (db.prepare(`
|
| SELECT context_window FROM models WHERE platform = 'cloudflare' AND model_id = '@cf/meta/llama-3.3-70b-instruct-fp8-fast'
|
| `).get() as { context_window: number }).context_window;
|
| expect(cfFp8Ctx).toBe(24000);
|
|
|
| const mistralCtx = db.prepare(`
|
| SELECT model_id, context_window FROM models
|
| WHERE platform = 'mistral'
|
| AND model_id IN ('codestral-latest', 'devstral-latest', 'magistral-medium-latest', 'mistral-large-latest')
|
| ORDER BY model_id
|
| `).all() as { model_id: string; context_window: number }[];
|
| expect(mistralCtx).toEqual([
|
| { model_id: 'codestral-latest', context_window: 256000 },
|
| { model_id: 'devstral-latest', context_window: 262144 },
|
| { model_id: 'magistral-medium-latest', context_window: 131072 },
|
| { model_id: 'mistral-large-latest', context_window: 262144 },
|
| ]);
|
| });
|
|
|
| it('V14: cerebras deprecation disables qwen-3-235b and llama3.1-8b but keeps gpt-oss-120b enabled', () => {
|
| process.env.ENCRYPTION_KEY = '0'.repeat(64);
|
| const db = initDb(':memory:');
|
|
|
| const rows = db.prepare(`
|
| SELECT model_id, enabled FROM models
|
| WHERE platform = 'cerebras'
|
| AND model_id IN ('qwen-3-235b-a22b-instruct-2507', 'llama3.1-8b', 'gpt-oss-120b')
|
| ORDER BY model_id
|
| `).all() as { model_id: string; enabled: number }[];
|
|
|
| expect(rows).toEqual([
|
| { model_id: 'gpt-oss-120b', enabled: 1 },
|
| { model_id: 'llama3.1-8b', enabled: 0 },
|
| { model_id: 'qwen-3-235b-a22b-instruct-2507', enabled: 0 },
|
| ]);
|
| });
|
|
|
| it('all enabled catalog platforms have a registered provider', async () => {
|
| process.env.ENCRYPTION_KEY = '0'.repeat(64);
|
| const db = initDb(':memory:');
|
| const { hasProvider } = await import('../../providers/index.js');
|
|
|
| const platforms = (db.prepare(
|
| `SELECT DISTINCT platform FROM models WHERE enabled = 1`
|
| ).all() as { platform: any }[]).map(r => r.platform);
|
|
|
| const missing = platforms.filter(p => !hasProvider(p));
|
| expect(missing).toEqual([]);
|
| });
|
| });
|
|
|