Files
OmniRoute/tests/unit/routing-events.test.ts
3g0r1ch d87b97a786 feat(routing): adaptive feedback loop v2 — operational/semantic quality, confidence, TTFT/ITL, end-to-end test (#10881)
Obrigado — feature substancial e bem estruturada: separa qualidade operacional (comportamento de wire: 4xx/5xx, 429, respostas malformadas, stream interrompido) de qualidade semântica (só setada por avaliadores externos, nunca inferida do sucesso HTTP), com confidence/sample-awareness para não deixar poucos sucessos de sorte dominarem o ranking. Instrumentação de streaming (TTFT/ITL) threaded até RoutingEvent, endpoint de explicabilidade, e teste E2E determinístico cobrindo degradação→recuperação→blip.

Validação (worktree própria a partir de origin/release/v3.8.50, merge limpo, 0 conflitos):
- typecheck:core limpo, complexity/cognitive-complexity dentro do baseline
- 59/59 testes passando (mlx-provider, routing-adaptive-e2e, routing-events(-concurrency), routing-otel, routing-quality, routing-scoring-quality, stream-timing, auto-combo-scoring-clamp)
2026-08-20 17:28:30 -03:00

142 lines
4.2 KiB
TypeScript

/**
* tests/unit/routing-events.test.ts
*
* Routing feedback foundation (open-sse/services/routing/events.ts):
* - createRoutingEvent normalizes defaults
* - outcomeFromStatus classifies HTTP statuses
* - MemoryRoutingEventStore is bounded and returns newest-first
* - dispatchRoutingEvent fans out to sinks and isolates a throwing sink
*/
import test from "node:test";
import assert from "node:assert/strict";
import {
MemoryRoutingEventStore,
createRoutingEvent,
outcomeFromStatus,
dispatchRoutingEvent,
registerRoutingEventSink,
listRoutingEventSinks,
clearRoutingEventSinks,
type RoutingEvent,
type RoutingEventSink,
} from "../../open-sse/services/routing/events.ts";
function event(partial: Partial<RoutingEvent> = {}): RoutingEvent {
return createRoutingEvent({
requestId: "req-1",
provider: "openai",
model: "gpt-4o",
strategy: "auto",
latencyMs: 120,
outcome: "success",
status: 200,
...partial,
});
}
test("createRoutingEvent fills observability defaults", () => {
const e = createRoutingEvent({
requestId: "req-x",
provider: "anthropic",
model: "claude-4",
latencyMs: 50,
outcome: "error",
status: 500,
});
assert.equal(e.strategy, "direct");
assert.equal(e.ttftMs, null);
assert.equal(e.inputTokens, null);
assert.equal(e.outputTokens, null);
assert.equal(e.cost, null);
assert.equal(e.retries, 0);
assert.equal(e.fallbackUsed, false);
assert.equal(e.finishReason, null);
assert.equal(e.connectionId, null);
assert.ok(e.ts > 0);
assert.equal(e.status, 500);
});
test("outcomeFromStatus classifies statuses", () => {
assert.equal(outcomeFromStatus(200), "success");
assert.equal(outcomeFromStatus(201), "success");
assert.equal(outcomeFromStatus(429), "rate_limited");
assert.equal(outcomeFromStatus(408), "timeout");
assert.equal(outcomeFromStatus(504), "timeout");
assert.equal(outcomeFromStatus(500), "error");
assert.equal(outcomeFromStatus(400), "error");
assert.equal(outcomeFromStatus(null), "error");
assert.equal(outcomeFromStatus(undefined), "error");
});
test("MemoryRoutingEventStore returns newest-first within capacity", () => {
const store = new MemoryRoutingEventStore(5);
for (let i = 0; i < 5; i++) store.record(event({ requestId: `r-${i}` }));
const recent = store.recent(5);
assert.equal(recent.length, 5);
assert.equal(recent[0].requestId, "r-4");
assert.equal(recent[4].requestId, "r-0");
});
test("MemoryRoutingEventStore is bounded and still newest-first after overflow", () => {
const store = new MemoryRoutingEventStore(3);
for (let i = 0; i < 10; i++) store.record(event({ requestId: `r-${i}` }));
assert.equal(store.size, 3);
const recent = store.recent(3);
assert.deepEqual(
recent.map((e) => e.requestId),
["r-9", "r-8", "r-7"]
);
store.clear();
assert.equal(store.size, 0);
assert.deepEqual(store.recent(), []);
});
test("dispatchRoutingEvent fans out to every registered sink", () => {
const seen: string[] = [];
const sink: RoutingEventSink = {
name: "test-a",
record: (e) => void seen.push(e.requestId),
};
const unsub = registerRoutingEventSink(sink);
try {
dispatchRoutingEvent(event({ requestId: "fan-1" }));
dispatchRoutingEvent(event({ requestId: "fan-2" }));
assert.deepEqual(seen, ["fan-1", "fan-2"]);
} finally {
unsub();
}
});
test("dispatchRoutingEvent isolates a throwing sink", () => {
const badSink: RoutingEventSink = {
name: "test-throw",
record: () => {
throw new Error("boom");
},
};
const goodSeen: string[] = [];
const goodSink: RoutingEventSink = {
name: "test-good",
record: (e) => void goodSeen.push(e.requestId),
};
registerRoutingEventSink(badSink);
registerRoutingEventSink(goodSink);
try {
dispatchRoutingEvent(event({ requestId: "isolated" }));
assert.deepEqual(goodSeen, ["isolated"]);
} finally {
clearRoutingEventSinks();
}
});
test("listRoutingEventSinks reports registered names", () => {
clearRoutingEventSinks();
assert.deepEqual(listRoutingEventSinks(), []);
const unsub = registerRoutingEventSink({ name: "probe", record: () => {} });
try {
assert.deepEqual(listRoutingEventSinks(), ["probe"]);
} finally {
unsub();
}
});