Files
OmniRoute/tests/unit/batch-a-domain.test.mjs
T
diegosouzapw 71d14209a4 feat: OmniRoute v1.0.0 — Intelligent AI Gateway & Universal LLM Proxy
OmniRoute is an intelligent API gateway that unifies 20+ AI providers behind a single
OpenAI-compatible endpoint. Features include intelligent routing with 6 strategies,
multi-format translation (OpenAI/Claude/Gemini/Responses API), circuit breakers,
semantic caching, combo fallback chains, real-time health monitoring, and a full
dashboard with provider management, analytics, and CLI tool integration.

Key highlights:
- 20+ providers (Claude Code, Codex, Gemini CLI, GitHub Copilot, iFlow, Qwen, Kiro, etc.)
- 6 routing strategies (Fill First, Round Robin, P2C, Random, Least Used, Cost Optimized)
- Export/Import database backup with full archive support
- Translator Playground with 4 modes (Playground, Chat Tester, Test Bench, Live Monitor)
- 100% TypeScript across src/ and open-sse/
- Docker support with multi-stage builds
- Comprehensive documentation and 9 dashboard screenshots
2026-02-18 00:02:15 -03:00

289 lines
9.1 KiB
JavaScript

/**
* Batch A — Domain Layer + Infrastructure Tests
*
* Tests for: modelAvailability, costRules, fallbackPolicy,
* errorCodes, requestId, fetchTimeout
*/
import { describe, it, before, after } from "node:test";
import assert from "node:assert/strict";
// ──────────────── T-19: Model Availability ────────────────
import {
isModelAvailable,
setModelUnavailable,
clearModelUnavailability,
getAvailabilityReport,
getUnavailableCount,
resetAllAvailability,
} from "../../src/domain/modelAvailability.ts";
describe("modelAvailability", () => {
before(() => resetAllAvailability());
after(() => resetAllAvailability());
it("should report model as available by default", () => {
assert.equal(isModelAvailable("openai", "gpt-4o"), true);
});
it("should mark model as unavailable", () => {
setModelUnavailable("openai", "gpt-4o", 60000, "rate limited");
assert.equal(isModelAvailable("openai", "gpt-4o"), false);
});
it("should report unavailable models", () => {
const report = getAvailabilityReport();
assert.equal(report.length, 1);
assert.equal(report[0].provider, "openai");
assert.equal(report[0].model, "gpt-4o");
assert.equal(report[0].reason, "rate limited");
assert.ok(report[0].remainingMs > 0);
});
it("should count unavailable models", () => {
assert.equal(getUnavailableCount(), 1);
});
it("should clear model unavailability", () => {
clearModelUnavailability("openai", "gpt-4o");
assert.equal(isModelAvailable("openai", "gpt-4o"), true);
assert.equal(getUnavailableCount(), 0);
});
it("should auto-expire after cooldown", () => {
setModelUnavailable("anthropic", "claude-sonnet-4-20250514", 1, "test");
// Wait 2ms for expiry
const start = Date.now();
while (Date.now() - start < 5) {} // spin wait
assert.equal(isModelAvailable("anthropic", "claude-sonnet-4-20250514"), true);
});
});
// ──────────────── T-19: Cost Rules ────────────────
import {
setBudget,
getBudget,
recordCost,
checkBudget,
getDailyTotal,
getCostSummary,
resetCostData,
} from "../../src/domain/costRules.ts";
describe("costRules", () => {
before(() => resetCostData());
after(() => resetCostData());
it("should allow when no budget set", () => {
const result = checkBudget("key-1");
assert.equal(result.allowed, true);
});
it("should set and get budget", () => {
setBudget("key-1", { dailyLimitUsd: 10.0, warningThreshold: 0.8 });
const budget = getBudget("key-1");
assert.equal(budget.dailyLimitUsd, 10.0);
assert.equal(budget.warningThreshold, 0.8);
});
it("should record costs and check budget", () => {
recordCost("key-1", 5.0);
const result = checkBudget("key-1");
assert.equal(result.allowed, true);
assert.equal(result.dailyUsed, 5.0);
});
it("should detect warning threshold", () => {
recordCost("key-1", 4.0); // total = 9.0 / 10.0 = 90% > 80%
const result = checkBudget("key-1");
assert.equal(result.allowed, true);
assert.equal(result.warningReached, true);
});
it("should block when budget exceeded", () => {
const result = checkBudget("key-1", 2.0); // 9.0 + 2.0 = 11.0 > 10.0
assert.equal(result.allowed, false);
assert.ok(result.reason.includes("exceeded"));
});
it("should get cost summary", () => {
const summary = getCostSummary("key-1");
assert.ok(summary.dailyTotal >= 9.0);
assert.equal(summary.totalEntries, 2);
});
});
// ──────────────── T-19: Fallback Policy ────────────────
import {
registerFallback,
resolveFallbackChain,
getNextFallback,
hasFallback,
removeFallback,
getAllFallbackChains,
resetAllFallbacks,
} from "../../src/domain/fallbackPolicy.ts";
describe("fallbackPolicy", () => {
before(() => resetAllFallbacks());
after(() => resetAllFallbacks());
it("should return empty chain for unknown model", () => {
assert.deepEqual(resolveFallbackChain("unknown"), []);
assert.equal(hasFallback("unknown"), false);
});
it("should register fallback chain sorted by priority", () => {
registerFallback("gpt-4o", [
{ provider: "azure", priority: 2 },
{ provider: "openai", priority: 0 },
{ provider: "github", priority: 1 },
]);
const chain = resolveFallbackChain("gpt-4o");
assert.equal(chain[0].provider, "openai");
assert.equal(chain[1].provider, "github");
assert.equal(chain[2].provider, "azure");
});
it("should exclude specified providers", () => {
const chain = resolveFallbackChain("gpt-4o", ["openai"]);
assert.equal(chain.length, 2);
assert.equal(chain[0].provider, "github");
});
it("should get next fallback", () => {
assert.equal(getNextFallback("gpt-4o"), "openai");
assert.equal(getNextFallback("gpt-4o", ["openai"]), "github");
assert.equal(getNextFallback("gpt-4o", ["openai", "github", "azure"]), null);
});
it("should respect enabled flag", () => {
registerFallback("test-model", [
{ provider: "a", enabled: false },
{ provider: "b", enabled: true },
]);
const chain = resolveFallbackChain("test-model");
assert.equal(chain.length, 1);
assert.equal(chain[0].provider, "b");
});
it("should remove fallback chain", () => {
removeFallback("test-model");
assert.equal(hasFallback("test-model"), false);
});
it("should list all chains", () => {
const all = getAllFallbackChains();
assert.ok("gpt-4o" in all);
});
});
// ──────────────── T-22: Error Codes ────────────────
import {
ERROR_CODES,
createErrorResponse,
getErrorsByCategory,
} from "../../src/shared/constants/errorCodes.ts";
describe("errorCodes", () => {
it("should have at least 20 error codes", () => {
assert.ok(Object.keys(ERROR_CODES).length >= 20);
});
it("should create error response for known code", () => {
const res = createErrorResponse("AUTH_001", { detail: "missing token" });
assert.equal(res.error.code, "AUTH_001");
assert.equal(res.error.message, "Authentication required");
assert.equal(res.status, 401);
assert.equal(res.error.detail, "missing token");
});
it("should create error response with requestId", () => {
const res = createErrorResponse("PROXY_002", { requestId: "abc-123" });
assert.equal(res.error.requestId, "abc-123");
assert.equal(res.status, 504);
});
it("should handle unknown code gracefully", () => {
const res = createErrorResponse("UNKNOWN_999");
assert.equal(res.status, 500);
assert.ok(res.error.message.includes("Unknown"));
});
it("should filter by category", () => {
const authErrors = getErrorsByCategory("AUTH");
assert.ok(authErrors.length >= 4);
assert.ok(authErrors.every((e) => e.category === "AUTH"));
});
});
// ──────────────── T-23: Request ID ────────────────
import {
getRequestId,
withRequestId,
addRequestIdHeader,
generateRequestId,
} from "../../src/shared/utils/requestId.ts";
describe("requestId", () => {
it("should return null outside context", () => {
assert.equal(getRequestId(), null);
});
it("should generate UUID format", () => {
const id = generateRequestId();
assert.match(id, /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/);
});
it("should propagate request ID through context", async () => {
const mockRequest = { headers: { get: (h) => (h === "x-request-id" ? "test-id-123" : null) } };
let captured = null;
await withRequestId(mockRequest, () => {
captured = getRequestId();
});
assert.equal(captured, "test-id-123");
});
it("should generate new ID when none provided", async () => {
const mockRequest = { headers: { get: () => null } };
let captured = null;
await withRequestId(mockRequest, () => {
captured = getRequestId();
});
assert.ok(captured);
assert.match(captured, /^[0-9a-f-]{36}$/);
});
it("should add request ID to headers", async () => {
const mockRequest = { headers: { get: (h) => (h === "x-request-id" ? "header-id" : null) } };
await withRequestId(mockRequest, () => {
const headers = addRequestIdHeader({ "content-type": "application/json" });
assert.equal(headers["x-request-id"], "header-id");
assert.equal(headers["content-type"], "application/json");
});
});
});
// ──────────────── T-25: Fetch Timeout ────────────────
import { getConfiguredTimeout, FetchTimeoutError } from "../../src/shared/utils/fetchTimeout.ts";
describe("fetchTimeout", () => {
it("should have default timeout of 120000ms", () => {
assert.equal(getConfiguredTimeout(), 120000);
});
it("should export FetchTimeoutError", () => {
const err = new FetchTimeoutError("test", 5000, "http://test.com");
assert.equal(err.name, "FetchTimeoutError");
assert.equal(err.timeoutMs, 5000);
assert.equal(err.url, "http://test.com");
assert.ok(err instanceof Error);
});
});