import { afterEach, beforeEach, describe, expect, it } from "bun:test"; import { ConversationStore } from "../../src/conversations/store.js"; import { createTestDatabase } from "../helpers/postgres.js"; describe("ConversationStore", () => { let store: ConversationStore; let dispose: (() => Promise) | undefined; beforeEach(async () => { const testDb = await createTestDatabase(); store = new ConversationStore(testDb.db); dispose = testDb.dispose; await store.initialize(); }); afterEach(async () => { await dispose?.(); }); it("issues backend-managed session ids when absent", async () => { const { record, created } = await store.ensure({ actorKey: "actor-1", projectId: "project-1", projectKey: "project-key-1", userId: "user-1", }); expect(created).toBe(true); expect(record.sessionId).toStartWith("chat-"); expect(record.ownerUserId).toBe("user-1"); expect(record.status).toBe("active"); }); it("touches metadata and preserves scoped ownership", async () => { const { record } = await store.ensure({ actorKey: "actor-2", projectId: "project-2", projectKey: "project-key-2", sessionId: "existing-session", userId: "user-2", }); const touched = await store.touch(record, { title: "新标题", }); expect(touched.title).toBe("新标题"); expect(touched.updatedAt >= record.updatedAt).toBe(true); const fetched = await store.get( { actorKey: "actor-2", projectId: "project-2", projectKey: "project-key-2", userId: "user-2", }, "existing-session", ); expect(fetched?.sessionId).toBe(record.sessionId); expect(fetched?.title).toBe("新标题"); }); it("tracks streaming state and clears it with runtime-session guarding", async () => { const { record } = await store.ensure({ actorKey: "actor-3", projectId: "project-3", projectKey: "project-key-3", sessionId: "streaming-session", userId: "user-3", }); const streaming = await store.markStreaming(record, "runtime-1"); expect(streaming.isStreaming).toBe(true); expect(streaming.streamingStartedAt).toBeDefined(); const skipped = await store.clearStreaming(record.sessionId, "runtime-2"); expect(skipped).toBeNull(); const stillStreaming = await store.get( { actorKey: "actor-3", projectId: "project-3", projectKey: "project-key-3", userId: "user-3", }, record.sessionId, ); expect(stillStreaming?.isStreaming).toBe(true); await store.clearStreaming(record.sessionId, "runtime-1"); const cleared = await store.get( { actorKey: "actor-3", projectId: "project-3", projectKey: "project-key-3", userId: "user-3", }, record.sessionId, ); expect(cleared?.isStreaming).toBe(false); expect(cleared?.streamingStartedAt).toBeUndefined(); }); });