Spaces:
Runtime error
Runtime error
File size: 7,021 Bytes
cd8bd0a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | /**
* Tests for src/lib/db/serviceModels.ts
*
* Uses an isolated in-memory DB via DATA_DIR override.
*/
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";
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-service-models-"));
process.env.DATA_DIR = TEST_DATA_DIR;
process.env.NODE_ENV = "test";
process.env.DISABLE_SQLITE_AUTO_BACKUP = "true";
const core = await import("../../../src/lib/db/core.ts");
const { getServiceModels, saveServiceModels, markAllUnavailable } =
await import("../../../src/lib/db/serviceModels.ts");
function resetDb() {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
}
test.beforeEach(() => {
resetDb();
});
test.after(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("getServiceModels β returns [] when no row exists", () => {
const result = getServiceModels("9router");
assert.deepEqual(result, []);
});
test("saveServiceModels + getServiceModels β round-trips a list (with available flag)", () => {
const models = [
{ id: "9r/gemma-3n-e4b", name: "Gemma 3n", object: "model", owned_by: "google" },
{ id: "9r/llama-3.3-70b", name: "Llama 3.3 70B", object: "model", owned_by: "meta" },
];
saveServiceModels("9router", models);
const result = getServiceModels("9router");
assert.equal(result.length, 2);
// Models are enriched with available: true on save.
assert.equal(result[0].id, "9r/gemma-3n-e4b");
assert.equal(result[0].available, true);
assert.equal(result[1].id, "9r/llama-3.3-70b");
assert.equal(result[1].available, true);
});
test("saveServiceModels β incoming model replaces old; old model pruned to available=false", () => {
saveServiceModels("9router", [{ id: "old-model" }]);
saveServiceModels("9router", [{ id: "new-model" }]);
const result = getServiceModels("9router");
// Both old and new are present β old is pruned (available=false), new is active.
const byId = Object.fromEntries(result.map((m) => [m.id, m]));
assert.ok("old-model" in byId, "old-model should persist (soft delete)");
assert.equal(byId["old-model"].available, false);
assert.ok("new-model" in byId, "new-model should be present");
assert.equal(byId["new-model"].available, true);
});
test("saveServiceModels β saving empty list marks previous models as unavailable (no hard delete)", () => {
saveServiceModels("9router", [{ id: "some-model" }]);
saveServiceModels("9router", []);
const result = getServiceModels("9router");
// Pruning keeps the model around as unavailable rather than deleting.
assert.equal(result.length, 1);
assert.equal(result[0].id, "some-model");
assert.equal(result[0].available, false);
});
test("models are scoped by tool β different tools don't interfere", () => {
saveServiceModels("9router", [{ id: "nr-model" }]);
saveServiceModels("cliproxyapi", [{ id: "cli-model" }]);
assert.equal(getServiceModels("9router")[0].id, "nr-model");
assert.equal(getServiceModels("cliproxyapi")[0].id, "cli-model");
});
test("getServiceModels β tolerates corrupt JSON by returning []", () => {
const db = core.getDbInstance();
db.prepare("INSERT OR REPLACE INTO key_value (namespace, key, value) VALUES (?, ?, ?)").run(
"serviceModels",
"9router",
"not-valid-json{"
);
const result = getServiceModels("9router");
assert.deepEqual(result, []);
});
test("getServiceModels β returns [] when stored value is not an array", () => {
const db = core.getDbInstance();
db.prepare("INSERT OR REPLACE INTO key_value (namespace, key, value) VALUES (?, ?, ?)").run(
"serviceModels",
"9router",
JSON.stringify({ id: "not-an-array" })
);
const result = getServiceModels("9router");
assert.deepEqual(result, []);
});
test("saveServiceModels β pruning: models missing from new payload have available=false", () => {
// Initial save with 3 models.
saveServiceModels("9router", [
{ id: "9router/model-a" },
{ id: "9router/model-b" },
{ id: "9router/model-c" },
]);
// Second save β model-b is missing (pruned), model-c stays, model-d is new.
saveServiceModels("9router", [{ id: "9router/model-c" }, { id: "9router/model-d" }]);
const result = getServiceModels("9router");
const byId = Object.fromEntries(result.map((m) => [m.id, m]));
// model-a was in first payload but not second, should be pruned
assert.ok("9router/model-a" in byId, "pruned model-a should still exist (soft delete)");
assert.equal(byId["9router/model-a"].available, false, "pruned model-a should be unavailable");
// model-b was in first payload but not second, should be pruned
assert.ok("9router/model-b" in byId, "pruned model-b should still exist (soft delete)");
assert.equal(byId["9router/model-b"].available, false, "pruned model-b should be unavailable");
// model-c was in both payloads β should be available
assert.equal(byId["9router/model-c"].available, true, "model-c should be available");
// model-d is new β should be available
assert.equal(byId["9router/model-d"].available, true, "model-d should be available");
});
test("saveServiceModels β incoming models are marked available=true", () => {
saveServiceModels("9router", [{ id: "9router/cx/gpt-5-mini", name: "GPT-5 mini" }]);
const result = getServiceModels("9router");
assert.equal(result.length, 1);
assert.equal(result[0].available, true);
});
test("markAllUnavailable β flips all rows for the given tool to available=false", () => {
saveServiceModels("9router", [{ id: "9router/model-x" }, { id: "9router/model-y" }]);
markAllUnavailable("9router");
const result = getServiceModels("9router");
assert.equal(result.length, 2);
for (const m of result) {
assert.equal(m.available, false, `${m.id} should be unavailable after markAllUnavailable`);
}
});
test("markAllUnavailable β does not affect other tools", () => {
saveServiceModels("9router", [{ id: "9router/model-x" }]);
saveServiceModels("cliproxy", [{ id: "cliproxy/model-z" }]);
markAllUnavailable("9router");
const cliproxyModels = getServiceModels("cliproxy");
assert.equal(cliproxyModels.length, 1);
// cliproxy models should not have been touched
assert.notEqual(cliproxyModels[0].available, false, "cliproxy model should not be affected");
});
test("markAllUnavailable β is a no-op when no models stored", () => {
assert.doesNotThrow(() => markAllUnavailable("9router"));
const result = getServiceModels("9router");
assert.deepEqual(result, []);
});
test("available field exists on ServiceModel interface (structural check)", () => {
saveServiceModels("9router", [{ id: "9router/test-model", available: true }]);
const result = getServiceModels("9router");
assert.ok("available" in result[0], "available field should be present in stored model");
});
|