Files
OmniRoute/tests/unit/db-schema-columns-split.test.ts
Praveen K Palaniswamy 65e81158ab fix(ollama): route models by advertised capability (#11088)
Landed with the design call resolved per the owner's pick — **option 1**: the synced store is now endpoint-agnostic (persistDiscoveredModels and managedModelImport no longer drop non-chat models at write time), and chat selectability moved to read time (auto-pool expansion in autoStrategy applies filterChatSelectableModels; the models-route projection already had its chatOnly filter). Your discovery test now passes end-to-end (3/3): /api/show capabilities persist per connection and image/embedding requests route through the advertising host.

Reconciliation notes: conflicted areas merged onto the current tip (adobe discovery import, requestedModel preflight signature, resolvedProvider fast-path coexists with the synced-route override — explicit resolution wins); carried base-red drains (#10055 memoization, #11071 test variants) dropped as already-landed; the managed-model-import exclusion test was propagated to the new contract (image/video models persist; the read filter still hides them from chat pickers — pinned by a new assertion). Full battery: 205/206 focused (the one red is a confirmed periodic-timer timing flake on the loaded devbox — 20/20 isolated), autoCombo vitest 30/30, combo suites 46/46, gates + typecheck clean.

Thank you @yourspraveen — the capability probe + routing design was right; it just needed the store contract opened up. Fixes #11087.
2026-08-23 11:45:01 -03:00

166 lines
5.8 KiB
TypeScript

// Characterization of the db/core.ts schema-column split (god-file decomposition): the idempotent
// ALTER-TABLE column reconcilers + table introspection helpers moved into db/schemaColumns.ts. These
// run an in-memory SQLite db through the helpers to lock the observable behavior: ensure* adds missing
// columns and is safe to re-run; hasTable/hasColumn/getTableColumns/quoteIdentifier introspect.
import { test } from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";
import { tryOpenSync } from "../../src/lib/db/adapters/driverFactory.ts";
import {
ensureUsageHistoryColumns,
ensureProviderConnectionsColumns,
ensureProxyLogsColumns,
hasColumn,
hasTable,
quoteIdentifier,
getTableColumns,
} from "../../src/lib/db/schemaColumns.ts";
function openMemoryDb() {
// Synchronous in-memory adapter — no DATA_DIR / file handles to clean up.
const db = tryOpenSync(":memory:");
assert.ok(db, "expected a synchronous sqlite adapter for :memory:");
return db!;
}
test("quoteIdentifier escapes embedded double quotes", () => {
assert.equal(quoteIdentifier("plain"), '"plain"');
assert.equal(quoteIdentifier('we"ird'), '"we""ird"');
});
test("hasTable / hasColumn / getTableColumns introspect a live table", () => {
const db = openMemoryDb();
try {
db.exec("CREATE TABLE usage_history (id INTEGER PRIMARY KEY, model TEXT)");
assert.equal(hasTable(db, "usage_history"), true);
assert.equal(hasTable(db, "does_not_exist"), false);
assert.equal(hasColumn(db, "usage_history", "model"), true);
assert.equal(hasColumn(db, "usage_history", "nope"), false);
assert.deepEqual(getTableColumns(db, "usage_history").sort(), ["id", "model"]);
} finally {
db.close?.();
}
});
test("ensureUsageHistoryColumns adds missing columns and is idempotent", () => {
const db = openMemoryDb();
try {
db.exec("CREATE TABLE usage_history (id INTEGER PRIMARY KEY, model TEXT)");
assert.equal(hasColumn(db, "usage_history", "service_tier"), false);
ensureUsageHistoryColumns(db);
for (const col of [
"success",
"latency_ms",
"ttft_ms",
"error_code",
"service_tier",
"combo_strategy",
]) {
assert.equal(hasColumn(db, "usage_history", col), true, `expected ${col} after ensure`);
}
// Re-running must not throw (columns already present) — idempotency.
assert.doesNotThrow(() => ensureUsageHistoryColumns(db));
} finally {
db.close?.();
}
});
test("ensureProviderConnectionsColumns repairs quota visibility with a visible default", () => {
const db = openMemoryDb();
try {
db.exec("CREATE TABLE provider_connections (id TEXT PRIMARY KEY, provider TEXT NOT NULL)");
assert.equal(hasColumn(db, "provider_connections", "quota_visible"), false);
ensureProviderConnectionsColumns(db);
assert.equal(hasColumn(db, "provider_connections", "quota_visible"), true);
const column = db
.prepare("PRAGMA table_info(provider_connections)")
.all()
.find((entry: { name?: string }) => entry.name === "quota_visible") as
{ notnull?: number; dflt_value?: string } | undefined;
assert.equal(column?.notnull, 1);
assert.equal(column?.dflt_value, "1");
assert.doesNotThrow(() => ensureProviderConnectionsColumns(db));
} finally {
db.close?.();
}
});
test("ensureProxyLogsColumns self-heals a bare proxy_logs (upgrade path)", () => {
const db = openMemoryDb();
try {
db.exec("CREATE TABLE proxy_logs (id TEXT PRIMARY KEY, timestamp TEXT NOT NULL)");
assert.equal(hasColumn(db, "proxy_logs", "egress_ip"), false);
ensureProxyLogsColumns(db);
assert.equal(hasColumn(db, "proxy_logs", "egress_ip"), true);
assert.doesNotThrow(() => ensureProxyLogsColumns(db));
} finally {
db.close?.();
}
});
test("migration 134 SQL applies egress_ip to a bare proxy_logs", () => {
const db = openMemoryDb();
try {
db.exec("CREATE TABLE proxy_logs (id TEXT PRIMARY KEY, timestamp TEXT NOT NULL)");
const sql = fs.readFileSync(
path.join(process.cwd(), "src/lib/db/migrations/134_proxy_logs_egress_ip.sql"),
"utf8"
);
db.exec(sql);
assert.equal(hasColumn(db, "proxy_logs", "egress_ip"), true);
} finally {
db.close?.();
}
});
test("ensureProviderConnectionsColumns restores base columns required by later migrations", () => {
const db = openMemoryDb();
try {
db.exec(`
CREATE TABLE provider_connections (
id TEXT PRIMARY KEY,
provider TEXT NOT NULL,
auth_type TEXT,
is_active INTEGER NOT NULL DEFAULT 1
)
`);
assert.equal(hasColumn(db, "provider_connections", "provider_specific_data"), false);
assert.equal(hasColumn(db, "provider_connections", "default_model"), false);
ensureProviderConnectionsColumns(db);
assert.equal(hasColumn(db, "provider_connections", "provider_specific_data"), true);
assert.equal(hasColumn(db, "provider_connections", "default_model"), true);
const columnsAfterFirstRun = getTableColumns(db, "provider_connections").sort();
const indexesAfterFirstRun = (
db.prepare("PRAGMA index_list(provider_connections)").all() as Array<{ name: string }>
)
.map((index) => index.name)
.sort();
const warnings: unknown[][] = [];
const originalWarn = console.warn;
try {
console.warn = (...args: unknown[]) => warnings.push(args);
ensureProviderConnectionsColumns(db);
} finally {
console.warn = originalWarn;
}
assert.deepEqual(getTableColumns(db, "provider_connections").sort(), columnsAfterFirstRun);
assert.deepEqual(
(db.prepare("PRAGMA index_list(provider_connections)").all() as Array<{ name: string }>)
.map((index) => index.name)
.sort(),
indexesAfterFirstRun
);
assert.deepEqual(warnings, []);
} finally {
db.close?.();
}
});