test: add unit tests for all 10 routers (92 total)
New test files: - test_conversations.py — list/create/get/update/delete/delete-all, admin enforcement - test_presets.py — list/create/update/delete, default preset protection - test_profile.py — get/update/default, length validation - test_models_router.py — list/ps/show/stats/search-status, connect errors - test_completions.py — API key auth, FIM passthrough, streaming/blocking, errors - test_search_route.py — explicit search flow, no results, stream errors - test_memories.py — edit/search/stats endpoints, validation, admin enforcement Update AGENTS.md with full test file coverage table and README.md
This commit is contained in:
161
tests/test_memories.py
Normal file
161
tests/test_memories.py
Normal file
@@ -0,0 +1,161 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
import app
|
||||
import config
|
||||
import db
|
||||
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-memories.db"
|
||||
SESSIONS.clear()
|
||||
PIN_ATTEMPTS.clear()
|
||||
RATE_EVENTS.clear()
|
||||
db.init_db()
|
||||
return TestClient(app.app, raise_server_exceptions=False)
|
||||
|
||||
|
||||
def _admin_headers(client: TestClient) -> dict:
|
||||
login = client.post("/api/auth/login", json={"pin": "1234"}, headers={"Origin": "http://testserver"})
|
||||
sid = login.json()["session_id"]
|
||||
return {"X-Session-ID": sid, "Origin": "http://testserver"}
|
||||
|
||||
|
||||
def _guest_headers(client: TestClient) -> dict:
|
||||
sid = client.post("/api/auth/guest", headers={"Origin": "http://testserver"}).json()["session_id"]
|
||||
return {"X-Session-ID": sid, "Origin": "http://testserver"}
|
||||
|
||||
|
||||
def _create_memory(client: TestClient, headers: dict, fact: str = "test fact", topic: str = "general") -> int:
|
||||
resp = client.post("/api/memories", json={"fact": fact, "topic": topic}, headers=headers)
|
||||
assert resp.status_code == 200
|
||||
return resp.json()["rowid"]
|
||||
|
||||
|
||||
def test_list_memories_empty(tmp_path: Path):
|
||||
with make_client(tmp_path) as client:
|
||||
resp = client.get("/api/memories", headers=_guest_headers(client))
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()["count"] == 0
|
||||
|
||||
|
||||
def test_list_memories_by_topic(tmp_path: Path):
|
||||
with make_client(tmp_path) as client:
|
||||
headers = _admin_headers(client)
|
||||
_create_memory(client, headers, "I like Python", "preference")
|
||||
_create_memory(client, headers, "Building a game", "project")
|
||||
|
||||
general = client.get("/api/memories?topic=preference", headers=_guest_headers(client))
|
||||
assert general.json()["count"] == 1
|
||||
assert general.json()["memories"][0]["topic"] == "preference"
|
||||
|
||||
|
||||
def test_create_memory_requires_fact(tmp_path: Path):
|
||||
with make_client(tmp_path) as client:
|
||||
resp = client.post("/api/memories", json={"fact": ""}, headers=_admin_headers(client))
|
||||
assert resp.status_code == 400
|
||||
|
||||
|
||||
def test_create_memory_too_long(tmp_path: Path):
|
||||
with make_client(tmp_path) as client:
|
||||
long_fact = "x" * (config.MAX_MEMORY_FACT_CHARS + 1)
|
||||
resp = client.post("/api/memories", json={"fact": long_fact}, headers=_admin_headers(client))
|
||||
assert resp.status_code == 413
|
||||
|
||||
|
||||
def test_edit_memory(tmp_path: Path):
|
||||
with make_client(tmp_path) as client:
|
||||
headers = _admin_headers(client)
|
||||
rowid = _create_memory(client, headers, "original fact")
|
||||
|
||||
edit = client.put(f"/api/memories/{rowid}", json={"fact": "updated fact"}, headers=headers)
|
||||
assert edit.status_code == 200
|
||||
|
||||
memories = client.get("/api/memories", headers=_guest_headers(client)).json()
|
||||
assert any(m["fact"] == "updated fact" for m in memories["memories"])
|
||||
|
||||
|
||||
def test_edit_memory_not_found(tmp_path: Path):
|
||||
with make_client(tmp_path) as client:
|
||||
resp = client.put("/api/memories/99999", json={"fact": "nope"}, headers=_admin_headers(client))
|
||||
assert resp.status_code == 404
|
||||
|
||||
|
||||
def test_edit_memory_empty_fact(tmp_path: Path):
|
||||
with make_client(tmp_path) as client:
|
||||
headers = _admin_headers(client)
|
||||
rowid = _create_memory(client, headers, "some fact")
|
||||
resp = client.put(f"/api/memories/{rowid}", json={"fact": ""}, headers=headers)
|
||||
assert resp.status_code == 400
|
||||
|
||||
|
||||
def test_edit_memory_too_long(tmp_path: Path):
|
||||
with make_client(tmp_path) as client:
|
||||
headers = _admin_headers(client)
|
||||
rowid = _create_memory(client, headers, "some fact")
|
||||
long_fact = "x" * (config.MAX_MEMORY_FACT_CHARS + 1)
|
||||
resp = client.put(f"/api/memories/{rowid}", json={"fact": long_fact}, headers=headers)
|
||||
assert resp.status_code == 413
|
||||
|
||||
|
||||
def test_delete_memory_not_found(tmp_path: Path):
|
||||
with make_client(tmp_path) as client:
|
||||
resp = client.delete("/api/memories/99999", headers=_admin_headers(client))
|
||||
assert resp.status_code == 404
|
||||
|
||||
|
||||
def test_search_memories(tmp_path: Path):
|
||||
with make_client(tmp_path) as client:
|
||||
headers = _admin_headers(client)
|
||||
_create_memory(client, headers, "my favorite color is blue", "preference")
|
||||
_create_memory(client, headers, "running nginx on port 443", "infrastructure")
|
||||
|
||||
resp = client.get("/api/memories/search?q=nginx&limit=5", headers=_guest_headers(client))
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert data["count"] >= 1
|
||||
assert any("nginx" in r["fact"] for r in data["results"])
|
||||
|
||||
|
||||
def test_search_memories_no_results(tmp_path: Path):
|
||||
with make_client(tmp_path) as client:
|
||||
resp = client.get("/api/memories/search?q=xyznonexistent&limit=5", headers=_guest_headers(client))
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()["count"] == 0
|
||||
|
||||
|
||||
def test_memory_stats(tmp_path: Path):
|
||||
with make_client(tmp_path) as client:
|
||||
headers = _admin_headers(client)
|
||||
_create_memory(client, headers, "like rust", "preference")
|
||||
_create_memory(client, headers, "like python", "preference")
|
||||
_create_memory(client, headers, "project game", "project")
|
||||
|
||||
resp = client.get("/api/memories/stats", headers=_guest_headers(client))
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert data["total"] == 3
|
||||
assert data["by_topic"]["preference"] == 2
|
||||
assert data["by_topic"]["project"] == 1
|
||||
|
||||
|
||||
def test_guest_cannot_create_memory(tmp_path: Path):
|
||||
with make_client(tmp_path) as client:
|
||||
resp = client.post("/api/memories", json={"fact": "hack"}, headers=_guest_headers(client))
|
||||
assert resp.status_code == 403
|
||||
|
||||
|
||||
def test_guest_cannot_edit_memory(tmp_path: Path):
|
||||
with make_client(tmp_path) as client:
|
||||
resp = client.put("/api/memories/1", json={"fact": "hack"}, headers=_guest_headers(client))
|
||||
assert resp.status_code == 403
|
||||
|
||||
|
||||
def test_guest_cannot_delete_memory(tmp_path: Path):
|
||||
with make_client(tmp_path) as client:
|
||||
resp = client.delete("/api/memories/1", headers=_guest_headers(client))
|
||||
assert resp.status_code == 403
|
||||
Reference in New Issue
Block a user