Spaces:
Running
Running
RemiFabre commited on
Commit ·
c63359c
1
Parent(s): ae5d968
Add audio playback test to hardware suite
Browse filesSplit test_playback_completes into test_playback_silent_completes and
test_playback_with_audio_completes so the sound replay path through
reachy_mini.media.play_sound() is exercised during hardware testing.
- TESTING.md +1 -1
- tests/run_tests.py +1 -1
- tests/test_hardware.py +30 -10
TESTING.md
CHANGED
|
@@ -123,7 +123,7 @@ pytest tests/ --browser chromium
|
|
| 123 |
|-------|------:|-------------|
|
| 124 |
| TestHardwareStartup | 1 | Robot reaches idle after startup |
|
| 125 |
| TestHardwareRecording | 2 | Record and verify motion capture |
|
| 126 |
-
| TestHardwarePlayback |
|
| 127 |
|
| 128 |
## View the matrix without running tests
|
| 129 |
|
|
|
|
| 123 |
|-------|------:|-------------|
|
| 124 |
| TestHardwareStartup | 1 | Robot reaches idle after startup |
|
| 125 |
| TestHardwareRecording | 2 | Record and verify motion capture |
|
| 126 |
+
| TestHardwarePlayback | 3 | Playback with and without audio |
|
| 127 |
|
| 128 |
## View the matrix without running tests
|
| 129 |
|
tests/run_tests.py
CHANGED
|
@@ -57,7 +57,7 @@ TEST_CLASS_DESCRIPTIONS: dict[str, tuple[str, str]] = {
|
|
| 57 |
# Hardware
|
| 58 |
"TestHardwareStartup": ("hardware", "Robot reaches idle after startup"),
|
| 59 |
"TestHardwareRecording": ("hardware", "Record and verify motion capture"),
|
| 60 |
-
"TestHardwarePlayback": ("hardware", "Playback
|
| 61 |
}
|
| 62 |
|
| 63 |
|
|
|
|
| 57 |
# Hardware
|
| 58 |
"TestHardwareStartup": ("hardware", "Robot reaches idle after startup"),
|
| 59 |
"TestHardwareRecording": ("hardware", "Record and verify motion capture"),
|
| 60 |
+
"TestHardwarePlayback": ("hardware", "Playback with and without audio"),
|
| 61 |
}
|
| 62 |
|
| 63 |
|
tests/test_hardware.py
CHANGED
|
@@ -184,30 +184,50 @@ class TestHardwareRecording:
|
|
| 184 |
|
| 185 |
|
| 186 |
class TestHardwarePlayback:
|
| 187 |
-
def
|
| 188 |
-
"""Play back a
|
| 189 |
import httpx
|
| 190 |
|
| 191 |
-
# Ensure we have at least one move to play
|
| 192 |
state = httpx.get(f"{base_url}/api/state", timeout=5).json()
|
| 193 |
-
|
| 194 |
-
assert
|
| 195 |
|
| 196 |
-
|
| 197 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 198 |
|
| 199 |
resp = httpx.post(
|
| 200 |
f"{base_url}/api/play",
|
| 201 |
-
json={"move_id":
|
| 202 |
timeout=5,
|
| 203 |
)
|
| 204 |
assert resp.status_code == 200
|
| 205 |
|
| 206 |
-
|
| 207 |
-
_wait_for_mode(base_url, "idle", timeout=duration + 15)
|
| 208 |
|
| 209 |
state = httpx.get(f"{base_url}/api/state", timeout=5).json()
|
| 210 |
assert state["mode"] == "idle"
|
|
|
|
|
|
|
|
|
|
| 211 |
|
| 212 |
def test_record_and_delete(self, base_url: str):
|
| 213 |
"""Record a move, then delete it and verify file is removed."""
|
|
|
|
| 184 |
|
| 185 |
|
| 186 |
class TestHardwarePlayback:
|
| 187 |
+
def test_playback_silent_completes(self, base_url: str):
|
| 188 |
+
"""Play back a silent move, verify mode returns to idle."""
|
| 189 |
import httpx
|
| 190 |
|
|
|
|
| 191 |
state = httpx.get(f"{base_url}/api/state", timeout=5).json()
|
| 192 |
+
move = next((m for m in state["moves"] if not m["has_audio"]), None)
|
| 193 |
+
assert move is not None, "No silent move available for playback test"
|
| 194 |
|
| 195 |
+
resp = httpx.post(
|
| 196 |
+
f"{base_url}/api/play",
|
| 197 |
+
json={"move_id": move["id"]},
|
| 198 |
+
timeout=5,
|
| 199 |
+
)
|
| 200 |
+
assert resp.status_code == 200
|
| 201 |
+
|
| 202 |
+
_wait_for_mode(base_url, "idle", timeout=move["duration"] + 15)
|
| 203 |
+
|
| 204 |
+
state = httpx.get(f"{base_url}/api/state", timeout=5).json()
|
| 205 |
+
assert state["mode"] == "idle"
|
| 206 |
+
|
| 207 |
+
def test_playback_with_audio_completes(self, base_url: str):
|
| 208 |
+
"""Play back a move that has audio, verify sound path is exercised."""
|
| 209 |
+
import httpx
|
| 210 |
+
|
| 211 |
+
state = httpx.get(f"{base_url}/api/state", timeout=5).json()
|
| 212 |
+
move = next((m for m in state["moves"] if m["has_audio"]), None)
|
| 213 |
+
assert move is not None, (
|
| 214 |
+
"No audio move available — test_record_with_audio must run first"
|
| 215 |
+
)
|
| 216 |
|
| 217 |
resp = httpx.post(
|
| 218 |
f"{base_url}/api/play",
|
| 219 |
+
json={"move_id": move["id"]},
|
| 220 |
timeout=5,
|
| 221 |
)
|
| 222 |
assert resp.status_code == 200
|
| 223 |
|
| 224 |
+
_wait_for_mode(base_url, "idle", timeout=move["duration"] + 15)
|
|
|
|
| 225 |
|
| 226 |
state = httpx.get(f"{base_url}/api/state", timeout=5).json()
|
| 227 |
assert state["mode"] == "idle"
|
| 228 |
+
assert "finished" in state["message"].lower(), (
|
| 229 |
+
f"Expected 'Finished playing' message, got: {state['message']}"
|
| 230 |
+
)
|
| 231 |
|
| 232 |
def test_record_and_delete(self, base_url: str):
|
| 233 |
"""Record a move, then delete it and verify file is removed."""
|