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:
parent
4515897acd
commit
05f6583870
2 changed files with 88 additions and 3 deletions
|
|
@ -3,6 +3,9 @@ import { after, describe, it } from "node:test";
|
||||||
|
|
||||||
import { buildApp } from "./server.js";
|
import { buildApp } from "./server.js";
|
||||||
import { setServers } from "node:dns";
|
import { setServers } from "node:dns";
|
||||||
|
import { allowedNodeEnvironmentFlags } from "node:process";
|
||||||
|
import { unescape } from "node:querystring";
|
||||||
|
import { error } from "node:console";
|
||||||
|
|
||||||
describe("API endpoints", () => {
|
describe("API endpoints", () => {
|
||||||
const app = buildApp();
|
const app = buildApp();
|
||||||
|
|
@ -212,4 +215,85 @@ describe("API endpoints", () => {
|
||||||
});
|
});
|
||||||
assert.equal(response.body.includes("Sensitive internal detail"), false);
|
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();
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import Fastify, { type FastifyError } from "fastify";
|
import Fastify, { type FastifyError } from "fastify";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { ingestDocument } from "./ingestion.js";
|
import { ingestDocument as ingestDocumentDefault } from "./ingestion.js";
|
||||||
import { checkOllamaHealth, generateResponse } from "./ollama.js";
|
import { checkOllamaHealth, generateResponse } from "./ollama.js";
|
||||||
|
|
||||||
const echoSchema = z.object({
|
const echoSchema = z.object({
|
||||||
|
|
@ -10,13 +10,14 @@ const echoSchema = z.object({
|
||||||
|
|
||||||
const documentSchema = z.object({
|
const documentSchema = z.object({
|
||||||
title: z.string().trim().min(1).max(200),
|
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),
|
content: z.string().trim().min(1).max(100_000),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const buildApp = (
|
export const buildApp = (
|
||||||
generate = generateResponse,
|
generate = generateResponse,
|
||||||
checkHealth = checkOllamaHealth,
|
checkHealth = checkOllamaHealth,
|
||||||
|
ingest = ingestDocumentDefault,
|
||||||
) => {
|
) => {
|
||||||
const app = Fastify({
|
const app = Fastify({
|
||||||
logger: true,
|
logger: true,
|
||||||
|
|
@ -112,7 +113,7 @@ export const buildApp = (
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const document = await ingestDocument(result.data);
|
const document = await ingest(result.data);
|
||||||
|
|
||||||
return reply.code(201).send(document);
|
return reply.code(201).send(document);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue