dify/knowledge-fs/packages/api/src/query-images.test.ts

117 lines
3.8 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
QUERY_IMAGE_EXPANSION_METADATA_KEY,
QUERY_IMAGE_REFERENCES_METADATA_KEY,
QueryImageReferencesSchema,
QueryImageResolutionError,
assertResolvedQueryImages,
hasQueryInput,
queryImageExpansionFromMetadata,
queryImageReferencesFromMetadata,
} from "./query-images";
const IMAGE_ID = "00000000-0000-4000-8000-000000000001";
describe("query image contracts", () => {
it("accepts either text or images and permits an intentional mixed query", () => {
expect(hasQueryInput({ query: "find this" })).toBe(true);
expect(hasQueryInput({ queryImages: [{ uploadFileId: IMAGE_ID }] })).toBe(true);
expect(hasQueryInput({ query: "find this", queryImages: [{ uploadFileId: IMAGE_ID }] })).toBe(
true,
);
expect(hasQueryInput({ query: " ", queryImages: [] })).toBe(false);
expect(hasQueryInput({})).toBe(false);
});
it("rejects malformed, duplicate, and over-count references", () => {
expect(() => QueryImageReferencesSchema.parse([{ uploadFileId: "not-a-uuid" }])).toThrow();
expect(() =>
QueryImageReferencesSchema.parse([{ uploadFileId: IMAGE_ID }, { uploadFileId: IMAGE_ID }]),
).toThrow("duplicate");
expect(() =>
QueryImageReferencesSchema.parse(
Array.from({ length: 5 }, (_, index) => ({
uploadFileId: `00000000-0000-4000-8000-00000000000${index}`,
})),
),
).toThrow();
});
it("enforces per-image and aggregate resolved-byte bounds", () => {
const nineMiB = new Uint8Array(9 * 1024 * 1024);
expect(() =>
assertResolvedQueryImages(
Array.from({ length: 4 }, (_, index) => ({
body: nineMiB,
byteSize: nineMiB.byteLength,
mimeType: "image/png" as const,
sha256: `${index}`.repeat(64),
uploadFileId: `00000000-0000-4000-8000-00000000000${index}`,
})),
),
).toThrow(QueryImageResolutionError);
expect(() =>
assertResolvedQueryImages([
{
body: new Uint8Array([1]),
byteSize: 2,
mimeType: "image/png",
sha256: "a".repeat(64),
uploadFileId: IMAGE_ID,
},
]),
).toThrow("byte size is invalid");
expect(() =>
assertResolvedQueryImages(
Array.from({ length: 5 }, (_, index) => ({
body: new Uint8Array([index]),
byteSize: 1,
mimeType: "image/png" as const,
sha256: `${index}`.repeat(64),
uploadFileId: `00000000-0000-4000-8000-00000000000${index}`,
})),
),
).toThrow("max count");
const tooLarge = new Uint8Array(10 * 1024 * 1024 + 1);
expect(() =>
assertResolvedQueryImages([
{
body: tooLarge,
byteSize: tooLarge.byteLength,
mimeType: "image/webp",
sha256: "b".repeat(64),
uploadFileId: IMAGE_ID,
},
]),
).toThrow("max bytes");
const valid = {
body: new Uint8Array([1, 2]),
byteSize: 2,
mimeType: "image/jpeg" as const,
sha256: "c".repeat(64),
uploadFileId: IMAGE_ID,
};
expect(assertResolvedQueryImages([valid])).toEqual([valid]);
});
it("round-trips only validated durable references and normalized expansion text", () => {
const metadata = {
[QUERY_IMAGE_EXPANSION_METADATA_KEY]: " visible invoice ",
[QUERY_IMAGE_REFERENCES_METADATA_KEY]: [{ uploadFileId: IMAGE_ID }],
};
expect(queryImageReferencesFromMetadata(metadata)).toEqual([{ uploadFileId: IMAGE_ID }]);
expect(queryImageExpansionFromMetadata(metadata)).toBe("visible invoice");
expect(
queryImageExpansionFromMetadata({ [QUERY_IMAGE_EXPANSION_METADATA_KEY]: " " }),
).toBeUndefined();
expect(
queryImageReferencesFromMetadata({ [QUERY_IMAGE_REFERENCES_METADATA_KEY]: "invalid" }),
).toEqual([]);
});
});