Files
diegosouzapw--omniroute/tests/integration/modelsDevSync.test.ts
T
2026-07-13 13:39:12 +08:00

187 lines
6.9 KiB
TypeScript

/**
* Integration tests for models.dev sync: live fetch → DB save → retrieve → resolution order.
*
* Uses a test DB file in /tmp to avoid touching production data.
*/
import { describe, it, before, after } from "node:test";
import assert from "node:assert/strict";
import { unlinkSync, existsSync } from "node:fs";
// Point DB at a temp file
const TEST_DB = "/tmp/omniroute-test-modelsdev.sqlite";
before(() => {
if (existsSync(TEST_DB)) unlinkSync(TEST_DB);
process.env.DATA_DIR = "/tmp";
process.env.DB_FILE = TEST_DB;
});
after(() => {
if (existsSync(TEST_DB)) unlinkSync(TEST_DB);
});
describe("modelsDevSync — integration: live fetch → DB → retrieve", () => {
it("fetches, saves pricing, and retrieves from DB", async () => {
const {
syncModelsDev,
getModelsDevPricing,
getSyncedCapabilities,
clearModelsDevPricing,
clearModelsDevCapabilities,
} = await import("../../src/lib/modelsDevSync.ts");
// 1. Sync from live API
const result = await syncModelsDev({ dryRun: false, syncCapabilities: true });
assert.equal(result.success, true, `sync should succeed: ${result.error || ""}`);
assert.ok(result.modelCount > 0, `should have pricing entries, got ${result.modelCount}`);
assert.ok(result.providerCount > 0, `should have providers, got ${result.providerCount}`);
assert.ok(
result.capabilityCount > 0,
`should have capabilities, got ${result.capabilityCount}`
);
// 2. Retrieve pricing from DB
const pricing = getModelsDevPricing();
assert.ok(Object.keys(pricing).length > 0, "should have pricing in DB");
// 3. Verify specific known models
assert.ok(pricing.openai, "openai pricing should exist");
assert.ok(pricing.openai["gpt-4o"], "gpt-4o pricing should exist in openai");
assert.ok(pricing.openai["gpt-4o"].input > 0, "gpt-4o input price should be > 0");
assert.ok(pricing.openai["gpt-4o"].output > 0, "gpt-4o output price should be > 0");
assert.ok(pricing.anthropic, "anthropic pricing should exist");
const claudeModels = Object.keys(pricing.anthropic).filter((m) => m.includes("claude"));
assert.ok(claudeModels.length > 0, "should have claude pricing entries");
assert.ok(pricing.deepseek, "deepseek pricing should exist");
assert.ok(pricing.if, "if (Qoder) pricing should exist (mapped from deepseek)");
// 4. Retrieve capabilities from DB
const caps = getSyncedCapabilities();
assert.ok(Object.keys(caps).length > 0, "should have capabilities in DB");
assert.ok(caps.openai, "openai capabilities should exist");
assert.ok(caps.openai["gpt-4o"], "gpt-4o capabilities should exist");
assert.equal(caps.openai["gpt-4o"].tool_call, true);
assert.equal(caps.openai["gpt-4o"].reasoning, false);
assert.equal(caps.openai["gpt-4o"].attachment, true);
// 5. Query specific capability
const specificCaps = getSyncedCapabilities("openai", "gpt-4o");
assert.ok(specificCaps.openai, "specific query should return openai");
assert.ok(specificCaps.openai["gpt-4o"], "specific query should return gpt-4o");
assert.equal(specificCaps.openai["gpt-4o"].limit_context, 128000);
// 6. Cleanup
clearModelsDevPricing();
clearModelsDevCapabilities();
const afterPricing = getModelsDevPricing();
assert.equal(Object.keys(afterPricing).length, 0, "pricing should be cleared");
const afterCaps = getSyncedCapabilities();
assert.equal(Object.keys(afterCaps).length, 0, "capabilities should be cleared");
});
it("dryRun returns data without saving to DB", async () => {
const { syncModelsDev, getModelsDevPricing, clearModelsDevPricing } =
await import("../../src/lib/modelsDevSync.ts");
// Clear any existing data first
clearModelsDevPricing();
const result = await syncModelsDev({ dryRun: true, syncCapabilities: false });
assert.equal(result.success, true);
assert.ok(result.data, "dryRun should return data");
assert.ok(result.data.pricing, "dryRun should return pricing data");
// Verify nothing was saved
const pricing = getModelsDevPricing();
assert.equal(Object.keys(pricing).length, 0, "dryRun should not save to DB");
});
it("sync without capabilities only saves pricing", async () => {
const {
syncModelsDev,
getModelsDevPricing,
getSyncedCapabilities,
clearModelsDevPricing,
clearModelsDevCapabilities,
} = await import("../../src/lib/modelsDevSync.ts");
clearModelsDevPricing();
clearModelsDevCapabilities();
const result = await syncModelsDev({ dryRun: false, syncCapabilities: false });
assert.equal(result.success, true);
assert.ok(result.modelCount > 0, "should have pricing entries");
assert.equal(result.capabilityCount, 0, "capabilityCount should be 0 when disabled");
// Pricing should be saved
const pricing = getModelsDevPricing();
assert.ok(Object.keys(pricing).length > 0, "pricing should be saved");
// Capabilities should NOT be saved
const caps = getSyncedCapabilities();
assert.equal(Object.keys(caps).length, 0, "capabilities should not be saved");
clearModelsDevPricing();
});
});
describe("modelsDevSync — resolution order: user > models.dev > LiteLLM > default", () => {
it("returns models.dev pricing when no user override exists", async () => {
const { syncModelsDev, getModelsDevPricing, clearModelsDevPricing } =
await import("../../src/lib/modelsDevSync.ts");
clearModelsDevPricing();
await syncModelsDev({ dryRun: false, syncCapabilities: false });
const pricing = getModelsDevPricing();
assert.ok(pricing.openai, "openai pricing should exist");
assert.ok(pricing.openai["gpt-4o"], "gpt-4o should have models.dev pricing");
clearModelsDevPricing();
});
it("getPricing() merges all layers correctly", async () => {
const { getPricing } = await import("../../src/lib/db/settings.ts");
const { syncModelsDev, clearModelsDevPricing, saveModelsDevPricing } =
await import("../../src/lib/modelsDevSync.ts");
const { updatePricing, resetPricing } = await import("../../src/lib/db/settings.ts");
// Clear all synced data first
clearModelsDevPricing();
// Sync models.dev pricing
await syncModelsDev({ dryRun: false, syncCapabilities: false });
// Get merged pricing
const merged = await getPricing();
// Should have openai pricing (either from models.dev or hardcoded defaults)
assert.ok(merged.openai || merged.cx, "should have openai/cx pricing in merged result");
// Add a user override
await updatePricing({
openai: {
"gpt-4o": { input: 999, output: 999 },
},
});
// Verify user override wins
const mergedWithOverride = await getPricing();
assert.equal(
mergedWithOverride.openai?.["gpt-4o"]?.input,
999,
"user override should win over models.dev"
);
// Reset the override
await resetPricing("openai", "gpt-4o");
clearModelsDevPricing();
});
});