import { describe, expect, it, vi } from "vitest"; import { dispatchBackgroundJob, historyCompactJob, historyCompactJobKey, messagingDeliverJob, parseBackgroundJob, profileConsolidateJob, profileConsolidateJobKey, } from "./background-jobs.js"; import type { BackgroundJobHandlers } from "./types.js"; function handlers(): BackgroundJobHandlers { return { "run.continue": vi.fn(async () => undefined), "routine.wakeup": vi.fn(async () => undefined), "computer.update": vi.fn(async () => undefined), "computer.sleep": vi.fn(async () => undefined), "computer.control-expire": vi.fn(async () => undefined), "skill.teaching-expire": vi.fn(async () => undefined), "history.compact": vi.fn(async () => undefined), "messaging.deliver": vi.fn(async () => undefined), "cloud_agent.poll": vi.fn(async () => undefined), "profile.consolidate": vi.fn(async () => undefined), }; } describe("background job contracts", () => { it("validates and dispatches messaging.deliver", async () => { const target = handlers(); await dispatchBackgroundJob(target, "messaging.deliver", { runId: "run-1" }); expect(target["messaging.deliver"]).toHaveBeenCalledWith({ runId: "run-1" }); expect(messagingDeliverJob("run-1")).toEqual({ name: "messaging.deliver", payload: { runId: "run-1" }, replaceKey: "messaging.deliver:run-1", }); expect(messagingDeliverJob()).toEqual({ name: "messaging.deliver", payload: {}, replaceKey: "messaging.deliver:drain", }); }); it("validates and dispatches a typed job", async () => { const target = handlers(); await dispatchBackgroundJob(target, "routine.wakeup", { routineId: "routine-1", scheduledFor: "2026-08-15T12:00:00.000Z", }); expect(target["routine.wakeup"]).toHaveBeenCalledWith({ routineId: "routine-1", scheduledFor: "2026-08-15T12:00:00.000Z", }); }); it("rejects unknown names and malformed deliveries", () => { expect(() => parseBackgroundJob("unknown", {})).toThrow("Unknown background job"); expect(() => parseBackgroundJob("routine.wakeup", { routineId: "routine-1", scheduledFor: "not-a-date", }), ).toThrow(); expect(() => parseBackgroundJob("run.continue", { runId: "" })).toThrow(); expect(() => parseBackgroundJob("computer.control-expire", { computerId: "computer-1", leaseId: "", }), ).toThrow(); }); it("validates and dispatches a control-expiry job", async () => { const target = handlers(); await dispatchBackgroundJob(target, "computer.control-expire", { computerId: "computer-1", leaseId: "lease-1", }); expect(target["computer.control-expire"]).toHaveBeenCalledWith({ computerId: "computer-1", leaseId: "lease-1", }); }); }); describe("historyCompactJob", () => { it("builds a job with a replace key scoped to the thread", () => { expect(historyCompactJob("thread-1")).toEqual({ name: "history.compact", payload: { threadId: "thread-1" }, replaceKey: historyCompactJobKey("thread-1"), }); }); it("keys different threads differently", () => { expect(historyCompactJobKey("thread-1")).not.toBe(historyCompactJobKey("thread-2")); }); }); describe("profileConsolidateJob", () => { it("validates, dispatches, and keys one pending consolidation per user", async () => { const target = handlers(); await dispatchBackgroundJob(target, "profile.consolidate", { userId: "user-1" }); expect(target["profile.consolidate"]).toHaveBeenCalledWith({ userId: "user-1" }); expect(() => parseBackgroundJob("profile.consolidate", { userId: "" })).toThrow(); expect(profileConsolidateJob("user-1")).toEqual({ name: "profile.consolidate", payload: { userId: "user-1" }, replaceKey: profileConsolidateJobKey("user-1"), }); expect(profileConsolidateJobKey("user-1")).not.toBe(profileConsolidateJobKey("user-2")); }); });