| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
|
|
| const RAG_BASE_URL = process.env.RAG_SPACE_URL || "https://YOUR-HF-USERNAME-rag-knowledge-base.hf.space"; |
| const RAG_API_KEY = process.env.RAG_API_KEY || "dev-insecure-change-me"; |
| const TEST_COMPANY = "comp_test_001"; |
|
|
| |
|
|
| async function ragFetch( |
| endpoint: string, |
| options: RequestInit = {} |
| ): Promise<{ ok: boolean; status: number; data: any }> { |
| const url = `${RAG_BASE_URL}${endpoint}`; |
| const res = await fetch(url, { |
| ...options, |
| headers: { |
| "Content-Type": "application/json", |
| "X-RAG-API-Key": RAG_API_KEY, |
| ...(options.headers || {}), |
| }, |
| }); |
|
|
| let data: any; |
| try { |
| data = await res.json(); |
| } catch { |
| data = { raw: await res.text() }; |
| } |
|
|
| return { ok: res.ok, status: res.status, data }; |
| } |
|
|
| |
|
|
| export async function testHealth() { |
| console.log("\nπ TEST 1: Health Check"); |
| const res = await fetch(`${RAG_BASE_URL}/health`); |
| const data = await res.json(); |
| console.log("Status:", res.status); |
| console.log("Response:", data); |
| console.assert(res.ok, "β Health check failed"); |
| console.assert(data.status === "ok" || data.status === "degraded", "β Unexpected status"); |
| console.log("β
Health check passed"); |
| return data; |
| } |
|
|
| |
|
|
| export async function testProvision() { |
| console.log("\nπ TEST 2: Provision Tenant"); |
| const res = await ragFetch("/api/v1/provision", { |
| method: "POST", |
| body: JSON.stringify({ company_id: TEST_COMPANY }), |
| }); |
| console.log("Status:", res.status); |
| console.log("Response:", res.data); |
| console.assert(res.ok, `β Provision failed: ${JSON.stringify(res.data)}`); |
| console.assert( |
| res.data.collection === `kb_${TEST_COMPANY}`, |
| `β Wrong collection name: ${res.data.collection}` |
| ); |
| console.log("β
Provision passed"); |
| return res.data; |
| } |
|
|
| |
|
|
| export async function testIngestFile() { |
| console.log("\nπ TEST 3: Ingest File"); |
|
|
| |
| const testContent = ` |
| Company: Bytestream Technologies |
| Return Policy: All products can be returned within 30 days with receipt. |
| Shipping: Standard delivery takes 3-5 business days. Express is 1-2 days. |
| Support Hours: Monday to Saturday, 9 AM to 6 PM PKT. |
| Contact: support@bytestream.pk or call 0300-123-4567. |
| Products: SmartBot AI Package - Rs. 25,000/month. Basic Plan - Rs. 8,000/month. |
| Refund Process: Refunds are processed within 7 business days after return approval. |
| `.trim(); |
|
|
| const blob = new Blob([testContent], { type: "text/plain" }); |
| const formData = new FormData(); |
| formData.append("company_id", TEST_COMPANY); |
| formData.append("file", blob, "test_company_kb.txt"); |
|
|
| const res = await fetch(`${RAG_BASE_URL}/api/v1/ingest/file`, { |
| method: "POST", |
| headers: { "X-RAG-API-Key": RAG_API_KEY }, |
| body: formData, |
| }); |
|
|
| const data = await res.json(); |
| console.log("Status:", res.status); |
| console.log("Response:", data); |
| console.assert(res.ok, `β File ingest failed: ${JSON.stringify(data)}`); |
| console.assert(data.chunks_ingested > 0, "β No chunks ingested"); |
| console.log(`β
File ingest passed β ${data.chunks_ingested} chunks ingested`); |
| return data; |
| } |
|
|
| |
|
|
| export async function testIngestUrl() { |
| console.log("\nπ TEST 4: Ingest URL"); |
|
|
| |
| const testUrl = "https://en.wikipedia.org/wiki/Customer_service"; |
|
|
| const res = await ragFetch("/api/v1/ingest/url", { |
| method: "POST", |
| body: JSON.stringify({ company_id: TEST_COMPANY, url: testUrl }), |
| }); |
|
|
| console.log("Status:", res.status); |
| console.log("Response:", { ...res.data, collection: res.data.collection }); |
| console.assert(res.ok, `β URL ingest failed: ${JSON.stringify(res.data)}`); |
| console.assert(res.data.chunks_ingested > 0, "β No chunks ingested from URL"); |
| console.log(`β
URL ingest passed β ${res.data.chunks_ingested} chunks ingested`); |
| return res.data; |
| } |
|
|
| |
|
|
| export async function testQueryFiller() { |
| console.log("\nπ TEST 5: Query β Filler Phrase (should skip RAG)"); |
|
|
| const res = await ragFetch("/api/v1/query", { |
| method: "POST", |
| body: JSON.stringify({ |
| company_id: TEST_COMPANY, |
| query: "Hello", |
| }), |
| }); |
|
|
| console.log("Status:", res.status); |
| console.log("needs_rag:", res.data.needs_rag); |
| console.log("search_mode:", res.data.search_mode); |
| console.assert(res.ok, "β Query failed"); |
| console.assert(res.data.needs_rag === false, "β Should have skipped RAG for 'Hello'"); |
| console.assert(res.data.search_mode === "skipped", "β search_mode should be 'skipped'"); |
| console.log("β
Filler query test passed β RAG correctly skipped"); |
| return res.data; |
| } |
|
|
| |
|
|
| export async function testQueryReal() { |
| console.log("\nπ TEST 6: Query β Real KB Question (should hit Qdrant)"); |
|
|
| const res = await ragFetch("/api/v1/query", { |
| method: "POST", |
| body: JSON.stringify({ |
| company_id: TEST_COMPANY, |
| query: "What is the return policy?", |
| top_k: 3, |
| }), |
| }); |
|
|
| console.log("Status:", res.status); |
| console.log("needs_rag:", res.data.needs_rag); |
| console.log("search_mode:", res.data.search_mode); |
| console.log("chunks found:", res.data.chunks.length); |
| console.log("context preview:", res.data.context.substring(0, 200) + "..."); |
| console.assert(res.ok, "β Query failed"); |
| console.assert(res.data.needs_rag === true, "β Should have triggered RAG"); |
| console.assert(res.data.chunks.length > 0, "β Should have found chunks"); |
| console.log("β
Real query test passed"); |
| return res.data; |
| } |
|
|
| |
|
|
| export async function testTenantIsolation() { |
| console.log("\nπ TEST 7: Tenant Isolation β Company B cannot read Company A data"); |
|
|
| const companyB = "comp_other_tenant_999"; |
|
|
| |
| const res = await ragFetch("/api/v1/query", { |
| method: "POST", |
| body: JSON.stringify({ |
| company_id: companyB, |
| query: "What is the return policy?", |
| skip_intent_check: true, |
| }), |
| }); |
|
|
| console.log("Status:", res.status); |
| console.log("chunks found:", res.data.chunks?.length ?? "N/A"); |
|
|
| |
| const isolated = !res.ok || res.data.chunks?.length === 0; |
| console.assert(isolated, "β CRITICAL: Company B got Company A's data!"); |
| console.log("β
Tenant isolation verified β Company B has zero results"); |
| } |
|
|
| |
|
|
| export async function testCollectionInfo() { |
| console.log("\nπ TEST 8: Collection Info"); |
|
|
| const res = await ragFetch(`/api/v1/collections/${TEST_COMPANY}`); |
| console.log("Status:", res.status); |
| console.log("Info:", res.data); |
| console.assert(res.ok, "β Collection info failed"); |
| console.assert(res.data.points_count > 0, "β No points in collection after ingestion"); |
| console.log(`β
Collection info passed β ${res.data.points_count} points stored`); |
| } |
|
|
| |
|
|
| export async function testCleanup() { |
| console.log("\nπ TEST 9: Cleanup β Delete Test Collection"); |
|
|
| const res = await ragFetch("/api/v1/delete", { |
| method: "DELETE", |
| body: JSON.stringify({ company_id: TEST_COMPANY, confirm: true }), |
| }); |
|
|
| console.log("Status:", res.status); |
| console.log("Response:", res.data); |
| console.assert(res.ok, `β Delete failed: ${JSON.stringify(res.data)}`); |
| console.log("β
Cleanup passed β test collection deleted"); |
| } |
|
|
| |
|
|
| export async function runAllTests() { |
| console.log("β".repeat(60)); |
| console.log(" RAG SPACE β FULL INTEGRATION TEST SUITE"); |
| console.log(` Target: ${RAG_BASE_URL}`); |
| console.log("β".repeat(60)); |
|
|
| try { |
| await testHealth(); |
| await testProvision(); |
| await testIngestFile(); |
|
|
| |
| console.log("\nβ³ Waiting 2s for Qdrant indexing..."); |
| await new Promise((r) => setTimeout(r, 2000)); |
|
|
| await testQueryFiller(); |
| await testQueryReal(); |
| await testTenantIsolation(); |
| await testCollectionInfo(); |
| await testCleanup(); |
|
|
| console.log("\n" + "β".repeat(60)); |
| console.log(" β
ALL TESTS PASSED β RAG Space is fully operational"); |
| console.log("β".repeat(60)); |
| } catch (err) { |
| console.error("\nβ TEST SUITE FAILED:", err); |
| throw err; |
| } |
| } |
|
|
| |
| |
| if (typeof window === "undefined") { |
| runAllTests().catch(console.error); |
| } |