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.
165 lines
5.5 KiB
Python
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
|