import { expect, describe, it, beforeAll } from "vitest"; import { clickhouseClient, createOrgProjectAndApiKey, createTraceScore, createScoresCh, getBlobStorageByProjectId, getScoresByIds, StorageService, StorageServiceFactory, } from "@langfuse/shared/src/server"; import { randomUUID } from "crypto"; import { env } from "../env"; import { processClickhouseScoreDelete } from "../features/scores/processClickhouseScoreDelete"; describe("score deletion", () => { let eventStorageService: StorageService; beforeAll(() => { eventStorageService = StorageServiceFactory.getInstance({ accessKeyId: env.LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID, secretAccessKey: env.LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY, bucketName: env.LANGFUSE_S3_EVENT_UPLOAD_BUCKET, endpoint: env.LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT, region: env.LANGFUSE_S3_EVENT_UPLOAD_REGION, forcePathStyle: env.LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE === "true", }); }); it("should delete all scores from Clickhouse", async () => { // Setup const { projectId } = await createOrgProjectAndApiKey(); const score = createTraceScore({ project_id: projectId }); await createScoresCh([score]); // When await processClickhouseScoreDelete(projectId, [score.id]); // Then const scores = await getScoresByIds(projectId, [score.id]); expect(scores).toHaveLength(0); }); it("should delete S3 event files for deleted scores", async () => { // Setup const { projectId } = await createOrgProjectAndApiKey(); const scoreId = randomUUID(); await createScoresCh([ createTraceScore({ id: scoreId, project_id: projectId }), ]); const fileType = "application/json"; const data = JSON.stringify({ hello: "world" }); await Promise.all([ eventStorageService.uploadFile({ fileName: `${projectId}/score/${scoreId}-score.json`, fileType, data, }), ]); await clickhouseClient().insert({ table: "blob_storage_file_log", format: "JSONEachRow", values: [ { id: randomUUID(), project_id: projectId, entity_type: "score", entity_id: scoreId, event_id: randomUUID(), bucket_name: env.LANGFUSE_S3_EVENT_UPLOAD_BUCKET, bucket_path: `${projectId}/score/${scoreId}-score.json`, created_at: new Date().getTime(), updated_at: new Date().getTime(), }, ], }); // When await processClickhouseScoreDelete(projectId, [scoreId]); // Then const eventLog = getBlobStorageByProjectId(projectId); for await (const _ of eventLog) { // Should never happen as the expect event log to be empty expect(true).toBe(false); } const files = await eventStorageService.listFiles(projectId); expect(files).toHaveLength(0); }); });