tests / rag-persistence.test.ts
tests / rag-persistence.test.ts
import "../src/polyfills";
import { afterEach, describe, expect, it } from "vitest";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { LocalDocumentStore } from "../src/local/store";
import { indexPdfBatch } from "../src/local/pdf-batch";
import { extractPdf } from "../src/net/pdf-extractor";
const roots: string[] = [];
function tempDir(): string {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "swarm-rag-test-"));
roots.push(dir);
return dir;
}
afterEach(() => { for (const dir of roots.splice(0)) fs.rmSync(dir, { recursive: true, force: true }); });
function pdfWithText(text: string): Buffer {
const content = `BT /F1 14 Tf 72 720 Td (${text}) Tj ET`;
const objects = [
"<< /Type /Catalog /Pages 2 0 R >>",
"<< /Type /Pages /Kids [3 0 R] /Count 1 >>",
"<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Resources << /Font << /F1 4 0 R >> >> /Contents 5 0 R >>",
"<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>",
`<< /Length ${Buffer.byteLength(content)} >>\nstream\n${content}\nendstream`,
];
let body = "%PDF-1.4\n";
const offsets = [0];
objects.forEach((object, index) => {
offsets.push(Buffer.byteLength(body));
body += `${index + 1} 0 obj\n${object}\nendobj\n`;
});
const xref = Buffer.byteLength(body);
body += `xref\n0 ${objects.length + 1}\n0000000000 65535 f \n`;
for (const offset of offsets.slice(1)) body += `${String(offset).padStart(10, "0")} 00000 n \n`;
body += `trailer\n<< /Size ${objects.length + 1} /Root 1 0 R >>\nstartxref\n${xref}\n%%EOF\n`;
return Buffer.from(body);
}
describe("RAG PDF and index persistence", () => {
it("extracts a real PDF, saves the index, reloads it and retrieves the passage", async () => {
const root = tempDir();
const docs = path.join(root, "docs");
fs.mkdirSync(docs);
fs.writeFileSync(path.join(docs, "research.pdf"), pdfWithText("Photovoltaic panels improve renewable energy efficiency"));
const store = new LocalDocumentStore();
const library = await store.indexLibrary("papers", docs);
expect(library.fileCount).toBe(1);
expect(store.search("photovoltaic renewable").length).toBeGreaterThan(0);
const indexPath = path.join(root, "index.json");
store.saveIndex(indexPath);
const restored = new LocalDocumentStore();
expect(restored.loadIndex(indexPath)).toEqual({ loaded: 1, skipped: 0 });
expect(restored.search("photovoltaic renewable")[0].text).toContain("Photovoltaic");
});
it("returns a bounded preview while retaining the whole PDF text for indexing", async () => {
const text = "Photovoltaic panels improve renewable energy efficiency";
const parsed = await extractPdf(pdfWithText(text), "https://example.org/a.pdf", "https://example.org/a.pdf", 16, false, 20, 1, true);
expect(parsed.text.length).toBeLessThanOrEqual(16);
expect(parsed.fullText).toContain(text);
});
it("indexes all extracted PDFs together in a durable, isolated folder", async () => {
const root = tempDir();
const store = new LocalDocumentStore();
const indexPath = path.join(root, "index.json");
const id = await indexPdfBatch([
{ url: "https://example.org/one.pdf", title: "One", fullText: "Hydrogen fuel research and useful technical findings" },
{ url: "https://example.org/two.pdf", title: "Two", fullText: "Battery storage research and useful scientific findings" },
], "batch", path.join(root, "batches"), store, () => { store.saveIndex(indexPath); return true; });
expect(store.getLibraries().find((lib) => lib.id === id)?.fileCount).toBe(2);
const restored = new LocalDocumentStore();
expect(restored.loadIndex(indexPath).loaded).toBe(1);
expect(restored.search("hydrogen fuel")[0].text).toContain("https://example.org/one.pdf");
expect(restored.search("battery storage")[0].text).toContain("Battery storage");
});
it("preserves an existing library when re-indexing cannot read any files", async () => {
const root = tempDir();
const file = path.join(root, "notes.txt");
fs.writeFileSync(file, "Original searchable evidence for renewable energy research.");
const store = new LocalDocumentStore();
const original = await store.indexLibrary("evidence", root);
fs.writeFileSync(file, "");
await expect(store.indexLibrary("evidence", root)).rejects.toThrow("previous library was preserved");
expect(store.getLibraries()[0].id).toBe(original.id);
expect(store.search("renewable energy").length).toBeGreaterThan(0);
});
});
import "../src/polyfills";
import { afterEach, describe, expect, it } from "vitest";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { LocalDocumentStore } from "../src/local/store";
import { indexPdfBatch } from "../src/local/pdf-batch";
import { extractPdf } from "../src/net/pdf-extractor";
const roots: string[] = [];
function tempDir(): string {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "swarm-rag-test-"));
roots.push(dir);
return dir;
}
afterEach(() => { for (const dir of roots.splice(0)) fs.rmSync(dir, { recursive: true, force: true }); });
function pdfWithText(text: string): Buffer {
const content = `BT /F1 14 Tf 72 720 Td (${text}) Tj ET`;
const objects = [
"<< /Type /Catalog /Pages 2 0 R >>",
"<< /Type /Pages /Kids [3 0 R] /Count 1 >>",
"<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Resources << /Font << /F1 4 0 R >> >> /Contents 5 0 R >>",
"<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>",
`<< /Length ${Buffer.byteLength(content)} >>\nstream\n${content}\nendstream`,
];
let body = "%PDF-1.4\n";
const offsets = [0];
objects.forEach((object, index) => {
offsets.push(Buffer.byteLength(body));
body += `${index + 1} 0 obj\n${object}\nendobj\n`;
});
const xref = Buffer.byteLength(body);
body += `xref\n0 ${objects.length + 1}\n0000000000 65535 f \n`;
for (const offset of offsets.slice(1)) body += `${String(offset).padStart(10, "0")} 00000 n \n`;
body += `trailer\n<< /Size ${objects.length + 1} /Root 1 0 R >>\nstartxref\n${xref}\n%%EOF\n`;
return Buffer.from(body);
}
describe("RAG PDF and index persistence", () => {
it("extracts a real PDF, saves the index, reloads it and retrieves the passage", async () => {
const root = tempDir();
const docs = path.join(root, "docs");
fs.mkdirSync(docs);
fs.writeFileSync(path.join(docs, "research.pdf"), pdfWithText("Photovoltaic panels improve renewable energy efficiency"));
const store = new LocalDocumentStore();
const library = await store.indexLibrary("papers", docs);
expect(library.fileCount).toBe(1);
expect(store.search("photovoltaic renewable").length).toBeGreaterThan(0);
const indexPath = path.join(root, "index.json");
store.saveIndex(indexPath);
const restored = new LocalDocumentStore();
expect(restored.loadIndex(indexPath)).toEqual({ loaded: 1, skipped: 0 });
expect(restored.search("photovoltaic renewable")[0].text).toContain("Photovoltaic");
});
it("returns a bounded preview while retaining the whole PDF text for indexing", async () => {
const text = "Photovoltaic panels improve renewable energy efficiency";
const parsed = await extractPdf(pdfWithText(text), "https://example.org/a.pdf", "https://example.org/a.pdf", 16, false, 20, 1, true);
expect(parsed.text.length).toBeLessThanOrEqual(16);
expect(parsed.fullText).toContain(text);
});
it("indexes all extracted PDFs together in a durable, isolated folder", async () => {
const root = tempDir();
const store = new LocalDocumentStore();
const indexPath = path.join(root, "index.json");
const id = await indexPdfBatch([
{ url: "https://example.org/one.pdf", title: "One", fullText: "Hydrogen fuel research and useful technical findings" },
{ url: "https://example.org/two.pdf", title: "Two", fullText: "Battery storage research and useful scientific findings" },
], "batch", path.join(root, "batches"), store, () => { store.saveIndex(indexPath); return true; });
expect(store.getLibraries().find((lib) => lib.id === id)?.fileCount).toBe(2);
const restored = new LocalDocumentStore();
expect(restored.loadIndex(indexPath).loaded).toBe(1);
expect(restored.search("hydrogen fuel")[0].text).toContain("https://example.org/one.pdf");
expect(restored.search("battery storage")[0].text).toContain("Battery storage");
});
it("preserves an existing library when re-indexing cannot read any files", async () => {
const root = tempDir();
const file = path.join(root, "notes.txt");
fs.writeFileSync(file, "Original searchable evidence for renewable energy research.");
const store = new LocalDocumentStore();
const original = await store.indexLibrary("evidence", root);
fs.writeFileSync(file, "");
await expect(store.indexLibrary("evidence", root)).rejects.toThrow("previous library was preserved");
expect(store.getLibraries()[0].id).toBe(original.id);
expect(store.search("renewable energy").length).toBeGreaterThan(0);
});
});