import { describe, it, afterEach } from "node:test"; import assert from "node:assert"; import { createFile, listFiles, deleteFile, getFile } from "@/lib/localDb"; describe("Files API - Integration Tests", () => { afterEach(() => { const allFiles = listFiles({ limit: 1000 }); for (const f of allFiles) { if (f.filename?.includes("test-")) { deleteFile(f.id); } } }); describe("POST /v1/files - File creation with auto-expiration", () => { it("should create batch file with 30-day expiration", () => { const now = Math.floor(Date.now() / 1000); const thirtyDaysInSeconds = 30 * 24 * 60 * 60; const file = createFile({ bytes: 100, filename: "test-api-batch.jsonl", purpose: "batch", content: Buffer.from("test batch content"), mimeType: "application/jsonl", }); assert(file.expiresAt !== null); const expectedMin = now + thirtyDaysInSeconds - 5; // 5 second tolerance const expectedMax = now + thirtyDaysInSeconds + 5; assert(file.expiresAt >= expectedMin && file.expiresAt <= expectedMax); }); it("should create non-batch file without auto-expiration", () => { const file = createFile({ bytes: 100, filename: "test-api-fine-tune.jsonl", purpose: "fine-tune", content: Buffer.from("test ft content"), mimeType: "application/jsonl", }); assert(file.expiresAt === null || file.expiresAt === undefined); }); it("should respect custom expires_after parameter", () => { const now = Math.floor(Date.now() / 1000); const sevenDaysInSeconds = 7 * 24 * 60 * 60; const customExpiry = now + sevenDaysInSeconds; const file = createFile({ bytes: 100, filename: "test-api-custom.jsonl", purpose: "assistants", content: Buffer.from("test custom"), mimeType: "application/jsonl", expiresAt: customExpiry, }); assert(file.expiresAt === customExpiry); }); }); describe("GET /v1/files - List files with expiration info", () => { it("should include expires_at in file list response", () => { const batchFile = createFile({ bytes: 100, filename: "test-list-batch.jsonl", purpose: "batch", content: Buffer.from("batch content"), mimeType: "application/jsonl", }); const files = listFiles({ limit: 10 }); const foundFile = files.find((f) => f.id === batchFile.id); assert(foundFile !== undefined); assert("expiresAt" in foundFile); assert(foundFile.expiresAt === batchFile.expiresAt); }); it("should show null expires_at for persistent files", () => { const persistedFile = createFile({ bytes: 100, filename: "test-list-persisted.txt", purpose: "assistants", content: Buffer.from("persisted"), mimeType: "text/plain", }); const files = listFiles({ limit: 10 }); const foundFile = files.find((f) => f.id === persistedFile.id); assert(foundFile !== undefined); assert(foundFile.expiresAt === null || foundFile.expiresAt === undefined); }); it("should list multiple files with different expiration policies", () => { const batchFile = createFile({ bytes: 100, filename: "test-multi-batch.jsonl", purpose: "batch", content: Buffer.from("batch"), mimeType: "application/jsonl", }); const persistedFile = createFile({ bytes: 100, filename: "test-multi-persisted.txt", purpose: "fine-tune", content: Buffer.from("persisted"), mimeType: "text/plain", }); const files = listFiles({ limit: 20 }); const batch = files.find((f) => f.id === batchFile.id); const persisted = files.find((f) => f.id === persistedFile.id); assert(batch !== undefined && batch.expiresAt !== null); assert( persisted !== undefined && (persisted.expiresAt === null || persisted.expiresAt === undefined) ); }); it("should filter by purpose while preserving expiration info", () => { createFile({ bytes: 100, filename: "test-filter-batch.jsonl", purpose: "batch", content: Buffer.from("batch"), mimeType: "application/jsonl", }); createFile({ bytes: 100, filename: "test-filter-ft.jsonl", purpose: "fine-tune", content: Buffer.from("ft"), mimeType: "application/jsonl", }); const batchFiles = listFiles({ purpose: "batch", limit: 10 }); assert(batchFiles.every((f) => f.purpose === "batch")); assert(batchFiles.every((f) => f.expiresAt !== null || true)); }); }); describe("DELETE /v1/files/{file_id} - File deletion", () => { it("should soft-delete file by setting deleted_at", () => { const file = createFile({ bytes: 100, filename: "test-delete.txt", purpose: "assistants", content: Buffer.from("deletable"), mimeType: "text/plain", }); const beforeDelete = getFile(file.id); assert(beforeDelete !== null); assert(beforeDelete.deletedAt === null || beforeDelete.deletedAt === undefined); deleteFile(file.id); const afterDelete = getFile(file.id); assert(afterDelete === null, "Deleted file should not be retrievable"); }); it("should remove deleted file from list", () => { const file = createFile({ bytes: 100, filename: "test-delete-list.txt", purpose: "assistants", content: Buffer.from("to delete"), mimeType: "text/plain", }); const beforeDelete = listFiles({ limit: 100 }).some((f) => f.id === file.id); assert(beforeDelete === true); deleteFile(file.id); const afterDelete = listFiles({ limit: 100 }).some((f) => f.id === file.id); assert(afterDelete === false); }); it("should handle deletion of non-existent file", () => { const result = deleteFile("file-nonexistent-xyz"); // Should not throw, just return false assert(typeof result === "boolean"); }); }); describe("File expiration data persistence", () => { it("should preserve expires_at when retrieving file", () => { const file = createFile({ bytes: 100, filename: "test-persist-expiry.jsonl", purpose: "batch", content: Buffer.from("test"), mimeType: "application/jsonl", }); const retrieved = getFile(file.id); assert(retrieved !== null); assert(retrieved.expiresAt === file.expiresAt); }); it("should maintain expiration data across list operations", () => { const file = createFile({ bytes: 100, filename: "test-expiry-list-persist.jsonl", purpose: "batch", content: Buffer.from("test"), mimeType: "application/jsonl", }); const originalExpiresAt = file.expiresAt; // Fetch from list const files = listFiles({ limit: 10 }); const listedFile = files.find((f) => f.id === file.id); assert(listedFile !== undefined); assert(listedFile.expiresAt === originalExpiresAt); }); }); });