v1.10.0 -> v1.11.0: terminal command RAG hook (Roadmap I)
- POST /api/ingest with Bearer token auth, chunk_text, embed, Qdrant upsert - docs/jc-ingest.sh — shell script for PROMPT_COMMAND hook on jarvis - /api/ingest exempted from session middleware (self-authenticating) - 5 tests: missing/wrong key, empty/missing content, success path
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import httpx
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
import app
|
||||
import db
|
||||
import routers.ingest as ingest_route
|
||||
from security import SESSIONS, PIN_ATTEMPTS, RATE_EVENTS
|
||||
|
||||
|
||||
def make_client(tmp_path: Path) -> TestClient:
|
||||
os.environ["JARVISCHAT_ADMIN_PIN"] = "1234"
|
||||
db.DB_PATH = tmp_path / "jarvischat-ingest.db"
|
||||
SESSIONS.clear()
|
||||
PIN_ATTEMPTS.clear()
|
||||
RATE_EVENTS.clear()
|
||||
db.init_db()
|
||||
return TestClient(app.app, raise_server_exceptions=False)
|
||||
|
||||
|
||||
TEST_API_KEY = "test-sk-jarvischat-ingest"
|
||||
|
||||
|
||||
def _auth_headers() -> dict:
|
||||
return {"Authorization": f"Bearer {TEST_API_KEY}", "Content-Type": "application/json", "Origin": "http://testserver"}
|
||||
|
||||
|
||||
def test_ingest_missing_api_key(tmp_path: Path):
|
||||
with make_client(tmp_path) as client:
|
||||
resp = client.post("/api/ingest", json={"content": "test"}, headers={"Origin": "http://testserver"})
|
||||
assert resp.status_code == 401
|
||||
|
||||
|
||||
def test_ingest_wrong_api_key(tmp_path: Path):
|
||||
with make_client(tmp_path) as client:
|
||||
resp = client.post("/api/ingest", json={"content": "test"},
|
||||
headers={"Authorization": "Bearer wrong", "Origin": "http://testserver"})
|
||||
assert resp.status_code == 401
|
||||
|
||||
|
||||
def test_ingest_empty_content(tmp_path: Path):
|
||||
monkeypatch = __import__('pytest').MonkeyPatch()
|
||||
monkeypatch.setattr(ingest_route, "COMPLETIONS_API_KEY", TEST_API_KEY)
|
||||
with make_client(tmp_path) as client:
|
||||
resp = client.post("/api/ingest", json={"content": ""}, headers=_auth_headers())
|
||||
assert resp.status_code == 422
|
||||
monkeypatch.undo()
|
||||
|
||||
|
||||
def test_ingest_missing_content(tmp_path: Path):
|
||||
monkeypatch = __import__('pytest').MonkeyPatch()
|
||||
monkeypatch.setattr(ingest_route, "COMPLETIONS_API_KEY", TEST_API_KEY)
|
||||
with make_client(tmp_path) as client:
|
||||
resp = client.post("/api/ingest", json={}, headers=_auth_headers())
|
||||
assert resp.status_code == 422
|
||||
monkeypatch.undo()
|
||||
|
||||
|
||||
def test_ingest_success(tmp_path: Path, monkeypatch):
|
||||
monkeypatch.setattr(ingest_route, "COMPLETIONS_API_KEY", TEST_API_KEY)
|
||||
|
||||
embed_count = 0
|
||||
|
||||
class FakeAsyncClient:
|
||||
class FakeResponse:
|
||||
def __init__(self, status, json_data=None):
|
||||
self.status_code = status
|
||||
self._json = json_data or {}
|
||||
|
||||
def json(self):
|
||||
return self._json
|
||||
|
||||
def __init__(self, *a, **kw):
|
||||
pass
|
||||
|
||||
async def __aenter__(self):
|
||||
return self
|
||||
|
||||
async def __aexit__(self, *a):
|
||||
pass
|
||||
|
||||
async def post(self, url, **kw):
|
||||
nonlocal embed_count
|
||||
if "/api/embeddings" in url:
|
||||
embed_count += 1
|
||||
return self.FakeResponse(200, {"embedding": [0.1] * 768})
|
||||
return self.FakeResponse(200)
|
||||
|
||||
async def put(self, url, **kw):
|
||||
return self.FakeResponse(200)
|
||||
|
||||
monkeypatch.setattr(httpx, "AsyncClient", lambda *a, **kw: FakeAsyncClient())
|
||||
|
||||
with make_client(tmp_path) as client:
|
||||
resp = client.post("/api/ingest", json={"content": "test " * 1000, "source": "terminal"}, headers=_auth_headers())
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert data["source"] == "terminal"
|
||||
assert data["chunks_ingested"] > 0
|
||||
assert embed_count == data["chunks_ingested"]
|
||||
assert "message" in data
|
||||
Reference in New Issue
Block a user