import { describe, expect, it, vi } from "vitest"; import { createContractHttpExecutor } from "../../src/adapters/http/http-execution-v3.ts"; import type { InstalledHttpContract } from "../../src/contracts/external-contract-runtime.ts"; import { TEST_CREATE_HTTP_CONTRACT, TEST_LIST_HTTP_CONTRACT, } from "../helpers/external-contract-fixture.ts"; const installed: InstalledHttpContract = TEST_LIST_HTTP_CONTRACT; const scope = Object.freeze({ generation: 1, fingerprint: "scope-1", identities: Object.freeze({}) as never, signal: new AbortController().signal, isCurrent: () => true, }); const createInstalled: InstalledHttpContract = TEST_CREATE_HTTP_CONTRACT; function mutationIntent( overrides: Readonly<{ intentId?: string; operationId?: string; idempotencyKey?: string | null; }> = {}, ) { return Object.freeze({ intentId: overrides.intentId ?? "intent-1", operationId: overrides.operationId ?? "TEST_CREATE_ENTITY", canonicalInputIdentity: "opaque-input-identity", ...(overrides.idempotencyKey === null ? {} : { idempotencyKey: overrides.idempotencyKey ?? "key-1" }), createdAtMonotonicMs: 1, }); } function operation( overrides: Readonly<{ deadlineMs?: number; responseBody?: "REQUIRED_JSON" | "OPTIONAL_JSON" | "NONE"; }> = {}, ): InstalledHttpContract { return { ...installed, contract: { ...installed.contract, responseBody: overrides.responseBody ?? installed.contract.responseBody, }, frontend: { ...installed.frontend, totalDeadlineMs: overrides.deadlineMs ?? installed.frontend.totalDeadlineMs, }, }; } async function flushMicrotasks(): Promise { await Promise.resolve(); await Promise.resolve(); await Promise.resolve(); } describe("descriptor-driven HTTP execution lifetime", () => { it.each([ ["absent intent", () => undefined], ["empty key", () => mutationIntent({ idempotencyKey: "" })], ["control-character key", () => mutationIntent({ idempotencyKey: "key\u0000private" })], ["over-budget key", () => mutationIntent({ idempotencyKey: "k".repeat(257) })], [ "wrong operation", () => mutationIntent({ operationId: "TEST_OTHER_COMMAND" }), ], ])( "rejects a KEYED command with %s before credentials or fetch", async (_label, intentFactory) => { const attachCredentials = vi.fn(() => ({ kind: "READY" as const, headers: {}, credentials: "omit" as const, })); const fetcher = vi.fn(); const executor = createContractHttpExecutor({ baseUrl: "https://api.example/", maxRetryAttempts: 0, attachCredentials, fetcher, }); const intent = intentFactory(); await expect( executor.execute( createInstalled, { name: "created" }, { scope, ...(intent === undefined ? {} : { intent }) }, ), ).resolves.toMatchObject({ kind: "CONTRACT_VIOLATION", violation: { kind: "MISSING_IDEMPOTENCY_KEY", operation: "REQUEST", }, effect: "NOT_STARTED", }); expect(attachCredentials).not.toHaveBeenCalled(); expect(fetcher).not.toHaveBeenCalled(); }, ); it.each([ ["an intent without a key", mutationIntent({ idempotencyKey: null })], ["an intent with a key", mutationIntent()], ])( "rejects a query carrying %s before credentials or fetch", async (_label, intent) => { const attachCredentials = vi.fn(() => ({ kind: "READY" as const, headers: {}, credentials: "omit" as const, })); const fetcher = vi.fn(); const executor = createContractHttpExecutor({ baseUrl: "https://api.example/", maxRetryAttempts: 0, attachCredentials, fetcher, }); await expect( executor.execute(installed, { limit: 20 }, { scope, intent }), ).resolves.toMatchObject({ kind: "CONTRACT_VIOLATION", violation: { kind: "UNEXPECTED_IDEMPOTENCY_KEY", operation: "REQUEST", }, effect: "NOT_STARTED", }); expect(attachCredentials).not.toHaveBeenCalled(); expect(fetcher).not.toHaveBeenCalled(); }, ); it.each([ { label: "query with the canonical reserved header", operation: installed, input: { limit: 20 }, context: { scope }, headerName: "Idempotency-Key", }, { label: "valid KEYED command with a case-variant reserved header", operation: createInstalled, input: { name: "created" }, context: { scope, intent: mutationIntent() }, headerName: "iDeMpOtEnCy-KeY", }, ])( "rejects a credential patch for $label before fetch", async ({ operation, input, context, headerName }) => { const attachCredentials = vi.fn(() => ({ kind: "READY" as const, headers: { [headerName]: "credential-owned-key" }, credentials: "omit" as const, })); const fetcher = vi.fn(); const executor = createContractHttpExecutor({ baseUrl: "https://api.example/", maxRetryAttempts: 0, attachCredentials, fetcher, }); await expect( executor.execute(operation, input, context), ).resolves.toMatchObject({ kind: "CONTRACT_VIOLATION", violation: { kind: "UNEXPECTED_IDEMPOTENCY_KEY", operation: "REQUEST", }, effect: "NOT_STARTED", }); expect(attachCredentials).toHaveBeenCalledOnce(); expect(fetcher).not.toHaveBeenCalled(); }, ); it("reuses one supplied idempotency key across every physical retry", async () => { const observedKeys: Array = []; let attempt = 0; const fetcher = vi.fn((_input: RequestInfo | URL, init?: RequestInit) => { observedKeys.push(new Headers(init?.headers).get("Idempotency-Key")); attempt += 1; if (attempt === 1) throw new TypeError("synchronous pre-dispatch failure"); return Promise.resolve( Response.json( { id: "created", name: "Created" }, { status: 201 }, ), ); }); const executor = createContractHttpExecutor({ baseUrl: "https://api.example/", maxRetryAttempts: 1, attachCredentials: () => ({ kind: "READY", headers: {}, credentials: "omit", }), fetcher, sleep: async () => {}, random: () => 0, }); const retryingCreate = { ...createInstalled, frontend: { ...createInstalled.frontend, retryBudget: 1 as const, }, }; await expect( executor.execute( retryingCreate, { name: "created" }, { scope, intent: mutationIntent({ idempotencyKey: "logical-key" }) }, ), ).resolves.toMatchObject({ kind: "SUCCESS" }); expect(fetcher).toHaveBeenCalledTimes(2); expect(observedKeys).toEqual(["logical-key", "logical-key"]); }); it("never emits a mutation idempotency header for a query", async () => { const observedKeys: Array = []; const fetcher = vi.fn( async (_input: RequestInfo | URL, init?: RequestInit) => { observedKeys.push( new Headers(init?.headers).get("Idempotency-Key"), ); return Response.json([]); }, ); const executor = createContractHttpExecutor({ baseUrl: "https://api.example/", maxRetryAttempts: 0, attachCredentials: () => ({ kind: "READY", headers: {}, credentials: "omit", }), fetcher, }); await expect( executor.execute( installed, { limit: 20 }, { scope }, ), ).resolves.toMatchObject({ kind: "SUCCESS" }); expect(fetcher).toHaveBeenCalledOnce(); expect(observedKeys).toEqual([null]); }); it("keeps intent identities out of request URLs and safe observations", async () => { const urls: string[] = []; const observations: unknown[] = []; const executor = createContractHttpExecutor({ baseUrl: "https://api.example/", maxRetryAttempts: 0, attachCredentials: () => ({ kind: "READY", headers: {}, credentials: "omit", }), fetcher: vi.fn(async (input) => { urls.push(String(input)); return Response.json( { id: "created", name: "Created" }, { status: 201 }, ); }), observe: (observation) => observations.push(observation), }); await expect( executor.execute( createInstalled, { name: "created" }, { scope, intent: Object.freeze({ intentId: "private-intent-id", operationId: "TEST_CREATE_ENTITY", canonicalInputIdentity: "private-canonical-input", idempotencyKey: "private-idempotency-key", createdAtMonotonicMs: 1, }), }, ), ).resolves.toMatchObject({ kind: "SUCCESS" }); const safeEvidence = JSON.stringify({ urls, observations }); expect(urls).toEqual(["https://api.example/api/test-entities"]); expect(observations).toHaveLength(1); expect(safeEvidence).not.toContain("private-intent-id"); expect(safeEvidence).not.toContain("private-canonical-input"); expect(safeEvidence).not.toContain("private-idempotency-key"); }); it.each([ [{}, "limit=20"], [{ limit: "7" }, "limit=7"], ])("projects the canonical validated input %#", async (input, expectedQuery) => { const fetcher = vi.fn(async () => Response.json([])); const executor = createContractHttpExecutor({ baseUrl: "https://api.example/", maxRetryAttempts: 0, attachCredentials: () => ({ kind: "READY", headers: {}, credentials: "omit", }), fetcher, }); await expect(executor.execute(installed, input, { scope })).resolves.toMatchObject({ kind: "SUCCESS", }); expect(String((fetcher.mock.calls as unknown[][])[0]?.[0])).toContain( expectedQuery, ); }); it("contains throwing and malformed external request projections", async () => { const executor = createContractHttpExecutor({ baseUrl: "https://api.example/", maxRetryAttempts: 0, attachCredentials: () => ({ kind: "READY", headers: {}, credentials: "omit", }), fetcher: vi.fn(), }); const throwing = { ...installed, contract: { ...installed.contract, projectRequest: () => { throw new Error("external descriptor defect"); }, }, }; const malformed = { ...installed, contract: { ...installed.contract, projectRequest: () => ({ pathValues: {}, queryEntries: [["limit"]], body: null }), }, } as unknown as typeof installed; await expect(executor.execute(throwing, { limit: 20 }, { scope })).resolves.toMatchObject({ kind: "CONTRACT_VIOLATION", effect: "NOT_APPLICABLE", }); await expect(executor.execute(malformed, { limit: 20 }, { scope })).resolves.toMatchObject({ kind: "CONTRACT_VIOLATION", effect: "NOT_APPLICABLE", }); }); it("preserves MAYBE_APPLIED for a malformed command response after dispatch", async () => { const executor = createContractHttpExecutor({ baseUrl: "https://api.example/", maxRetryAttempts: 0, attachCredentials: () => ({ kind: "READY", headers: {}, credentials: "omit", }), fetcher: vi.fn(async () => Response.json({ malformed: true }, { status: 201 })), }); await expect( executor.execute( createInstalled, { name: "created" }, { scope, intent: mutationIntent(), }, ), ).resolves.toMatchObject({ kind: "CONTRACT_VIOLATION", violation: { kind: "SUCCESS_SCHEMA_INVALID" }, effect: "MAYBE_APPLIED", }); }); it("preserves MAYBE_APPLIED when a command response arrives after its scope fence", async () => { let current = true; const lifetime = new AbortController(); const fencedScope = Object.freeze({ ...scope, signal: lifetime.signal, isCurrent: () => current, }); const executor = createContractHttpExecutor({ baseUrl: "https://api.example/", maxRetryAttempts: 0, attachCredentials: () => ({ kind: "READY", headers: {}, credentials: "omit", }), fetcher: vi.fn(async () => { current = false; lifetime.abort(); return Response.json( { id: "created", name: "Created" }, { status: 201 }, ); }), }); await expect( executor.execute( createInstalled, { name: "created" }, { scope: fencedScope, intent: mutationIntent({ intentId: "intent-2", idempotencyKey: "key-2" }), }, ), ).resolves.toMatchObject({ kind: "CONTRACT_VIOLATION", violation: { kind: "SCOPE_FENCED" }, effect: "MAYBE_APPLIED", }); }); it("settles a credential hang at the total operation deadline", async () => { vi.useFakeTimers(); let settled = false; const executor = createContractHttpExecutor({ baseUrl: "https://api.example/", maxRetryAttempts: 0, attachCredentials: () => new Promise(() => {}), }); const result = executor .execute(operation({ deadlineMs: 5 }), { limit: 20 }, { scope }) .then((outcome) => { settled = true; return outcome; }); await vi.advanceTimersByTimeAsync(5); await flushMicrotasks(); expect(settled).toBe(true); await expect(result).resolves.toMatchObject({ kind: "TRANSPORT_FAILURE", failure: { kind: "TIMEOUT" }, }); vi.useRealTimers(); }); it("cancels a non-cooperative retry sleep when the caller aborts", async () => { const caller = new AbortController(); let sleepSignal: AbortSignal | undefined; let settled = false; const executor = createContractHttpExecutor({ baseUrl: "https://api.example/", maxRetryAttempts: 2, attachCredentials: () => ({ kind: "READY", headers: {}, credentials: "omit", }), fetcher: vi.fn(async () => Response.json( { type: "about:blank", title: "temporary", status: 503 }, { status: 503 }, ), ), sleep: (_ms, signal) => { sleepSignal = signal; return new Promise(() => {}); }, random: () => 0, }); const result = executor .execute(installed, { limit: 20 }, { scope, signal: caller.signal }) .then((outcome) => { settled = true; return outcome; }); await vi.waitFor(() => expect(sleepSignal).toBeDefined()); caller.abort(); await flushMicrotasks(); expect(sleepSignal?.aborted).toBe(true); expect(settled).toBe(true); await expect(result).resolves.toMatchObject({ kind: "CANCELLED" }); }); it("treats an unreadable forbidden-body probe as a transport failure", async () => { const body = new ReadableStream({ pull(controller) { controller.error(new TypeError("stream failed")); }, }); const executor = createContractHttpExecutor({ baseUrl: "https://api.example/", maxRetryAttempts: 0, attachCredentials: () => ({ kind: "READY", headers: {}, credentials: "omit", }), fetcher: vi.fn(async () => new Response(body, { status: 200 })), }); await expect( executor.execute( operation({ responseBody: "NONE" }), { limit: 20 }, { scope }, ), ).resolves.toMatchObject({ kind: "TRANSPORT_FAILURE", failure: { kind: "RESPONSE_STREAM_FAILURE" }, }); }); });