Files
odysseus/tests/test_diagnostics_logs.py
T
Kfir Sadeh d8e7cc7053 feat(ui): add real-time diagnostic logs console (#974)
* feat(diagnostics): add admin-gated real-time diagnostics logs terminal UI

* feat(ui): resolve diagnostics logs feedback and optimize client-side caching

* feat(ui): resolve diagnostics logs feedback
2026-06-15 10:32:51 +02:00

111 lines
3.5 KiB
Python

"""Route-level regression tests for GET /api/diagnostics/logs."""
import pytest
fastapi = pytest.importorskip("fastapi")
pytest.importorskip("starlette.testclient")
from fastapi import FastAPI, HTTPException, Request
from starlette.testclient import TestClient
# Importing the route module pulls a few app deps; skip cleanly if unavailable.
diag = pytest.importorskip("routes.diagnostics_routes")
def _client_with_admin_gate(monkeypatch, gate, tmp_path=None):
"""Mount the diagnostics router with a mock require_admin and DATA_DIR."""
monkeypatch.setattr(diag, "require_admin", gate)
if tmp_path:
monkeypatch.setattr(diag, "DATA_DIR", str(tmp_path))
app = FastAPI()
app.include_router(diag.setup_diagnostics_routes(
rag_manager=None, rag_available=False, research_handler=None,
memory_vector=None))
return TestClient(app, raise_server_exceptions=False)
def test_logs_unauthenticated_rejected(monkeypatch):
def gate(_request: Request):
raise HTTPException(401, "Not authenticated")
client = _client_with_admin_gate(monkeypatch, gate)
r = client.get("/api/diagnostics/logs")
assert r.status_code == 401
def test_logs_non_admin_forbidden(monkeypatch):
def gate(_request: Request):
raise HTTPException(403, "Admin only")
client = _client_with_admin_gate(monkeypatch, gate)
r = client.get("/api/diagnostics/logs")
assert r.status_code == 403
def test_logs_missing_file(monkeypatch, tmp_path):
def gate(_request: Request):
return None
client = _client_with_admin_gate(monkeypatch, gate, tmp_path)
r = client.get("/api/diagnostics/logs")
assert r.status_code == 200
body = r.json()
assert body["status"] == "success"
assert body["logs"] == []
def test_logs_tailing_and_clamping(monkeypatch, tmp_path):
# Setup mock log file
log_dir = tmp_path / "logs"
log_dir.mkdir(parents=True, exist_ok=True)
log_file = log_dir / "app.log"
# Write 1500 log lines
lines = [f"Log line {i}\n" for i in range(1, 1501)]
log_file.write_text("".join(lines), encoding="utf-8")
def gate(_request: Request):
return None
client = _client_with_admin_gate(monkeypatch, gate, tmp_path)
# 1. Default limit (200)
r = client.get("/api/diagnostics/logs")
assert r.status_code == 200
body = r.json()
assert len(body["logs"]) == 200
assert body["logs"][-1] == "Log line 1500"
assert body["logs"][0] == "Log line 1301"
# 2. Clamped upper bound (limit=2000 -> clamps to 1000)
r = client.get("/api/diagnostics/logs?limit=2000")
assert r.status_code == 200
body = r.json()
assert len(body["logs"]) == 1000
assert body["logs"][-1] == "Log line 1500"
assert body["logs"][0] == "Log line 501"
# 3. Clamped lower bound (limit=-5 -> clamps to 1)
r = client.get("/api/diagnostics/logs?limit=-5")
assert r.status_code == 200
body = r.json()
assert len(body["logs"]) == 1
assert body["logs"][0] == "Log line 1500"
# 4. Clamp limit=0 -> clamps to 1
r = client.get("/api/diagnostics/logs?limit=0")
assert r.status_code == 200
body = r.json()
assert len(body["logs"]) == 1
assert body["logs"][0] == "Log line 1500"
# 5. Exact custom limit
r = client.get("/api/diagnostics/logs?limit=5")
assert r.status_code == 200
body = r.json()
assert len(body["logs"]) == 5
assert body["logs"] == [
"Log line 1496",
"Log line 1497",
"Log line 1498",
"Log line 1499",
"Log line 1500"
]