Files
Timmy-time-dashboard/tests/test_dashboard_routes.py
Alexspayne f9b84c1e2f feat: Mission Control v2 — swarm, L402, voice, marketplace, React dashboard
Major expansion of the Timmy Time Dashboard:

Backend modules:
- Swarm subsystem: registry, manager, bidder, coordinator, agent_runner, swarm_node, tasks, comms
- L402/Lightning: payment_handler, l402_proxy with HMAC macaroons
- Voice NLU: regex-based intent detection (chat, status, swarm, task, help, voice)
- Notifications: push notifier for swarm events
- Shortcuts: Siri Shortcuts iOS integration endpoints
- WebSocket: live dashboard event manager
- Inter-agent: agent-to-agent messaging layer

Dashboard routes:
- /swarm/* — swarm management and agent registry
- /marketplace — agent catalog with sat pricing
- /voice/* — voice command processing
- /mobile — mobile status endpoint
- /swarm/live — WebSocket live feed

React web dashboard (dashboard-web/):
- Sovereign Terminal design — dark theme with Bitcoin orange accents
- Three-column layout: status sidebar, workspace tabs, context panel
- Chat, Swarm, Tasks, Marketplace tab views
- JetBrains Mono typography, terminal aesthetic
- Framer Motion animations throughout

Tests: 228 passing (expanded from 93)
Includes Kimi's additional templates and QA work.
2026-02-21 12:57:38 -05:00

165 lines
5.5 KiB
Python

"""Tests for new dashboard routes: swarm, marketplace, voice, mobile, shortcuts."""
import tempfile
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from fastapi.testclient import TestClient
@pytest.fixture(autouse=True)
def tmp_swarm_db(tmp_path, monkeypatch):
"""Point swarm SQLite to a temp directory for test isolation."""
db_path = tmp_path / "swarm.db"
monkeypatch.setattr("swarm.tasks.DB_PATH", db_path)
monkeypatch.setattr("swarm.registry.DB_PATH", db_path)
yield db_path
@pytest.fixture
def client():
from dashboard.app import app
with TestClient(app) as c:
yield c
# ── Swarm routes ─────────────────────────────────────────────────────────────
def test_swarm_status(client):
response = client.get("/swarm")
assert response.status_code == 200
data = response.json()
assert "agents" in data
assert "tasks_total" in data
def test_swarm_list_agents(client):
response = client.get("/swarm/agents")
assert response.status_code == 200
assert "agents" in response.json()
def test_swarm_spawn_agent(client):
response = client.post("/swarm/spawn", data={"name": "TestBot"})
assert response.status_code == 200
data = response.json()
assert data["name"] == "TestBot"
assert "agent_id" in data
def test_swarm_list_tasks(client):
response = client.get("/swarm/tasks")
assert response.status_code == 200
assert "tasks" in response.json()
def test_swarm_post_task(client):
response = client.post("/swarm/tasks", data={"description": "Research Bitcoin"})
assert response.status_code == 200
data = response.json()
assert data["description"] == "Research Bitcoin"
assert data["status"] == "bidding"
def test_swarm_get_task(client):
# Create a task first
create_resp = client.post("/swarm/tasks", data={"description": "Find me"})
task_id = create_resp.json()["task_id"]
# Retrieve it
response = client.get(f"/swarm/tasks/{task_id}")
assert response.status_code == 200
assert response.json()["description"] == "Find me"
def test_swarm_get_task_not_found(client):
response = client.get("/swarm/tasks/nonexistent")
assert response.status_code == 200
assert "error" in response.json()
# ── Marketplace routes ───────────────────────────────────────────────────────
def test_marketplace_list(client):
response = client.get("/marketplace")
assert response.status_code == 200
data = response.json()
assert "agents" in data
assert data["total"] >= 7 # Timmy + 6 planned personas
def test_marketplace_has_timmy(client):
response = client.get("/marketplace")
agents = response.json()["agents"]
timmy = next((a for a in agents if a["id"] == "timmy"), None)
assert timmy is not None
assert timmy["status"] == "active"
assert timmy["rate_sats"] == 0
def test_marketplace_has_planned_agents(client):
response = client.get("/marketplace")
data = response.json()
assert data["planned_count"] >= 6
def test_marketplace_agent_detail(client):
response = client.get("/marketplace/echo")
assert response.status_code == 200
assert response.json()["name"] == "Echo"
def test_marketplace_agent_not_found(client):
response = client.get("/marketplace/nonexistent")
assert response.status_code == 200
assert "error" in response.json()
# ── Voice routes ─────────────────────────────────────────────────────────────
def test_voice_nlu(client):
response = client.post("/voice/nlu", data={"text": "What is your status?"})
assert response.status_code == 200
data = response.json()
assert data["intent"] == "status"
assert data["confidence"] >= 0.8
def test_voice_nlu_chat_fallback(client):
response = client.post("/voice/nlu", data={"text": "Tell me about Bitcoin"})
assert response.status_code == 200
assert response.json()["intent"] == "chat"
def test_voice_tts_status(client):
response = client.get("/voice/tts/status")
assert response.status_code == 200
assert "available" in response.json()
# ── Mobile routes ────────────────────────────────────────────────────────────
def test_mobile_dashboard(client):
response = client.get("/mobile")
assert response.status_code == 200
assert "TIMMY TIME" in response.text
def test_mobile_status(client):
with patch("dashboard.routes.health.check_ollama", new_callable=AsyncMock, return_value=True):
response = client.get("/mobile/status")
assert response.status_code == 200
data = response.json()
assert data["agent"] == "timmy"
assert data["ready"] is True
# ── Shortcuts route ──────────────────────────────────────────────────────────
def test_shortcuts_setup(client):
response = client.get("/shortcuts/setup")
assert response.status_code == 200
data = response.json()
assert "title" in data
assert "actions" in data
assert len(data["actions"]) >= 4