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:
gramps
2026-07-03 12:35:21 -07:00
parent 04fbe90f08
commit 1ac21ad13f
5 changed files with 203 additions and 3 deletions
+104
View File
@@ -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