mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-03 13:52:09 +03:00
Move chat pipeline validation, circuit breaker execution, proxy resolution, logging, and session header handling into dedicated helpers to keep the SSE handler smaller and easier to verify. Also fix shared API option precedence, rebuild skill version caches after deletions, ignore api.trycloudflare.com false positives, and add rate-limit manager test flush/reset hooks for deterministic coverage. Expand integration and unit coverage across chat routing, auth, cloud sync, skills, executors, streaming, DB helpers, proxy handling, and provider/model utilities.
330 lines
10 KiB
JavaScript
330 lines
10 KiB
JavaScript
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-db-models-"));
|
|
process.env.DATA_DIR = TEST_DATA_DIR;
|
|
|
|
const core = await import("../../src/lib/db/core.ts");
|
|
const modelsDb = await import("../../src/lib/db/models.ts");
|
|
|
|
async function resetStorage() {
|
|
core.resetDbInstance();
|
|
|
|
for (let attempt = 0; attempt < 10; attempt++) {
|
|
try {
|
|
if (fs.existsSync(TEST_DATA_DIR)) {
|
|
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
|
}
|
|
break;
|
|
} catch (error) {
|
|
if ((error?.code === "EBUSY" || error?.code === "EPERM") && attempt < 9) {
|
|
await new Promise((resolve) => setTimeout(resolve, 50 * (attempt + 1)));
|
|
} else {
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
|
|
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
|
|
}
|
|
|
|
test.beforeEach(async () => {
|
|
await resetStorage();
|
|
});
|
|
|
|
test.after(async () => {
|
|
core.resetDbInstance();
|
|
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
|
|
});
|
|
|
|
test("model aliases can be created, listed and deleted", async () => {
|
|
await modelsDb.setModelAlias("fast-default", { provider: "openai", model: "gpt-4.1-mini" });
|
|
await modelsDb.setModelAlias("reasoning", { provider: "anthropic", model: "claude-3-7-sonnet" });
|
|
|
|
const aliases = await modelsDb.getModelAliases();
|
|
|
|
assert.deepEqual(aliases["fast-default"], {
|
|
provider: "openai",
|
|
model: "gpt-4.1-mini",
|
|
});
|
|
assert.deepEqual(aliases.reasoning, {
|
|
provider: "anthropic",
|
|
model: "claude-3-7-sonnet",
|
|
});
|
|
|
|
await modelsDb.deleteModelAlias("fast-default");
|
|
|
|
assert.equal((await modelsDb.getModelAliases())["fast-default"], undefined);
|
|
});
|
|
|
|
test("MITM aliases support per-tool lookup and aggregated reads", async () => {
|
|
await modelsDb.setMitmAliasAll("cursor", {
|
|
"gpt-4.1": "cursor/gpt-4.1",
|
|
});
|
|
await modelsDb.setMitmAliasAll("codex", {
|
|
"gpt-4.1-mini": "codex/gpt-4.1-mini",
|
|
});
|
|
|
|
assert.deepEqual(await modelsDb.getMitmAlias("cursor"), {
|
|
"gpt-4.1": "cursor/gpt-4.1",
|
|
});
|
|
assert.deepEqual(await modelsDb.getMitmAlias(), {
|
|
cursor: { "gpt-4.1": "cursor/gpt-4.1" },
|
|
codex: { "gpt-4.1-mini": "codex/gpt-4.1-mini" },
|
|
});
|
|
});
|
|
|
|
test("custom models can be added once and queried by provider", async () => {
|
|
const created = await modelsDb.addCustomModel(
|
|
"openrouter",
|
|
"anthropic/claude-3.7-sonnet",
|
|
"Claude 3.7 Sonnet",
|
|
"manual",
|
|
"responses",
|
|
["chat", "responses"]
|
|
);
|
|
const duplicate = await modelsDb.addCustomModel(
|
|
"openrouter",
|
|
"anthropic/claude-3.7-sonnet",
|
|
"Claude 3.7 Sonnet"
|
|
);
|
|
const providerModels = await modelsDb.getCustomModels("openrouter");
|
|
const allModels = await modelsDb.getAllCustomModels();
|
|
|
|
assert.equal(duplicate.id, created.id);
|
|
assert.equal(providerModels.length, 1);
|
|
assert.deepEqual(providerModels[0], created);
|
|
assert.equal(allModels.openrouter.length, 1);
|
|
});
|
|
|
|
test("replaceCustomModels preserves compat fields and respects the empty-list guard", async () => {
|
|
await modelsDb.addCustomModel("openai", "gpt-4.1", "GPT-4.1");
|
|
await modelsDb.updateCustomModel("openai", "gpt-4.1", {
|
|
normalizeToolCallId: true,
|
|
preserveOpenAIDeveloperRole: false,
|
|
upstreamHeaders: {
|
|
"X-Test": " enabled ",
|
|
Host: "should-be-removed",
|
|
},
|
|
});
|
|
|
|
const replaced = await modelsDb.replaceCustomModels("openai", [
|
|
{
|
|
id: "gpt-4.1",
|
|
name: "GPT-4.1 Refreshed",
|
|
source: "api-sync",
|
|
supportsThinking: true,
|
|
},
|
|
]);
|
|
const guarded = await modelsDb.replaceCustomModels("openai", []);
|
|
|
|
assert.equal(replaced[0].normalizeToolCallId, true);
|
|
assert.equal(replaced[0].preserveOpenAIDeveloperRole, false);
|
|
assert.deepEqual(replaced[0].upstreamHeaders, { "X-Test": "enabled" });
|
|
assert.equal(replaced[0].supportsThinking, true);
|
|
assert.equal(guarded.length, 1);
|
|
|
|
await modelsDb.replaceCustomModels("openai", [], { allowEmpty: true });
|
|
|
|
assert.deepEqual(await modelsDb.getCustomModels("openai"), []);
|
|
});
|
|
|
|
test("removing a custom model also removes its compat override", async () => {
|
|
await modelsDb.addCustomModel("anthropic", "claude-3-haiku", "Claude 3 Haiku");
|
|
modelsDb.mergeModelCompatOverride("anthropic", "claude-3-haiku", {
|
|
normalizeToolCallId: true,
|
|
isHidden: true,
|
|
});
|
|
|
|
assert.equal(await modelsDb.removeCustomModel("anthropic", "claude-3-haiku"), true);
|
|
assert.equal(await modelsDb.removeCustomModel("anthropic", "claude-3-haiku"), false);
|
|
assert.deepEqual(await modelsDb.getCustomModels("anthropic"), []);
|
|
assert.deepEqual(modelsDb.getModelCompatOverrides("anthropic"), []);
|
|
});
|
|
|
|
test("synced available models are unioned across connections and cleaned per connection", async () => {
|
|
await modelsDb.replaceSyncedAvailableModelsForConnection("openai", "conn-a", [
|
|
{ id: "gpt-4.1", name: "GPT-4.1", source: "api-sync" },
|
|
{ id: "gpt-4.1-mini", name: "GPT-4.1 Mini", source: "api-sync" },
|
|
]);
|
|
const union = await modelsDb.replaceSyncedAvailableModelsForConnection("openai", "conn-b", [
|
|
{ id: "gpt-4.1-mini", name: "GPT-4.1 Mini", source: "api-sync" },
|
|
{ id: "o3-mini", name: "o3-mini", source: "api-sync" },
|
|
]);
|
|
const remaining = await modelsDb.deleteSyncedAvailableModelsForConnection("openai", "conn-a");
|
|
const allProviders = await modelsDb.getAllSyncedAvailableModels();
|
|
|
|
assert.deepEqual(union.map((model) => model.id).sort(), ["gpt-4.1", "gpt-4.1-mini", "o3-mini"]);
|
|
assert.deepEqual(remaining.map((model) => model.id).sort(), ["gpt-4.1-mini", "o3-mini"]);
|
|
assert.deepEqual(allProviders.openai.map((model) => model.id).sort(), [
|
|
"gpt-4.1-mini",
|
|
"o3-mini",
|
|
]);
|
|
});
|
|
|
|
test("compat overrides expose per-protocol getters and removable extra headers", async () => {
|
|
modelsDb.mergeModelCompatOverride("openai", "gpt-4.1", {
|
|
normalizeToolCallId: true,
|
|
preserveOpenAIDeveloperRole: false,
|
|
isHidden: true,
|
|
upstreamHeaders: {
|
|
"X-Top": "1",
|
|
"bad header": "skip",
|
|
},
|
|
compatByProtocol: {
|
|
openai: {
|
|
normalizeToolCallId: false,
|
|
preserveOpenAIDeveloperRole: true,
|
|
upstreamHeaders: {
|
|
"X-Proto": "yes",
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
assert.equal(modelsDb.getModelNormalizeToolCallId("openai", "gpt-4.1"), true);
|
|
assert.equal(modelsDb.getModelNormalizeToolCallId("openai", "gpt-4.1", "openai"), false);
|
|
assert.equal(modelsDb.getModelPreserveOpenAIDeveloperRole("openai", "gpt-4.1"), false);
|
|
assert.equal(modelsDb.getModelPreserveOpenAIDeveloperRole("openai", "gpt-4.1", "openai"), true);
|
|
assert.equal(modelsDb.getModelIsHidden("openai", "gpt-4.1"), true);
|
|
assert.deepEqual(modelsDb.getModelUpstreamExtraHeaders("openai", "gpt-4.1", "openai"), {
|
|
"X-Top": "1",
|
|
"X-Proto": "yes",
|
|
});
|
|
|
|
modelsDb.removeModelCompatOverride("openai", "gpt-4.1");
|
|
|
|
assert.equal(modelsDb.getModelNormalizeToolCallId("openai", "gpt-4.1"), false);
|
|
assert.deepEqual(modelsDb.getModelCompatOverrides("openai"), []);
|
|
});
|
|
|
|
test("sanitizeUpstreamHeadersMap keeps only safe trimmed headers", () => {
|
|
const sanitized = modelsDb.sanitizeUpstreamHeadersMap({
|
|
"X-First": " one ",
|
|
Host: "blocked",
|
|
"Bad Header": "blocked",
|
|
"X-Newline": "bad\nvalue",
|
|
"X-Second": 42,
|
|
});
|
|
|
|
assert.deepEqual(sanitized, {
|
|
"X-First": "one",
|
|
"X-Second": "42",
|
|
});
|
|
});
|
|
|
|
test("compat overrides ignore invalid protocol keys and can be fully removed again", () => {
|
|
modelsDb.mergeModelCompatOverride("openai", "gpt-4.1-mini", {
|
|
normalizeToolCallId: true,
|
|
preserveOpenAIDeveloperRole: true,
|
|
isHidden: true,
|
|
upstreamHeaders: {
|
|
"X-Test": "enabled",
|
|
Host: "blocked",
|
|
},
|
|
compatByProtocol: {
|
|
openai: {
|
|
normalizeToolCallId: false,
|
|
},
|
|
invalid: {
|
|
normalizeToolCallId: true,
|
|
},
|
|
},
|
|
});
|
|
|
|
let overrides = modelsDb.getModelCompatOverrides("openai");
|
|
|
|
assert.equal(overrides.length, 1);
|
|
assert.equal(overrides[0].compatByProtocol.invalid, undefined);
|
|
assert.deepEqual(overrides[0].upstreamHeaders, { "X-Test": "enabled" });
|
|
|
|
modelsDb.mergeModelCompatOverride("openai", "gpt-4.1-mini", {
|
|
normalizeToolCallId: false,
|
|
preserveOpenAIDeveloperRole: null,
|
|
isHidden: null,
|
|
upstreamHeaders: null,
|
|
compatByProtocol: {
|
|
openai: {
|
|
upstreamHeaders: {},
|
|
},
|
|
},
|
|
});
|
|
|
|
overrides = modelsDb.getModelCompatOverrides("openai");
|
|
|
|
assert.deepEqual(overrides, [
|
|
{
|
|
id: "gpt-4.1-mini",
|
|
compatByProtocol: {
|
|
openai: {
|
|
normalizeToolCallId: false,
|
|
},
|
|
},
|
|
},
|
|
]);
|
|
});
|
|
|
|
test("compat getters fall back to override rows when custom model storage is malformed", async () => {
|
|
await modelsDb.addCustomModel("anthropic", "claude-edge", "Claude Edge");
|
|
await modelsDb.updateCustomModel("anthropic", "claude-edge", {
|
|
normalizeToolCallId: true,
|
|
preserveOpenAIDeveloperRole: false,
|
|
upstreamHeaders: {
|
|
"X-Custom": "top",
|
|
},
|
|
compatByProtocol: {
|
|
openai: {
|
|
normalizeToolCallId: false,
|
|
preserveOpenAIDeveloperRole: true,
|
|
upstreamHeaders: {
|
|
"X-Proto": "proto",
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
modelsDb.mergeModelCompatOverride("anthropic", "claude-edge", {
|
|
normalizeToolCallId: true,
|
|
preserveOpenAIDeveloperRole: false,
|
|
isHidden: true,
|
|
upstreamHeaders: {
|
|
"X-Compat": "fallback",
|
|
},
|
|
compatByProtocol: {
|
|
openai: {
|
|
normalizeToolCallId: false,
|
|
preserveOpenAIDeveloperRole: true,
|
|
upstreamHeaders: {
|
|
"X-Compat-Proto": "fallback-proto",
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
const db = core.getDbInstance();
|
|
db.prepare("UPDATE key_value SET value = ? WHERE namespace = 'customModels' AND key = ?").run(
|
|
"{not-json",
|
|
"anthropic"
|
|
);
|
|
|
|
assert.equal(modelsDb.getModelNormalizeToolCallId("anthropic", "claude-edge", "openai"), false);
|
|
assert.equal(
|
|
modelsDb.getModelPreserveOpenAIDeveloperRole("anthropic", "claude-edge", "openai"),
|
|
true
|
|
);
|
|
assert.equal(modelsDb.getModelIsHidden("anthropic", "claude-edge"), true);
|
|
assert.deepEqual(modelsDb.getModelUpstreamExtraHeaders("anthropic", "claude-edge", "openai"), {
|
|
"X-Compat": "fallback",
|
|
"X-Compat-Proto": "fallback-proto",
|
|
});
|
|
});
|
|
|
|
test("missing alias helpers return empty results for unknown tools and providers", async () => {
|
|
assert.deepEqual(await modelsDb.getMitmAlias("missing-tool"), {});
|
|
assert.deepEqual(await modelsDb.getCustomModels("missing-provider"), []);
|
|
assert.deepEqual(await modelsDb.getAllSyncedAvailableModels(), {});
|
|
});
|