Files
openswarm/backend/tests/test_api_dashboards.py
T

157 lines
4.9 KiB
Python

"""CRUD smoke for /api/dashboards.
Dashboards are the spatial canvas units. Each holds a `DashboardLayout`
(positions for agent/view/browser cards + sticky notes). Sessions are
tagged with `dashboard_id` so deleting a dashboard cascades into its
sessions.
Tests:
- lifespan migration creates "Dashboard 1" on a fresh boot
- create / get / update (name + layout) / duplicate / delete round-trip
- delete cascades into SESSIONS_DIR (sessions tagged with the
dashboard id are removed from disk)
- seed-demo lays down a session JSON with two messages
"""
from __future__ import annotations
import json
import os
def test_lifespan_seeds_default_dashboard(client):
"""First boot with no existing dashboards creates 'Dashboard 1'."""
resp = client.get("/api/dashboards/list")
assert resp.status_code == 200
items = resp.json()["dashboards"]
assert len(items) >= 1
assert any(d["name"] == "Dashboard 1" for d in items)
def test_create_get_update_delete_dashboard(client):
create = client.post(
"/api/dashboards/create",
json={"name": "Project Alpha"},
)
assert create.status_code == 200
dashboard_id = create.json()["id"]
fetched = client.get(f"/api/dashboards/{dashboard_id}")
assert fetched.status_code == 200
assert fetched.json()["name"] == "Project Alpha"
# Renaming flips auto_named → False (per dashboards.py:275).
update = client.put(
f"/api/dashboards/{dashboard_id}",
json={"name": "Project Beta"},
)
assert update.status_code == 200
body = update.json()
assert body["name"] == "Project Beta"
assert body["auto_named"] is False
deleted = client.delete(f"/api/dashboards/{dashboard_id}")
assert deleted.status_code == 200
gone = client.get(f"/api/dashboards/{dashboard_id}")
assert gone.status_code == 404
def test_dashboard_layout_round_trip(client):
"""PUT layout with a sticky note and assert it survives a re-fetch."""
create = client.post("/api/dashboards/create", json={"name": "L"})
dashboard_id = create.json()["id"]
layout = {
"cards": {},
"view_cards": {},
"browser_cards": {},
"notes": {
"n1": {
"note_id": "n1",
"x": 100,
"y": 200,
"width": 240,
"height": 200,
"content": "test note",
"color": "yellow",
}
},
"expanded_session_ids": [],
}
resp = client.put(
f"/api/dashboards/{dashboard_id}",
json={"layout": layout},
)
assert resp.status_code == 200
refetched = client.get(f"/api/dashboards/{dashboard_id}")
assert refetched.json()["layout"]["notes"]["n1"]["content"] == "test note"
def test_duplicate_dashboard(client):
create = client.post("/api/dashboards/create", json={"name": "Source"})
dashboard_id = create.json()["id"]
dup = client.post(f"/api/dashboards/{dashboard_id}/duplicate")
assert dup.status_code == 200
body = dup.json()
assert body["id"] != dashboard_id
assert body["name"] == "Source (copy)"
def test_delete_dashboard_cascades_to_sessions(client):
"""Sessions tagged with dashboard_id must be removed on delete.
Drops a fake session file straight onto SESSIONS_DIR (no agent
spawn needed) and verifies the cascade in `delete_dashboard`.
"""
from backend.config.paths import SESSIONS_DIR
create = client.post("/api/dashboards/create", json={"name": "Cascade"})
dashboard_id = create.json()["id"]
os.makedirs(SESSIONS_DIR, exist_ok=True)
session_id = "fake-session-cascade"
session_path = os.path.join(SESSIONS_DIR, f"{session_id}.json")
with open(session_path, "w") as f:
json.dump(
{
"id": session_id,
"name": "junk",
"dashboard_id": dashboard_id,
"messages": [],
"branches": {},
"active_branch_id": "main",
"created_at": "2026-01-01T00:00:00",
},
f,
)
assert os.path.exists(session_path)
deleted = client.delete(f"/api/dashboards/{dashboard_id}")
assert deleted.status_code == 200
assert not os.path.exists(session_path), (
"session file tagged with deleted dashboard should be removed"
)
def test_seed_demo_creates_session(client):
from backend.config.paths import SESSIONS_DIR
create = client.post("/api/dashboards/create", json={"name": "Demo"})
dashboard_id = create.json()["id"]
resp = client.post(f"/api/dashboards/{dashboard_id}/seed-demo")
assert resp.status_code == 200
session_id = resp.json()["session_id"]
session_path = os.path.join(SESSIONS_DIR, f"{session_id}.json")
assert os.path.exists(session_path)
with open(session_path) as f:
data = json.load(f)
assert data["dashboard_id"] == dashboard_id
assert len(data["messages"]) == 2 # canned welcome conversation