Files
pikasTech-HWLAB/internal/cloud/workbench-kafka-rail-stream.test.ts
T

101 lines
4.0 KiB
TypeScript

import { expect, test } from "bun:test";
import { createWorkbenchKafkaRailProjectionStream } from "./workbench-kafka-rail-stream.ts";
test("rail stream emits scoped snapshots and only semantic live deltas", async () => {
const summaries = new Map([
["ses_rail_a", railSummary("ses_rail_a", "1", "running")],
["ses_rail_b", railSummary("ses_rail_b", "2", "completed")]
]);
const subscribers = new Set<(envelope: unknown) => void>();
const delivered: any[] = [];
const bridge = {
async waitWorkbenchSessionRailReady() { return { ready: true }; },
workbenchSessionSummaries({ sessionIds = [] } = {}) {
return { ok: true, sessions: sessionIds.map((sessionId: string) => summaries.get(sessionId)) };
},
subscribeLiveHwlabEvents(listener: (envelope: unknown) => void) {
subscribers.add(listener);
return () => subscribers.delete(listener);
}
};
const stream = createWorkbenchKafkaRailProjectionStream({
bridge,
sessionIds: ["ses_rail_b", "ses_rail_a"],
deliver(payload: unknown) { delivered.push(payload); return true; }
});
await stream.start();
expect(delivered.map((item) => [item.phase, item.sessionId, item.session.status])).toEqual([
["snapshot", "ses_rail_a", "running"],
["snapshot", "ses_rail_b", "completed"]
]);
for (const listener of subscribers) listener({ schema: "hwlab.event.v1", sessionId: "ses_rail_a", event: { type: "assistant" } });
await Promise.resolve();
expect(delivered).toHaveLength(2);
summaries.set("ses_rail_a", railSummary("ses_rail_a", "4", "completed"));
for (const listener of subscribers) listener({ schema: "hwlab.event.v1", sessionId: "ses_rail_a", event: { type: "result", terminal: true } });
await Promise.resolve();
await Promise.resolve();
expect(delivered.map((item) => [item.phase, item.sessionId, item.session.status])).toEqual([
["snapshot", "ses_rail_a", "running"],
["snapshot", "ses_rail_b", "completed"],
["live", "ses_rail_a", "completed"]
]);
expect(stream.status()).toMatchObject({ live: true, snapshotCount: 2, liveCount: 1 });
stream.stop();
expect(subscribers.size).toBe(0);
});
test("rail stream waits for the first user-derived summary without failing the active session", async () => {
const sessionId = "ses_new_without_user";
const summaries = new Map<string, ReturnType<typeof railSummary>>();
const subscribers = new Set<(envelope: unknown) => void>();
const delivered: any[] = [];
const failures: unknown[] = [];
const bridge = {
async waitWorkbenchSessionRailReady() { return { ready: true }; },
workbenchSessionSummaries({ sessionIds = [] } = {}) {
return { ok: true, sessions: sessionIds.map((id: string) => summaries.get(id)).filter(Boolean) };
},
subscribeLiveHwlabEvents(listener: (envelope: unknown) => void) {
subscribers.add(listener);
return () => subscribers.delete(listener);
}
};
const stream = createWorkbenchKafkaRailProjectionStream({
bridge,
sessionIds: [sessionId],
deliver(payload: unknown) { delivered.push(payload); return true; },
onFailure(error: unknown) { failures.push(error); }
});
await stream.start();
expect(delivered).toEqual([]);
expect(failures).toEqual([]);
summaries.set(sessionId, railSummary(sessionId, "7", "running"));
for (const listener of subscribers) listener({ schema: "hwlab.event.v1", sessionId, event: { type: "user" } });
await Promise.resolve();
await Promise.resolve();
expect(delivered).toHaveLength(1);
expect(delivered[0]).toMatchObject({ phase: "live", sessionId, session: { firstUserMessagePreview: `title ${sessionId}` } });
expect(failures).toEqual([]);
stream.stop();
});
function railSummary(sessionId: string, offset: string, status: string) {
return {
sessionId,
firstUserMessagePreview: `title ${sessionId}`,
lastUserMessageAt: "2026-07-22T08:00:00.000Z",
lastTraceId: `trc_${sessionId}`,
status,
revision: { topic: "hwlab.event.v1", partition: 0, offset, valuesRedacted: true },
valuesRedacted: true
};
}