업로드 및 썸네일 등록의 경쟁 조건을 수정하고 캐시 무효화와 스트리밍 캐시의 메모리 사용량을 개선

This commit is contained in:
static committed 2026-10-12 14:02:41 +09:00
1 parent 75e8ed6c77
commit d986493431
9 files changed
+232 -34

No files matched your search

+56
View File
@@ -4,6 +4,7 @@ import { beforeEach, describe, expect, it } from "vitest";
import { UploadRepo, db } from "#lib/server/db/index.ts";
import { FileService, UploadService } from "#lib/server/services/index.ts";
import { isChunkUploaded } from "#lib/server/services/upload.ts";
import { hashFile } from "#lib/server/storage/index.ts";
import { ciphertext, createUser, newEntryParams, resetDatabase } from "../helpers/database.ts";
beforeEach(resetDatabase);
@@ -38,6 +39,61 @@ describe("upload session bitmap", () => {
});
describe("upload completion", () => {
it.each([false, true])(
"rejects a late duplicate without changing the file (completed: %s)",
async (completeBeforeDuplicate) => {
const { userId } = await createUser();
const { uploadId } = await UploadService.startFileUpload({
...newEntryParams(userId, "root"),
totalChunks: 1,
hskVersion: null,
contentType: "image/png",
encCreatedAt: null,
encLastModifiedAt: ciphertext(),
});
const session = (await UploadRepo.getUploadSession(db, uploadId, userId))!;
const started = Promise.withResolvers<void>();
const release = Promise.withResolvers<void>();
const duplicate = UploadService.uploadChunk(
userId,
uploadId,
1,
Readable.from(
(async function* () {
started.resolve();
await release.promise;
yield Buffer.alloc(100, 2);
})(),
),
);
await started.promise;
try {
const chunk = Buffer.alloc(100, 1);
const hash = createHash("sha256").update(chunk).digest("base64");
await UploadService.uploadChunk(userId, uploadId, 1, Readable.from([chunk]));
if (completeBeforeDuplicate) {
await UploadService.completeFileUpload(userId, uploadId, null, hash);
}
const rejected = expect(duplicate).rejects.toMatchObject({
code: completeBeforeDuplicate ? "NOT_FOUND" : "CONFLICT",
});
release.resolve();
await rejected;
expect(await hashFile(session.path)).toBe(hash);
if (!completeBeforeDuplicate) {
await UploadService.completeFileUpload(userId, uploadId, null, hash);
}
expect(await FileService.getAllFileIds(userId)).toHaveLength(1);
} finally {
release.resolve();
await duplicate.catch(() => {});
}
},
);
it("registers the file only once when completed concurrently", async () => {
const { userId } = await createUser();
const { uploadId } = await UploadService.startFileUpload({