mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
* feat(settings): configurable model catalog cache TTL Add modelCatalogCacheTtlMs to DatabaseSettings with default 1500ms. Extend cache-config API route to accept the new field. Replace hardcoded catalog cache TTL with dynamic settings value. Add 'Cache' settings tab at /dashboard/settings/cache with sidebar entry, i18n keys, header description, and legacy route redirect. * feat(combo): add model connection filter toggle to ModelSelectModal Adds a 'Show configured only' checkbox below the search bar in ModelSelectModal that filters each provider group's models through hasEligibleConnectionForModel. Toggle state persists in localStorage. - Import hasEligibleConnectionForModel from domain/connectionModelRules - showConfiguredOnly state + localStorage persistence - connectionFilteredGroups memo layered on filteredGroups - Renders both provider section and empty state from connectionFilteredGroups * test(combo): add connection filter toggle tests for ModelSelectModal Three test cases: (1) hide excluded models when toggle on, (2) show empty state when all models excluded, (3) drop provider group when all its models excluded. All 3 tests pass. * fix(settings): correct cache-config route import + add route/tab coverage The cache-config route imported get/update helpers from a nonexistent module (@/lib/localDb/databaseSettings) and called an undefined updateSettings() in PUT, crashing every request. Import the real databaseSettings module (matching the sibling database/route.ts convention) and call updateDatabaseSettings(); idempotencyWindowMs is routed through the flat @/lib/db/settings module instead, since that is where it is actually read at runtime (idempotencyLayer.ts, runtimeSettings.ts) — it was never part of the databaseSettings "cache" section type. Also fixes a dashboard-typecheck regression in ModelSelectModal.tsx: the new connection-filter toggle called hasEligibleConnectionForModel() with activeProviders entries typed too narrowly to include providerSpecificData, which real connection objects carry at runtime. Adds: - tests/unit/cache-config-route-8219.test.ts: GET/PUT resolve without crashing, modelCatalogCacheTtlMs and idempotencyWindowMs round-trip. - tests/unit/ui/cache-settings-tab-bounds-8219.test.tsx: CacheSettingsTab min/max TTL bounds (100ms/60000ms) gate the Save button and surface a validation message; in-bounds values PUT correctly. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * chore(quality): rebaseline sections.ts for #8219 own-growth --------- Co-authored-by: oyi77 <oyi77@users.noreply.github.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
84 lines
3.1 KiB
TypeScript
84 lines
3.1 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import fs from "node:fs";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
|
|
// Regression guard for #8219: the cache-config route imported
|
|
// `updateSettings`/`getDatabaseSettings`/`updateDatabaseSettings` from a
|
|
// non-existent module (`@/lib/localDb/databaseSettings`) and called an
|
|
// undefined `updateSettings` in PUT. Any request crashed the route with a
|
|
// ReferenceError before this fix. This test proves:
|
|
// 1. The route module resolves without throwing on import.
|
|
// 2. GET/PUT resolve without crashing.
|
|
// 3. `modelCatalogCacheTtlMs` round-trips through PUT then GET.
|
|
|
|
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-cache-config-"));
|
|
process.env.DATA_DIR = TEST_DATA_DIR;
|
|
process.env.DISABLE_SQLITE_AUTO_BACKUP = "true";
|
|
|
|
const core = await import("../../src/lib/db/core.ts");
|
|
|
|
function resetStorage() {
|
|
core.resetDbInstance();
|
|
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
|
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
|
|
}
|
|
|
|
function makeJsonRequest(method: string, body?: unknown): Request {
|
|
return new Request("http://localhost/api/settings/cache-config", {
|
|
method,
|
|
headers: { "Content-Type": "application/json" },
|
|
body: body === undefined ? undefined : JSON.stringify(body),
|
|
});
|
|
}
|
|
|
|
test.beforeEach(() => {
|
|
resetStorage();
|
|
});
|
|
|
|
test.after(() => {
|
|
resetStorage();
|
|
});
|
|
|
|
test("cache-config route resolves and modelCatalogCacheTtlMs round-trips", async (t) => {
|
|
// Importing the route module must not throw (RED before the fix: the
|
|
// module-level import of a nonexistent path crashed at import time).
|
|
const cacheConfigRoute = await import("../../src/app/api/settings/cache-config/route.ts");
|
|
|
|
await t.test("GET resolves without crashing and returns defaults", async () => {
|
|
const response = await cacheConfigRoute.GET(makeJsonRequest("GET") as never);
|
|
const body = await response.json();
|
|
|
|
assert.equal(response.status, 200);
|
|
assert.equal(typeof body.modelCatalogCacheTtlMs, "number");
|
|
});
|
|
|
|
await t.test("PUT resolves without crashing and persists the new TTL", async () => {
|
|
const putResponse = await cacheConfigRoute.PUT(
|
|
makeJsonRequest("PUT", { modelCatalogCacheTtlMs: 4242 }) as never
|
|
);
|
|
const putBody = await putResponse.json();
|
|
|
|
assert.equal(putResponse.status, 200);
|
|
assert.equal(putBody.ok, true);
|
|
|
|
const getResponse = await cacheConfigRoute.GET(makeJsonRequest("GET") as never);
|
|
const getBody = await getResponse.json();
|
|
|
|
assert.equal(getResponse.status, 200);
|
|
assert.equal(getBody.modelCatalogCacheTtlMs, 4242, "modelCatalogCacheTtlMs must round-trip");
|
|
});
|
|
|
|
await t.test("PUT persists idempotencyWindowMs via the flat settings module", async () => {
|
|
const putResponse = await cacheConfigRoute.PUT(
|
|
makeJsonRequest("PUT", { idempotencyWindowMs: 9000 }) as never
|
|
);
|
|
assert.equal(putResponse.status, 200);
|
|
|
|
const getResponse = await cacheConfigRoute.GET(makeJsonRequest("GET") as never);
|
|
const getBody = await getResponse.json();
|
|
assert.equal(getBody.idempotencyWindowMs, 9000);
|
|
});
|
|
});
|