231 lines
6.8 KiB
Python
231 lines
6.8 KiB
Python
"""Smoke tests — verify every major page loads without uncaught exceptions.
|
|
|
|
These tests catch regressions that unit tests miss: import errors,
|
|
template rendering failures, database schema mismatches, and startup
|
|
crashes. They run fast (no Ollama needed) and should stay green on
|
|
every commit.
|
|
"""
|
|
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
|
|
@pytest.fixture
|
|
def client():
|
|
from dashboard.app import app
|
|
|
|
# Block all LLM calls so smoke tests never hit a real Ollama
|
|
mock_run = MagicMock()
|
|
mock_run.content = "Smoke test — no LLM."
|
|
mock_agent = MagicMock()
|
|
mock_agent.run.return_value = mock_run
|
|
with patch("timmy.agent.create_timmy", return_value=mock_agent):
|
|
with TestClient(app, raise_server_exceptions=False) as c:
|
|
yield c
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Core pages — these MUST return 200
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestCorePages:
|
|
"""Every core dashboard page loads without error."""
|
|
|
|
def test_index(self, client):
|
|
r = client.get("/")
|
|
assert r.status_code == 200
|
|
|
|
def test_health(self, client):
|
|
r = client.get("/health")
|
|
assert r.status_code == 200
|
|
|
|
def test_health_status(self, client):
|
|
r = client.get("/health/status")
|
|
assert r.status_code == 200
|
|
|
|
def test_agent_panel(self, client):
|
|
r = client.get("/agents/default/panel")
|
|
assert r.status_code == 200
|
|
|
|
def test_agent_history(self, client):
|
|
r = client.get("/agents/default/history")
|
|
assert r.status_code == 200
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Feature pages — should return 200 (or 307 redirect, never 500)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestFeaturePages:
|
|
"""Feature pages load without 500 errors."""
|
|
|
|
def test_briefing(self, client):
|
|
r = client.get("/briefing")
|
|
assert r.status_code in (200, 307)
|
|
|
|
def test_thinking(self, client):
|
|
r = client.get("/thinking")
|
|
assert r.status_code == 200
|
|
|
|
def test_tools(self, client):
|
|
r = client.get("/tools")
|
|
assert r.status_code == 200
|
|
|
|
def test_memory(self, client):
|
|
r = client.get("/memory")
|
|
assert r.status_code == 200
|
|
|
|
def test_calm(self, client):
|
|
r = client.get("/calm")
|
|
assert r.status_code == 200
|
|
|
|
def test_tasks(self, client):
|
|
r = client.get("/tasks")
|
|
assert r.status_code == 200
|
|
|
|
def test_work_orders_queue(self, client):
|
|
r = client.get("/work-orders/queue")
|
|
assert r.status_code == 200
|
|
|
|
def test_mobile(self, client):
|
|
r = client.get("/mobile")
|
|
assert r.status_code == 200
|
|
|
|
def test_spark(self, client):
|
|
r = client.get("/spark")
|
|
assert r.status_code in (200, 307)
|
|
|
|
def test_models(self, client):
|
|
r = client.get("/models")
|
|
assert r.status_code == 200
|
|
|
|
def test_memory_page(self, client):
|
|
r = client.get("/memory")
|
|
assert r.status_code in (200, 307)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# JSON API endpoints — should return valid JSON, never 500
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestAPIEndpoints:
|
|
"""API endpoints return valid JSON without server errors."""
|
|
|
|
def test_health_json(self, client):
|
|
r = client.get("/health")
|
|
assert r.status_code == 200
|
|
data = r.json()
|
|
assert "status" in data
|
|
|
|
def test_health_components(self, client):
|
|
r = client.get("/health/components")
|
|
assert r.status_code == 200
|
|
|
|
def test_health_sovereignty(self, client):
|
|
r = client.get("/health/sovereignty")
|
|
assert r.status_code == 200
|
|
|
|
def test_health_snapshot(self, client):
|
|
r = client.get("/health/snapshot")
|
|
assert r.status_code == 200
|
|
data = r.json()
|
|
assert "overall_status" in data
|
|
assert data["overall_status"] in ["green", "yellow", "red", "unknown"]
|
|
|
|
def test_queue_status(self, client):
|
|
r = client.get("/api/queue/status")
|
|
assert r.status_code == 200
|
|
|
|
def test_tasks_api(self, client):
|
|
r = client.get("/api/tasks")
|
|
assert r.status_code == 200
|
|
|
|
def test_chat_history(self, client):
|
|
r = client.get("/api/chat/history")
|
|
assert r.status_code == 200
|
|
|
|
def test_tools_stats(self, client):
|
|
r = client.get("/tools/api/stats")
|
|
assert r.status_code == 200
|
|
|
|
def test_thinking_api(self, client):
|
|
r = client.get("/thinking/api")
|
|
assert r.status_code == 200
|
|
|
|
def test_notifications_api(self, client):
|
|
r = client.get("/api/notifications")
|
|
assert r.status_code == 200
|
|
|
|
def test_mobile_status(self, client):
|
|
r = client.get("/mobile/status")
|
|
assert r.status_code == 200
|
|
|
|
def test_discord_status(self, client):
|
|
r = client.get("/discord/status")
|
|
assert r.status_code == 200
|
|
|
|
def test_telegram_status(self, client):
|
|
r = client.get("/telegram/status")
|
|
assert r.status_code == 200
|
|
|
|
def test_grok_status(self, client):
|
|
r = client.get("/grok/status")
|
|
assert r.status_code == 200
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# No 500s — every GET route should survive without server error
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestNo500:
|
|
"""Verify that no page returns a 500 Internal Server Error."""
|
|
|
|
@pytest.mark.parametrize(
|
|
"path",
|
|
[
|
|
"/",
|
|
"/health",
|
|
"/health/status",
|
|
"/health/sovereignty",
|
|
"/health/snapshot",
|
|
"/health/components",
|
|
"/agents/default/panel",
|
|
"/agents/default/history",
|
|
"/briefing",
|
|
"/thinking",
|
|
"/thinking/api",
|
|
"/tools",
|
|
"/tools/api/stats",
|
|
"/memory",
|
|
"/calm",
|
|
"/tasks",
|
|
"/tasks/pending",
|
|
"/tasks/active",
|
|
"/tasks/completed",
|
|
"/work-orders/queue",
|
|
"/work-orders/queue/pending",
|
|
"/work-orders/queue/active",
|
|
"/mobile",
|
|
"/mobile/status",
|
|
"/spark",
|
|
"/models",
|
|
"/api/queue/status",
|
|
"/api/tasks",
|
|
"/api/chat/history",
|
|
"/api/notifications",
|
|
"/discord/status",
|
|
"/telegram/status",
|
|
"/grok/status",
|
|
"/grok/stats",
|
|
],
|
|
)
|
|
def test_no_500(self, client, path):
|
|
r = client.get(path)
|
|
assert r.status_code != 500, f"GET {path} returned 500"
|