105 lines
2.9 KiB
TypeScript
105 lines
2.9 KiB
TypeScript
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<void>) | 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();
|
|
});
|
|
});
|