84 lines
2.9 KiB
TypeScript
84 lines
2.9 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import type { RoomMapping } from "./config.js";
|
|
import { buildManifest, MAX_ATTACHMENT_BYTES } from "./exporter.js";
|
|
import type { IndexedFile } from "./archive-index.js";
|
|
import { payloadPath } from "./archive-index.js";
|
|
|
|
const mapping: RoomMapping = {
|
|
roomId: "!room:example.org",
|
|
workspaceId: "11111111-1111-4111-8111-111111111111",
|
|
groupId: "22222222-2222-4222-8222-222222222222",
|
|
};
|
|
|
|
function row(overrides: Partial<IndexedFile> = {}): IndexedFile {
|
|
return {
|
|
id: "0d0e0f10-1111-4222-8222-333333333333",
|
|
eventId: "$ev1",
|
|
mxcUri: "mxc://example.org/abc",
|
|
originalName: "cat photo.png",
|
|
safeName: "cat_photo.png",
|
|
mime: "image/png",
|
|
mimeClass: "image",
|
|
byteSize: 1234,
|
|
sha256: "a".repeat(64),
|
|
sender: "@alice:example.org",
|
|
createdAt: "2026-01-02T03:04:05.000Z",
|
|
ocisResourceId: "42",
|
|
available: true,
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
describe("bundle manifest shape", () => {
|
|
it("carries every index row with the documented field names", () => {
|
|
const rows = [row(), row({ eventId: "$ev2", available: false, byteSize: 10, safeName: "gone.bin" })];
|
|
const manifest = buildManifest(mapping, rows, new Date("2026-02-03T04:05:06.000Z"), ["age1testrecipient"]);
|
|
expect(manifest).toMatchObject({
|
|
format: "chat-media-archive-bundle",
|
|
version: 1,
|
|
roomId: mapping.roomId,
|
|
workspaceId: mapping.workspaceId,
|
|
groupId: mapping.groupId,
|
|
exportedAt: "2026-02-03T04:05:06.000Z",
|
|
objectKey: null,
|
|
recipients: ["age1testrecipient"],
|
|
});
|
|
expect(manifest.files).toHaveLength(2);
|
|
expect(manifest.files[0]).toEqual({
|
|
eventId: "$ev1",
|
|
mxcUri: "mxc://example.org/abc",
|
|
originalName: "cat photo.png",
|
|
safeName: "cat_photo.png",
|
|
mime: "image/png",
|
|
mimeClass: "image",
|
|
byteSize: 1234,
|
|
sha256: "a".repeat(64),
|
|
sender: "@alice:example.org",
|
|
createdAt: "2026-01-02T03:04:05.000Z",
|
|
ocisResourceId: "42",
|
|
available: true,
|
|
});
|
|
});
|
|
|
|
it("counts only available files in fileCount/totalBytes, but records every row", () => {
|
|
const manifest = buildManifest(mapping, [
|
|
row({ byteSize: 100 }),
|
|
row({ eventId: "$ev2", byteSize: 40, available: false }),
|
|
], new Date(0), []);
|
|
expect(manifest.fileCount).toBe(1);
|
|
expect(manifest.totalBytes).toBe(100);
|
|
expect(manifest.files).toHaveLength(2);
|
|
expect(manifest.files.map((f) => f.available)).toEqual([true, false]);
|
|
});
|
|
|
|
it("derives deterministic, collision-free tar payload paths", () => {
|
|
const one = row({ eventId: "$a", safeName: "x.png" });
|
|
expect(payloadPath(one)).toBe("files/$a/x.png");
|
|
// Different events never collide even with identical safe names.
|
|
expect(payloadPath(row({ eventId: "$b", safeName: "x.png" }))).not.toBe(payloadPath(one));
|
|
});
|
|
|
|
it("documents the per-attachment budget constant", () => {
|
|
expect(MAX_ATTACHMENT_BYTES).toBe(20 * 1024 * 1024);
|
|
});
|
|
});
|