Files
next-tjwater-agent/tests/sessions/metadataStore.test.ts
T

161 lines
4.8 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it } from "bun:test";
import { mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import {
SessionContextMismatchError,
SessionMetadataStore,
} from "../../src/sessions/metadataStore.js";
describe("SessionMetadataStore", () => {
let tempDir: string;
let store: SessionMetadataStore;
beforeEach(async () => {
tempDir = await mkdtemp(join(tmpdir(), "tjwater-session-"));
store = new SessionMetadataStore(tempDir);
await store.initialize();
});
it("does not return or ensure a session owned by another context", async () => {
await store.ensure({
actorKey: "actor-1",
projectId: "project-1",
projectKey: "project-key-1",
sessionId: "shared-id",
userId: "user-1",
});
expect(
await store.get(
{
actorKey: "actor-2",
projectId: "project-2",
projectKey: "project-key-2",
userId: "user-2",
},
"shared-id",
),
).toBeNull();
expect(
store.ensure({
actorKey: "actor-2",
projectId: "project-2",
projectKey: "project-key-2",
sessionId: "shared-id",
userId: "user-2",
}),
).rejects.toBeInstanceOf(SessionContextMismatchError);
});
afterEach(async () => {
await rm(tempDir, { force: true, recursive: true });
});
it("persists the provided opencode session id", async () => {
const { record, created } = await store.ensure({
actorKey: "actor-1",
projectId: "project-1",
projectKey: "project-key-1",
sessionId: "opencode-session-1",
userId: "user-1",
});
expect(created).toBe(true);
expect(record.sessionId).toBe("opencode-session-1");
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?.title).toBe("新标题");
});
it("finds a triggered session only inside the owning context", async () => {
const context = {
actorKey: "actor-trigger",
projectId: "project-trigger",
projectKey: "project-key-trigger",
userId: "user-trigger",
};
const { record } = await store.ensure({
...context,
sessionId: "triggered-session",
trigger: {
triggerId: "peripheral.work_order.created:project:order:1",
source: "peripheral_sample",
subjectType: "work_order",
subjectId: "50000000-0000-4000-8000-000000000001",
workflow: "water_quality_complaint",
occurredAt: "2026-09-22T10:00:00+08:00",
},
});
expect(
await store.findByTrigger(
context,
"peripheral.work_order.created:project:order:1",
),
).toEqual(record);
expect(
await store.findByTrigger(
{ ...context, actorKey: "other-actor", userId: "other-user" },
"peripheral.work_order.created:project:order:1",
),
).toBeNull();
});
it("keeps ordinary chat, task execution, and task collaboration distinct", async () => {
const context = {
actorKey: "actor-purpose",
projectId: "project-purpose",
projectKey: "project-key-purpose",
userId: "user-purpose",
};
await store.ensure({ ...context, sessionId: "ordinary" });
await store.ensure({
...context,
sessionId: "execution",
purpose: "task_execution",
taskId: "50000000-0000-4000-8000-000000000001",
requestId: "60000000-0000-4000-8000-000000000001",
});
await store.ensure({
...context,
sessionId: "collaboration",
purpose: "task_collaboration",
taskId: "50000000-0000-4000-8000-000000000001",
});
expect((await store.list(context, { purpose: "ordinary_chat" })).map((item) => item.sessionId)).toEqual(["ordinary"]);
expect((await store.list(context, { purpose: "task_execution" })).map((item) => item.sessionId)).toEqual(["execution"]);
expect((await store.findByTask(context, "50000000-0000-4000-8000-000000000001", "task_collaboration"))?.sessionId).toBe("collaboration");
expect((await store.findByRequest(context, "60000000-0000-4000-8000-000000000001"))?.sessionId).toBe("execution");
});
});