test: add document ingestion endpoint coverage

- Add tests for successful document ingestion and response payloads
- Verify invalid document input returns HTTP 400 without invoking ingestion
- Verify ingestion failures return sanitized HTTP 503 responses
- Inject the ingestion function through buildApp for isolated testing
- Increase the maximum document source length to 2,000 characters
This commit is contained in:
Brandon Wolfgang 2026-10-22 10:43:35 -05:00
parent 4515897acd
commit 05f6583870
2 changed files with 88 additions and 3 deletions

View file

@ -3,6 +3,9 @@ import { after, describe, it } from "node:test";
import { buildApp } from "./server.js";
import { setServers } from "node:dns";
import { allowedNodeEnvironmentFlags } from "node:process";
import { unescape } from "node:querystring";
import { error } from "node:console";
describe("API endpoints", () => {
const app = buildApp();
@ -212,4 +215,85 @@ describe("API endpoints", () => {
});
assert.equal(response.body.includes("Sensitive internal detail"), false);
});
it("POST /documents ingests a valid document", async () => {
const app = buildApp(undefined, undefined, async (document) => {
assert.equal(document.title, "Test document");
assert.equal(document.source, "unit-test");
assert.equal(document.content, "Document content.");
return { documentId: "42", chunkCount: 1 };
});
try {
const response = await app.inject({
method: "POST",
url: "/documents",
payload: {
title: "Test document",
source: "unit-test",
content: "Document content.",
},
});
assert.equal(response.statusCode, 201);
assert.deepEqual(response.json(), {
documentId: "42",
chunkCount: 1,
});
} finally {
await app.close();
}
});
it("POST / documents rejects invalid input", async () => {
const app = buildApp(undefined, undefined, async () => {
throw new Error("Ingestions should not run");
});
try {
const response = await app.inject({
method: "POST",
url: "/documents",
payload: {
title: " ",
content: "Document content.",
},
});
assert.equal(response.statusCode, 400);
assert.deepEqual(response.json(), {
error: "Invalid document",
});
} finally {
await app.close();
}
});
it("POST /documents returns 503 when ingestion fails", async () => {
const app = buildApp(undefined, undefined, async () => {
throw new Error("Database connection details");
});
try {
const response = await app.inject({
method: "POST",
url: "/documents",
payload: {
title: "Test document",
content: "Document content.",
},
});
assert.equal(response.statusCode, 503);
assert.deepEqual(response.json(), {
error: "Document ingestion failed",
});
assert.equal(
response.body.includes("Database connection details"),
false,
);
} finally {
await app.close();
}
});
});

View file

@ -1,7 +1,7 @@
import Fastify, { type FastifyError } from "fastify";
import { z } from "zod";
import { ingestDocument } from "./ingestion.js";
import { ingestDocument as ingestDocumentDefault } from "./ingestion.js";
import { checkOllamaHealth, generateResponse } from "./ollama.js";
const echoSchema = z.object({
@ -10,13 +10,14 @@ const echoSchema = z.object({
const documentSchema = z.object({
title: z.string().trim().min(1).max(200),
source: z.string().trim().max(2_00).optional(),
source: z.string().trim().max(2_000).optional(),
content: z.string().trim().min(1).max(100_000),
});
export const buildApp = (
generate = generateResponse,
checkHealth = checkOllamaHealth,
ingest = ingestDocumentDefault,
) => {
const app = Fastify({
logger: true,
@ -112,7 +113,7 @@ export const buildApp = (
}
try {
const document = await ingestDocument(result.data);
const document = await ingest(result.data);
return reply.code(201).send(document);
} catch (error) {