RemiFabre commited on
Commit
c63359c
·
1 Parent(s): ae5d968

Add audio playback test to hardware suite

Browse files

Split 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.

Files changed (3) hide show
  1. TESTING.md +1 -1
  2. tests/run_tests.py +1 -1
  3. 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 | 2 | Playback completes and returns to idle |
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 completes and returns to idle"),
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 test_playback_completes(self, base_url: str):
188
- """Play back a recorded move, verify mode returns to idle."""
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
- moves = state["moves"]
194
- assert len(moves) > 0, "No moves available for playback test"
195
 
196
- move_id = moves[0]["id"]
197
- duration = moves[0]["duration"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
198
 
199
  resp = httpx.post(
200
  f"{base_url}/api/play",
201
- json={"move_id": move_id},
202
  timeout=5,
203
  )
204
  assert resp.status_code == 200
205
 
206
- # Wait for playback to complete (duration + buffer)
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."""