@convex-dev/agent
Version:
A agent component for Convex.
131 lines (126 loc) • 4.08 kB
text/typescript
/// <reference types="vite/client" />
import { convexTest } from "convex-test";
import { describe, expect, test } from "vitest";
import { api } from "./_generated/api.js";
import schema from "./schema.js";
import { modules } from "./setup.test.js";
import type { Doc } from "./_generated/dataModel.js";
import type { PaginationResult } from "convex/server";
describe("files", () => {
test("addFile increments refcount and does not create a new entry", async () => {
const t = convexTest(schema, modules);
const storageId = "storage-1";
const hash = "hash-1";
const filename = "file.txt";
// Add the file for the first time
const { fileId, storageId: returnedStorageId } = await t.mutation(
api.files.addFile,
{
storageId,
hash,
filename,
mimeType: "text/plain",
},
);
expect(fileId).toBeTruthy();
expect(returnedStorageId).toBe(storageId);
// Add the same file again
const { fileId: fileId2 } = await t.mutation(api.files.addFile, {
storageId,
hash,
filename,
mimeType: "text/plain",
});
expect(fileId2).toBe(fileId);
// Add the same file with a different filename (should create a new entry)
const { fileId: fileId3 } = await t.mutation(api.files.addFile, {
storageId,
hash,
filename: "other.txt",
mimeType: "text/plain",
});
expect(fileId3).not.toBe(fileId);
// Add the same file with undefined filename (should create a new entry)
const { fileId: fileId4 } = await t.mutation(api.files.addFile, {
storageId,
hash,
filename: undefined,
mimeType: "text/plain",
});
expect(fileId4).not.toBe(fileId);
});
test("useExistingFile only matches files with the same hash and filename", async () => {
const t = convexTest(schema, modules);
const storageId = "storage-2";
const hash = "hash-2";
const filename = "file2.txt";
// Add a file
const { fileId } = await t.mutation(api.files.addFile, {
storageId,
hash,
filename,
mimeType: "text/plain",
});
// Should match
const fileId2 = await t.mutation(api.files.useExistingFile, {
hash,
filename,
});
expect(fileId2?.fileId).toBe(fileId);
// Should not match with different filename
const fileId3 = await t.mutation(api.files.useExistingFile, {
hash,
filename: "other2.txt",
});
expect(fileId3).toBeNull();
// Should not match with undefined filename
const fileId4 = await t.mutation(api.files.useExistingFile, {
hash,
});
expect(fileId4).toBeNull();
});
test("getFilesToDelete paginates through files with refcount 0 one at a time", async () => {
const t = convexTest(schema, modules);
// Add 3 files with refcount 0
const files = [];
for (let i = 0; i < 3; i++) {
const { fileId } = await t.mutation(api.files.addFile, {
storageId: `storage-del-${i}`,
hash: `hash-del-${i}`,
filename: `file-del-${i}.txt`,
mimeType: "text/plain",
});
// Manually set refcount to 0
await t.run(async (ctx) => {
await ctx.db.patch(fileId, { refcount: 0 });
});
files.push(fileId);
}
// Paginate through files to delete one at a time
let cursor: string | null = null;
const seen: string[] = [];
for (let i = 0; i < 3; i++) {
const { page, continueCursor, isDone }: PaginationResult<Doc<"files">> =
await t.query(api.files.getFilesToDelete, {
paginationOpts: {
numItems: 1,
cursor,
},
});
expect(page.length).toBe(1);
seen.push(page[0]._id);
cursor = continueCursor;
expect(isDone).toBe(false);
}
const { page, isDone } = await t.query(api.files.getFilesToDelete, {
paginationOpts: {
numItems: 1,
cursor,
},
});
expect(page.length).toBe(0);
expect(isDone).toBe(true);
// All fileIds should be seen
expect(seen.sort()).toEqual(files.sort());
});
});