64 lines
2.2 KiB
TypeScript
64 lines
2.2 KiB
TypeScript
import { test, before, after, afterEach } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import {
|
|
getCircuitBreaker,
|
|
resetAllCircuitBreakers,
|
|
STATE,
|
|
} from "../../src/shared/utils/circuitBreaker.ts";
|
|
import { checkFallbackError } from "../../open-sse/services/accountFallback.ts";
|
|
import { startFaultyUpstream, type FaultyUpstream } from "../helpers/faultyUpstream.ts";
|
|
|
|
const RUN = process.env.RUN_CHAOS_INT === "1";
|
|
|
|
let up: FaultyUpstream;
|
|
before(async () => {
|
|
up = await startFaultyUpstream({ kind: "ok" });
|
|
});
|
|
after(async () => {
|
|
await up?.stop();
|
|
});
|
|
afterEach(() => {
|
|
resetAllCircuitBreakers();
|
|
});
|
|
|
|
test("breaker OPENs after real timeouts, then refreshes to HALF_OPEN", { skip: !RUN }, async () => {
|
|
up.setMode({ kind: "timeout" });
|
|
const breaker = getCircuitBreaker("chaos-timeout", {
|
|
failureThreshold: 3,
|
|
resetTimeout: 300,
|
|
isFailure: () => true,
|
|
});
|
|
for (let i = 0; i < 3; i++) {
|
|
await assert.rejects(() =>
|
|
breaker.execute(() => fetch(up.url, { signal: AbortSignal.timeout(120) }))
|
|
);
|
|
}
|
|
assert.equal(breaker.canExecute(), false);
|
|
assert.equal(breaker.getStatus().state, STATE.OPEN);
|
|
await new Promise((r) => setTimeout(r, 330));
|
|
assert.equal(breaker.getStatus().state, STATE.HALF_OPEN);
|
|
assert.equal(breaker.canExecute(), true);
|
|
});
|
|
|
|
test("breaker trips on a real connection reset", { skip: !RUN }, async () => {
|
|
up.setMode({ kind: "reset" });
|
|
const breaker = getCircuitBreaker("chaos-reset", {
|
|
failureThreshold: 2,
|
|
resetTimeout: 300,
|
|
isFailure: () => true,
|
|
});
|
|
for (let i = 0; i < 2; i++) {
|
|
await assert.rejects(() => breaker.execute(() => fetch(up.url)));
|
|
}
|
|
assert.equal(breaker.getStatus().state, STATE.OPEN);
|
|
});
|
|
|
|
test("checkFallbackError classifies a real 503 response as recoverable fallback", { skip: !RUN }, async () => {
|
|
up.setMode({ kind: "status", code: 503, body: "service unavailable" });
|
|
const res = await fetch(up.url);
|
|
const text = await res.text();
|
|
const decision = checkFallbackError(res.status, text, 0, null, "chaos-provider", res.headers);
|
|
assert.equal(decision.shouldFallback, true);
|
|
assert.ok(decision.cooldownMs > 0, "503 should yield a positive cooldown");
|
|
});
|