99 lines
3.0 KiB
TypeScript
99 lines
3.0 KiB
TypeScript
import { describe, expect, it, vi } from "vitest";
|
|
|
|
import {
|
|
createEventSyncController,
|
|
type EventSyncDependencies,
|
|
} from "../../apps/web/src/event-sync.js";
|
|
import { isSseEvent } from "../../packages/shared-contracts/src/index.js";
|
|
|
|
function dependencies() {
|
|
return {
|
|
bootstrap: vi.fn(async () => undefined),
|
|
refetchEntity: vi.fn(async () => undefined),
|
|
refetchModels: vi.fn(async () => undefined),
|
|
} satisfies EventSyncDependencies;
|
|
}
|
|
|
|
describe("TDD-WP0-EVT-001 REST refetch", () => {
|
|
it("accepts only fixed non-sensitive event fields and separated versions", () => {
|
|
expect(
|
|
isSseEvent({
|
|
config_set_version: 7,
|
|
entity_ref: "models:current",
|
|
event_id: 1,
|
|
event_type: "model_config_changed",
|
|
occurred_at: "2026-07-27T09:00:00.000Z",
|
|
}),
|
|
).toBe(true);
|
|
expect(
|
|
isSseEvent({
|
|
entity_ref: "models:runtime",
|
|
event_id: 2,
|
|
event_type: "model_runtime_changed",
|
|
occurred_at: "2026-07-27T09:00:01.000Z",
|
|
runtime_availability_version: 12,
|
|
}),
|
|
).toBe(true);
|
|
expect(
|
|
isSseEvent({
|
|
config_set_version: 7,
|
|
entity_ref: "models:current",
|
|
event_id: 3,
|
|
event_type: "model_changed",
|
|
occurred_at: "2026-07-27T09:00:02.000Z",
|
|
prompt: "private body",
|
|
runtime_availability_version: 12,
|
|
}),
|
|
).toBe(false);
|
|
});
|
|
|
|
it("uses REST for every event and bootstraps once after a sequence gap", async () => {
|
|
const calls = dependencies();
|
|
const controller = createEventSyncController(calls);
|
|
|
|
await controller.handleEvent({
|
|
entity_ref: "projects:project-1",
|
|
event_id: 10,
|
|
event_type: "project_state_changed",
|
|
occurred_at: "2026-07-27T09:00:00.000Z",
|
|
state_version: 4,
|
|
});
|
|
await controller.handleEvent({
|
|
config_set_version: 8,
|
|
entity_ref: "models:current",
|
|
event_id: 12,
|
|
event_type: "model_config_changed",
|
|
occurred_at: "2026-07-27T09:00:01.000Z",
|
|
});
|
|
|
|
expect(calls.refetchEntity).toHaveBeenCalledWith("projects:project-1");
|
|
expect(calls.bootstrap).toHaveBeenCalledTimes(1);
|
|
expect(calls.refetchModels).toHaveBeenCalledWith({
|
|
configSetVersion: 8,
|
|
reason: "config",
|
|
});
|
|
});
|
|
|
|
it("bootstraps once per disconnect incident and never applies event payload as truth", async () => {
|
|
const calls = dependencies();
|
|
const controller = createEventSyncController(calls);
|
|
|
|
await controller.handleDisconnect();
|
|
await controller.handleDisconnect();
|
|
expect(calls.bootstrap).toHaveBeenCalledTimes(1);
|
|
|
|
await controller.handleEvent({
|
|
entity_ref: "storage:local",
|
|
event_id: 21,
|
|
event_type: "storage_state_changed",
|
|
occurred_at: "2026-07-27T09:00:02.000Z",
|
|
state_version: 9,
|
|
});
|
|
await controller.handleDisconnect();
|
|
|
|
expect(calls.bootstrap).toHaveBeenCalledTimes(2);
|
|
expect(calls.refetchEntity).toHaveBeenCalledWith("storage:local");
|
|
expect(calls.refetchEntity).not.toHaveBeenCalledWith(expect.objectContaining({ state_version: 9 }));
|
|
});
|
|
});
|