import { mkdtemp, readFile, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, describe, expect, it } from "vitest"; import { createPublicGenerationJob, PublicApiConflictError } from "@/lib/server/public-api-jobs"; const fixtureUrl = new URL("../contracts/jobs/jobs-v1.json", import.meta.url); let runtimeDir: string | undefined; afterEach(async () => { if (runtimeDir) await rm(runtimeDir, { recursive: true, force: true }); runtimeDir = undefined; }); describe("jobs v1 cross-language contract", () => { it("freezes statuses, bounds and retry behavior", async () => { const fixture = JSON.parse(await readFile(fixtureUrl, "utf8")); expect(fixture.version).toBe(1); expect(fixture.statuses).toEqual(["queued", "running", "succeeded", "failed", "expired", "cancelled"]); expect(fixture.terminalStatuses).toEqual(["succeeded", "failed", "expired", "cancelled"]); expect(fixture.priority).toEqual({ minimum: -100, maximum: 100, default: 0 }); expect(fixture.claim).toEqual({ minimumBatch: 1, maximumBatch: 20, defaultLockTimeoutSeconds: 300 }); }); it("uses stable request fingerprints and rejects payload drift", async () => { const fixture = JSON.parse(await readFile(fixtureUrl, "utf8")); runtimeDir = await mkdtemp(join(tmpdir(), "zhinian-jobs-contract-")); process.env.ZHINIAN_RUNTIME_DIR = runtimeDir; process.env.ZHINIAN_DATA_BACKEND = "local"; process.env.JIMENG_VISUAL_MOCK = "true"; const request = new Request("http://local.test/api/v1/jobs", { headers: { "Idempotency-Key": "header-key" }, }); const input = { client: { id: "fixture-client", key: "secret" }, request, origin: "http://local.test", body: fixture.idempotency.body, }; const created = await createPublicGenerationJob(input); expect(created.reused).toBe(false); expect(created.job.idempotencyKey).toBe("header-key"); expect(created.job.idempotencyFingerprint).toBe(fixture.idempotency.fingerprint); const replay = await createPublicGenerationJob(input); expect(replay.reused).toBe(true); expect(replay.job.id).toBe(created.job.id); await expect(createPublicGenerationJob({ ...input, body: { ...fixture.idempotency.body, prompt: "hello!" }, })).rejects.toBeInstanceOf(PublicApiConflictError); }); });