This commit is contained in:
TJY
2026-07-16 08:31:52 +08:00
commit 8590fafac1
34 changed files with 2611 additions and 0 deletions
+42
View File
@@ -0,0 +1,42 @@
from fastapi.testclient import TestClient
from led_platform.main import app
def test_bootstrap_returns_tile_scene_and_timing_data():
client = TestClient(app)
response = client.get("/api/bootstrap/left")
assert response.status_code == 200
data = response.json()
assert data["tile"]["id"] == "left"
assert data["state"]["active_view"]
assert data["server_time_ms"] > 0
def test_switch_scene_returns_scheduled_commit_payload():
client = TestClient(app)
response = client.post("/api/scenes/energy/switch")
assert response.status_code == 200
data = response.json()
assert data["state"]["active_scene_id"] == "energy"
assert data["state"]["active_view"] == "energy"
assert data["apply_at_ms"] > data["server_time_ms"]
def test_action_rejects_unsupported_action():
client = TestClient(app)
response = client.post("/api/actions", json={"action": "eval.anything"})
assert response.status_code == 400
def test_sync_status_endpoint_exposes_commands_and_nodes():
client = TestClient(app)
response = client.get("/api/sync/status")
assert response.status_code == 200
data = response.json()
assert "nodes" in data
assert "commands" in data
+54
View File
@@ -0,0 +1,54 @@
from led_platform.domain import CommandEnvelope, CommandType, PerformanceSample
from led_platform.services.sync_coordinator import SyncCoordinator
def test_sync_coordinator_marks_command_complete_after_both_tiles_ack():
coordinator = SyncCoordinator(["left", "right"], command_ttl_seconds=30)
message = CommandEnvelope(
type=CommandType.COMMIT_SCENE,
payload={"apply_at_ms": 2000, "state": {"active_scene_id": "overview"}},
)
record = coordinator.register_command(message, message.payload)
assert not record.complete
coordinator.ack(
{
"command_id": message.command_id,
"node_id": "left-node",
"tile_id": "left",
"status": "committed",
}
)
assert not coordinator.status()["commands"][0]["complete"]
coordinator.ack(
{
"command_id": message.command_id,
"node_id": "right-node",
"tile_id": "right",
"status": "committed",
}
)
assert coordinator.status()["commands"][0]["complete"]
def test_sync_coordinator_tracks_node_clock_and_frame_metrics():
coordinator = SyncCoordinator(["left", "right"], command_ttl_seconds=30)
coordinator.connect_node(node_id="left-node", tile_id="left", app_version="test")
coordinator.clock_quality("left-node", clock_offset_ms=2.5, rtt_ms=6.0)
coordinator.telemetry(
PerformanceSample(
node_id="left-node",
tile_id="left",
fps=59.4,
frame_time_ms=16.1,
dropped_frames=1,
)
)
node = coordinator.status()["nodes"][0]
assert node["clock_offset_ms"] == 2.5
assert node["rtt_ms"] == 6.0
assert node["fps"] == 59.4
assert node["frame_time_ms"] == 16.1
+27
View File
@@ -0,0 +1,27 @@
from pathlib import Path
from led_platform.services.tile_store import TileStore
def test_tiles_cover_wall_as_two_half_width_servers():
store = TileStore(Path("config/tiles.json"), wall_width=14880, wall_height=3510)
left = store.get("left")
right = store.get("right")
assert left.x == 0
assert left.width == 7440
assert right.x == 7440
assert right.width == 7440
assert left.right == right.x
assert right.right == 14880
def test_each_server_has_four_4k_physical_outputs():
store = TileStore(Path("config/tiles.json"), wall_width=14880, wall_height=3510)
for tile in store.all():
assert tile.desktop_width == 7680
assert tile.desktop_height == 4320
assert len(tile.physical_outputs) == 4
assert all(output.width == 3840 for output in tile.physical_outputs)
assert all(output.height == 2160 for output in tile.physical_outputs)