import { beforeAll, beforeEach, describe, expect, it, afterAll } from "vitest"; import { randomUUID as uuid } from "crypto"; import { Test, TestingModule } from "@nestjs/testing"; import { NotFoundException } from "@nestjs/common"; import { PrismaClient } from "@prisma/client"; import { AgentMemoryService } from "./agent-memory.service"; import { PrismaService } from "../prisma/prisma.service"; const shouldRunDbIntegrationTests = process.env.RUN_DB_TESTS === "true" && Boolean(process.env.DATABASE_URL); const describeFn = shouldRunDbIntegrationTests ? describe : describe.skip; async function createWorkspace( prisma: PrismaClient, label: string ): Promise<{ workspaceId: string; ownerId: string }> { const workspace = await prisma.workspace.create({ data: { name: `${label} ${Date.now()}`, owner: { create: { email: `${label.toLowerCase().replace(/\s+/g, "-")}-${Date.now()}@example.com`, name: `${label} Owner`, }, }, }, }); return { workspaceId: workspace.id, ownerId: workspace.ownerId, }; } describeFn("AgentMemoryService Integration", () => { let moduleRef: TestingModule; let prisma: PrismaClient; let service: AgentMemoryService; let setupComplete = false; let workspaceAId: string; let workspaceAOwnerId: string; let workspaceBId: string; let workspaceBOwnerId: string; beforeAll(async () => { prisma = new PrismaClient(); await prisma.$connect(); const workspaceA = await createWorkspace(prisma, "Agent Memory Integration A"); workspaceAId = workspaceA.workspaceId; workspaceAOwnerId = workspaceA.ownerId; const workspaceB = await createWorkspace(prisma, "Agent Memory Integration B"); workspaceBId = workspaceB.workspaceId; workspaceBOwnerId = workspaceB.ownerId; moduleRef = await Test.createTestingModule({ providers: [ AgentMemoryService, { provide: PrismaService, useValue: prisma, }, ], }).compile(); service = moduleRef.get(AgentMemoryService); setupComplete = true; }); beforeEach(async () => { if (!setupComplete) { return; } await prisma.agentMemory.deleteMany({ where: { workspaceId: { in: [workspaceAId, workspaceBId], }, }, }); }); afterAll(async () => { if (!prisma) { return; } const workspaceIds = [workspaceAId, workspaceBId].filter( (id): id is string => typeof id === "string" ); const ownerIds = [workspaceAOwnerId, workspaceBOwnerId].filter( (id): id is string => typeof id === "string" ); if (workspaceIds.length > 0) { await prisma.agentMemory.deleteMany({ where: { workspaceId: { in: workspaceIds, }, }, }); await prisma.workspace.deleteMany({ where: { id: { in: workspaceIds } } }); } if (ownerIds.length > 0) { await prisma.user.deleteMany({ where: { id: { in: ownerIds } } }); } if (moduleRef) { await moduleRef.close(); } await prisma.$disconnect(); }); it("upserts and lists memory entries", async () => { if (!setupComplete) { return; } const agentId = `agent-${uuid()}`; const entry = await service.upsert(workspaceAId, agentId, "session-context", { value: { intent: "create-tests", depth: "integration" }, }); expect(entry.workspaceId).toBe(workspaceAId); expect(entry.agentId).toBe(agentId); expect(entry.key).toBe("session-context"); const listed = await service.findAll(workspaceAId, agentId); expect(listed).toHaveLength(1); expect(listed[0]?.id).toBe(entry.id); expect(listed[0]?.value).toMatchObject({ intent: "create-tests" }); }); it("updates existing key via upsert without creating duplicates", async () => { if (!setupComplete) { return; } const agentId = `agent-${uuid()}`; const first = await service.upsert(workspaceAId, agentId, "preferences", { value: { model: "fast" }, }); const second = await service.upsert(workspaceAId, agentId, "preferences", { value: { model: "accurate" }, }); expect(second.id).toBe(first.id); expect(second.value).toMatchObject({ model: "accurate" }); const rowCount = await prisma.agentMemory.count({ where: { workspaceId: workspaceAId, agentId, key: "preferences", }, }); expect(rowCount).toBe(1); }); it("lists keys in sorted order and isolates by workspace", async () => { if (!setupComplete) { return; } const agentId = `agent-${uuid()}`; await service.upsert(workspaceAId, agentId, "beta", { value: { v: 2 } }); await service.upsert(workspaceAId, agentId, "alpha", { value: { v: 1 } }); await service.upsert(workspaceBId, agentId, "alpha", { value: { v: 99 } }); const workspaceAEntries = await service.findAll(workspaceAId, agentId); const workspaceBEntries = await service.findAll(workspaceBId, agentId); expect(workspaceAEntries.map((row) => row.key)).toEqual(["alpha", "beta"]); expect(workspaceBEntries).toHaveLength(1); expect(workspaceBEntries[0]?.value).toMatchObject({ v: 99 }); }); it("throws NotFoundException when requesting unknown key", async () => { if (!setupComplete) { return; } await expect(service.findOne(workspaceAId, `agent-${uuid()}`, "missing")).rejects.toThrow( NotFoundException ); }); });