Files
led-controller/tests/test_audio_reset_tracking.py
Jimmy ace5770b3a refactor(api): complete fastapi migration and related features
Finish native FastAPI controllers, drop vendored microdot, and add
Wi-Fi driver runtime, beat SSE, simulated BPM, sequence playback
improvements, bridge ESP-NOW sources, UI updates, and tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-11 22:55:28 +12:00

150 lines
4.3 KiB
Python

"""Reset detector must not stop the stream or clear ``running``."""
import os
import sys
import time
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SRC_PATH = os.path.join(PROJECT_ROOT, "src")
if SRC_PATH not in sys.path:
sys.path.insert(0, SRC_PATH)
from util.audio_detector import ( # noqa: E402
AudioBeatDetector,
set_shared_beat_detector,
shared_beat_detector_timing_sequences,
)
class _FakeRuntime:
def __init__(self):
self.reset_calls = 0
def reset_state(self):
self.reset_calls += 1
def test_reset_tracking_false_when_not_running():
det = AudioBeatDetector()
assert det.reset_tracking() is False
def test_reset_tracking_queues_on_audio_thread():
det = AudioBeatDetector()
rt = _FakeRuntime()
with det._lock:
det._running = True
det._runtime = rt
det._status["running"] = True
det._status["bpm"] = 128.0
det._status["beat_seq"] = 7
assert det.reset_tracking() is True
assert rt.reset_calls == 0
assert det._pending_reset is True
st = det.status()
assert st["running"] is True
assert st["bpm"] == 128.0
assert st["beat_seq"] == 7
det._process_pending_reset(rt)
assert rt.reset_calls == 1
assert det._pending_reset is False
assert det.status()["running"] is True
def test_status_keeps_bpm_during_holdover():
det = AudioBeatDetector()
with det._lock:
det._running = True
det._holdover_active = True
det._status["running"] = True
det._status["bpm"] = 128.0
det._status["last_beat_ts"] = time.time() - 10.0
assert det.status()["bpm"] == 128.0
class _FakeRuntimeGap:
def __init__(self):
self.reset_tempo_calls = 0
def reset_tempo_state(self):
self.reset_tempo_calls += 1
def test_silence_gap_starts_holdover_and_resets_tempo_once():
det = AudioBeatDetector()
rt = _FakeRuntimeGap()
with det._lock:
det._running = True
det._status["running"] = True
det._status["bpm"] = 120.0
det._last_real_beat_ts = time.time() - 10.0
det._maybe_recover_after_silence_gap(rt)
assert rt.reset_tempo_calls == 1
assert det._holdover_active is True
det._maybe_recover_after_silence_gap(rt)
assert rt.reset_tempo_calls == 1
det._record_beat(120.0)
assert det._holdover_active is True
def test_timing_sequences_true_while_holdover_active():
det = AudioBeatDetector()
set_shared_beat_detector(det)
try:
with det._lock:
det._running = True
det._status["running"] = True
det._status["bpm"] = 120.0
det._record_beat(120.0)
assert det._holdover_active is True
assert shared_beat_detector_timing_sequences() is True
finally:
set_shared_beat_detector(None)
def test_timing_sequences_false_when_running_without_beats():
det = AudioBeatDetector()
set_shared_beat_detector(det)
try:
with det._lock:
det._running = True
det._status["running"] = True
assert shared_beat_detector_timing_sequences() is False
det._record_beat(120.0)
assert shared_beat_detector_timing_sequences() is True
det._stop_bpm_holdover()
with det._lock:
det._last_real_beat_ts = time.time() - 5.0
assert shared_beat_detector_timing_sequences() is False
finally:
set_shared_beat_detector(None)
def test_record_beat_keeps_previous_bpm_when_new_readout_invalid():
det = AudioBeatDetector()
det._record_beat(128.0)
det._record_beat(None)
assert det.status()["bpm"] == 128.0
def test_holdover_last_beat_does_not_block_tempo_retry():
"""Holdover refreshes last_beat_ts but recovery uses last real beat only."""
det = AudioBeatDetector()
rt = _FakeRuntimeGap()
with det._lock:
det._running = True
det._status["running"] = True
det._status["bpm"] = 120.0
det._last_real_beat_ts = time.time() - 10.0
det._maybe_recover_after_silence_gap(rt)
assert rt.reset_tempo_calls == 1
with det._lock:
det._status["last_beat_ts"] = time.time()
det._last_gap_tempo_reset_ts = time.time() - 10.0
det._maybe_recover_after_silence_gap(rt)
assert rt.reset_tempo_calls == 2
assert det._holdover_active is True