feat(right_arm): /home, /custom_pose, PUT /custom_pose, PUT /offset + fixture conftest
This commit is contained in:
1 parent
afbfd55bca
commit
59f7f66d77
3 files changed
+164
-1
No files matched your search
@@ -7,3 +7,29 @@ from pathlib import Path
|
||||
_SRC = Path(__file__).resolve().parent.parent / "src"
|
||||
if str(_SRC) not in sys.path:
|
||||
sys.path.insert(0, str(_SRC))
|
||||
|
||||
import pytest
|
||||
|
||||
_CFG_PATH = Path(__file__).resolve().parent.parent / "config.yaml"
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _restore_config_yaml():
|
||||
"""Snapshot/restore config.yaml + in-memory singleton.
|
||||
Any test that triggers update_config() would otherwise leave the file
|
||||
cosmetically reformatted (compact flow-style -> block-style) AND/OR
|
||||
semantically mutated. This fixture keeps the working tree clean."""
|
||||
if not _CFG_PATH.exists():
|
||||
yield
|
||||
return
|
||||
snapshot = _CFG_PATH.read_bytes()
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
_CFG_PATH.write_bytes(snapshot)
|
||||
# Reset in-memory singleton so subsequent tests re-read disk
|
||||
try:
|
||||
from presa_mano import config as _cfg_mod
|
||||
_cfg_mod._STATE["config"] = None # type: ignore[attr-defined]
|
||||
except Exception:
|
||||
pass # if internals change, we still get the disk reset
|
||||
@@ -326,3 +326,56 @@ def test_move_toward_412_when_not_g1_right():
|
||||
r = client.post("/api/right_arm/move/toward",
|
||||
json={"class_name": "pestello", "dry_run": True})
|
||||
assert r.status_code == 412
|
||||
|
||||
|
||||
def test_home_calls_wrist_absolute_with_home_pose():
|
||||
calls = []
|
||||
def _abs(**kw):
|
||||
calls.append(kw)
|
||||
return {"ok": True}
|
||||
with patch("presa_mano.api.right_arm_routes._deps.g1") as g1_f, \
|
||||
patch("presa_mano.api.right_arm_routes._deps.active_robot_key", return_value="g1"), \
|
||||
patch("presa_mano.api.right_arm_routes._deps.default_side", return_value="right"):
|
||||
g1 = MagicMock(); g1.wrist_absolute.side_effect = _abs; g1_f.return_value = g1
|
||||
r = client.post("/api/right_arm/home", json={"dry_run": True})
|
||||
assert r.status_code == 200
|
||||
assert len(calls) == 1
|
||||
assert calls[0]["side"] == "right"
|
||||
assert len(calls[0]["position"]) == 3
|
||||
assert len(calls[0]["quaternion"]) == 4
|
||||
|
||||
|
||||
def test_custom_pose_executes_pose_with_dry_run_default_false():
|
||||
calls = []
|
||||
def _abs(**kw):
|
||||
calls.append(kw); return {"ok": True}
|
||||
with patch("presa_mano.api.right_arm_routes._deps.g1") as g1_f, \
|
||||
patch("presa_mano.api.right_arm_routes._deps.active_robot_key", return_value="g1"), \
|
||||
patch("presa_mano.api.right_arm_routes._deps.default_side", return_value="right"):
|
||||
g1 = MagicMock(); g1.wrist_absolute.side_effect = _abs; g1_f.return_value = g1
|
||||
r = client.post("/api/right_arm/custom_pose", json={})
|
||||
assert r.status_code == 200
|
||||
assert len(calls) == 1
|
||||
|
||||
|
||||
def test_put_custom_pose_updates_config():
|
||||
new_pos = [0.40, -0.15, 0.25]
|
||||
new_rpy = [10.0, -5.0, 90.0]
|
||||
r = client.put("/api/right_arm/custom_pose",
|
||||
json={"position": new_pos, "rpy_deg": new_rpy})
|
||||
assert r.status_code == 200
|
||||
r2 = client.get("/api/config")
|
||||
cp = r2.json()["tab_right_arm"]["custom_pose"]
|
||||
assert cp["position"] == new_pos
|
||||
assert cp["rpy_deg"] == new_rpy
|
||||
|
||||
|
||||
def test_put_offset_updates_config():
|
||||
r = client.put("/api/right_arm/offset",
|
||||
json={"move_offset_camera_mm": {"x": 5, "y": -3, "z": 75},
|
||||
"axis_sign_cam_to_wrist": {"x": -1, "y": 1, "z": -1}})
|
||||
assert r.status_code == 200
|
||||
r2 = client.get("/api/config")
|
||||
body = r2.json()["tab_right_arm"]
|
||||
assert body["move_offset_camera_mm"] == {"x": 5, "y": -3, "z": 75}
|
||||
assert body["axis_sign_cam_to_wrist"] == {"x": -1, "y": 1, "z": -1}
|
||||
Reference in new issue
Block a user