Some checks failed
CI / Frontend Lint (pull_request) Failing after 6s
CI / Frontend Type Check (pull_request) Failing after 7s
CI / Frontend Build (pull_request) Failing after 6s
CI / Frontend E2E Tests (pull_request) Failing after 8s
CI / Orchestrator Build (pull_request) Failing after 6s
CI / Contracts Compile (pull_request) Failing after 6s
CI / Contracts Test (pull_request) Failing after 7s
Code Quality / SonarQube Analysis (pull_request) Failing after 20s
Code Quality / Code Quality Checks (pull_request) Failing after 6s
Security Scan / Dependency Vulnerability Scan (pull_request) Failing after 4s
Security Scan / OWASP ZAP Scan (pull_request) Failing after 4s
Closes gap-analysis v2 §7.6 / §10.7. - Adds DEFAULT_PHASE_TIMEOUTS: Record<TransactionState, number | null> to orchestrator/src/types/transactionState.ts, covering all 12 states of the §8 state machine with rationale-per-state comments. - getPhaseTimeoutMs(state) honours per-state env overrides (PHASE_TIMEOUT_<STATE>=<ms>; '0' disables; invalid → default). - CLOSED is the only state with a null (no-timeout) value. - 9 unit tests; full suite passes.
76 lines
2.2 KiB
TypeScript
76 lines
2.2 KiB
TypeScript
/**
|
|
* Tests for per-state phase timeouts (arch §12.1 / gap v2 §7.6 / §10.7).
|
|
*/
|
|
|
|
import {
|
|
DEFAULT_PHASE_TIMEOUTS,
|
|
TRANSACTION_STATES,
|
|
getPhaseTimeoutMs,
|
|
} from "../../src/types/transactionState";
|
|
|
|
describe("PHASE_TIMEOUTS", () => {
|
|
const savedEnv = { ...process.env };
|
|
|
|
afterEach(() => {
|
|
process.env = { ...savedEnv };
|
|
});
|
|
|
|
it("has a mapping for every declared transaction state", () => {
|
|
for (const s of TRANSACTION_STATES) {
|
|
expect(DEFAULT_PHASE_TIMEOUTS).toHaveProperty(s);
|
|
}
|
|
});
|
|
|
|
it("CLOSED is the only state without a timeout", () => {
|
|
const nullStates = TRANSACTION_STATES.filter(
|
|
(s) => DEFAULT_PHASE_TIMEOUTS[s] === null,
|
|
);
|
|
expect(nullStates).toEqual(["CLOSED"]);
|
|
});
|
|
|
|
it("all non-terminal timeouts are strictly positive integers", () => {
|
|
for (const s of TRANSACTION_STATES) {
|
|
const v = DEFAULT_PHASE_TIMEOUTS[s];
|
|
if (v === null) continue;
|
|
expect(v).toBeGreaterThan(0);
|
|
expect(Number.isInteger(v)).toBe(true);
|
|
}
|
|
});
|
|
|
|
it("getPhaseTimeoutMs honours a valid env override", () => {
|
|
process.env.PHASE_TIMEOUT_EXECUTING = "123456";
|
|
expect(getPhaseTimeoutMs("EXECUTING")).toBe(123456);
|
|
});
|
|
|
|
it("getPhaseTimeoutMs treats override '0' as 'no timeout' (null)", () => {
|
|
process.env.PHASE_TIMEOUT_EXECUTING = "0";
|
|
expect(getPhaseTimeoutMs("EXECUTING")).toBeNull();
|
|
});
|
|
|
|
it("getPhaseTimeoutMs falls back to default when override is invalid", () => {
|
|
process.env.PHASE_TIMEOUT_EXECUTING = "not-a-number";
|
|
expect(getPhaseTimeoutMs("EXECUTING")).toBe(
|
|
DEFAULT_PHASE_TIMEOUTS.EXECUTING,
|
|
);
|
|
});
|
|
|
|
it("getPhaseTimeoutMs falls back to default when override is negative", () => {
|
|
process.env.PHASE_TIMEOUT_PREPARED = "-1";
|
|
expect(getPhaseTimeoutMs("PREPARED")).toBe(
|
|
DEFAULT_PHASE_TIMEOUTS.PREPARED,
|
|
);
|
|
});
|
|
|
|
it("returns the default when no env override exists", () => {
|
|
delete process.env.PHASE_TIMEOUT_VALIDATING;
|
|
expect(getPhaseTimeoutMs("VALIDATING")).toBe(
|
|
DEFAULT_PHASE_TIMEOUTS.VALIDATING,
|
|
);
|
|
});
|
|
|
|
it("CLOSED stays null even with no env override", () => {
|
|
delete process.env.PHASE_TIMEOUT_CLOSED;
|
|
expect(getPhaseTimeoutMs("CLOSED")).toBeNull();
|
|
});
|
|
});
|