"""Integration test del router /api/right_arm/*.""" from __future__ import annotations from unittest.mock import patch, MagicMock from fastapi.testclient import TestClient from presa_mano.main import app client = TestClient(app) def _fake_wrist_response(): return { "left_wrist": {"position": [0.10, 0.20, 0.30], "quaternion": [0, 0, 0, 1]}, "right_wrist": {"position": [0.30, -0.20, 0.30], "quaternion": [0, 0, 0, 1]}, } def test_state_returns_wrist_pose_and_config(): with patch("presa_mano.api.right_arm_routes._deps.g1") as g1_factory: g1 = MagicMock() g1.wrist.return_value = _fake_wrist_response() g1_factory.return_value = g1 r = client.get("/api/right_arm/state") assert r.status_code == 200 body = r.json() assert body["wrist"]["position"] == [0.30, -0.20, 0.30] assert "rpy_deg" in body["wrist"] assert body["side"] == "right" or body["side"] in ("left", "right") assert "home_pose" in body assert "custom_pose" in body assert "offset_camera_mm" in body assert "axis_signs" in body assert "max_step_m" in body assert "z_floor_m" in body assert "robot_active" in body assert "timings_ms" in body def test_state_502_when_g1_unavailable(): from presa_mano.clients import G1Unavailable with patch("presa_mano.api.right_arm_routes._deps.g1") as g1_factory: g1 = MagicMock() g1.wrist.side_effect = G1Unavailable("connection refused") g1_factory.return_value = g1 r = client.get("/api/right_arm/state") assert r.status_code == 502 def test_activate_sets_robot_active_g1_and_side_right(): # /activate รจ idempotente: chiama PUT /api/config e ritorna /state with patch("presa_mano.api.right_arm_routes._deps.g1") as g1_factory: g1 = MagicMock() g1.wrist.return_value = _fake_wrist_response() g1_factory.return_value = g1 r = client.post("/api/right_arm/activate") assert r.status_code == 200 body = r.json() assert body["robot_active"] == "g1" assert body["side"] == "right" def test_snapshot_front_returns_jpeg(): fake_jpeg = b"\xff\xd8\xff" + b"\x00" * 100 # magic JPEG bytes with patch("presa_mano.api.right_arm_routes._deps.front_camera") as factory: cam = MagicMock() cam.rgb_jpeg.return_value = fake_jpeg factory.return_value = cam r = client.get("/api/right_arm/snapshot/front") assert r.status_code == 200 assert r.headers["content-type"].startswith("image/jpeg") assert r.content == fake_jpeg def test_snapshot_wrist_returns_jpeg(): fake_jpeg = b"\xff\xd8\xff" + b"\x00" * 50 with patch("presa_mano.api.right_arm_routes._deps.nuwa") as factory: cam = MagicMock() cam.rgb_jpeg.return_value = fake_jpeg factory.return_value = cam r = client.get("/api/right_arm/snapshot/wrist") assert r.status_code == 200 assert r.headers["content-type"].startswith("image/jpeg") assert r.content == fake_jpeg def test_snapshot_front_502_on_failure(): with patch("presa_mano.api.right_arm_routes._deps.front_camera") as factory: cam = MagicMock() cam.rgb_jpeg.side_effect = RuntimeError("connection refused") factory.return_value = cam r = client.get("/api/right_arm/snapshot/front") assert r.status_code == 502