229 lines
7.1 KiB
TypeScript
229 lines
7.1 KiB
TypeScript
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);
|
|
});
|
|
});
|
|
});
|