Plan 3: state machine (IDLE -> WAKE_PENDING -> LISTENING <-> ASSISTANT_SPEAKING -> IDLE_PENDING -> IDLE)

This commit is contained in:
2026-06-11 22:47:23 +00:00
parent 908e3f4907
commit d75129c4f9
2 changed files with 172 additions and 0 deletions
+102
View File
@@ -0,0 +1,102 @@
from client.state import State, StateMachine
def test_starts_idle_with_wakeword_enabled_and_uplink_disabled():
sm = StateMachine()
assert sm.state is State.IDLE
assert sm.wakeword_enabled
assert not sm.uplink_enabled
def test_wake_fired_goes_idle_to_wake_pending_and_disables_wakeword():
sm = StateMachine()
assert sm.wake_fired() is True
assert sm.state is State.WAKE_PENDING
assert not sm.wakeword_enabled
assert not sm.uplink_enabled
def test_wake_fired_is_idempotent_when_not_idle():
sm = StateMachine()
sm.wake_fired()
assert sm.wake_fired() is False
assert sm.state is State.WAKE_PENDING
def test_session_started_goes_wake_pending_to_listening_and_unmutes_uplink():
sm = StateMachine()
sm.wake_fired()
sm.session_started()
assert sm.state is State.LISTENING
assert sm.uplink_enabled
assert not sm.wakeword_enabled
def test_assistant_audio_arrived_mutes_uplink():
sm = StateMachine()
sm.wake_fired()
sm.session_started()
sm.assistant_audio_arrived()
assert sm.state is State.ASSISTANT_SPEAKING
assert not sm.uplink_enabled
def test_assistant_audio_arrived_is_noop_outside_listening():
sm = StateMachine()
sm.assistant_audio_arrived()
assert sm.state is State.IDLE # ignored from IDLE
sm.wake_fired()
sm.assistant_audio_arrived()
assert sm.state is State.WAKE_PENDING # ignored from WAKE_PENDING
def test_assistant_done_returns_to_listening_from_speaking():
sm = StateMachine()
sm.wake_fired()
sm.session_started()
sm.assistant_audio_arrived()
sm.assistant_done()
assert sm.state is State.LISTENING
assert sm.uplink_enabled
def test_assistant_done_is_noop_when_not_speaking():
sm = StateMachine()
sm.wake_fired()
sm.session_started() # LISTENING; never went to ASSISTANT_SPEAKING
sm.assistant_done()
assert sm.state is State.LISTENING
def test_session_ended_routes_through_idle_pending_then_idle():
sm = StateMachine()
sm.wake_fired()
sm.session_started()
sm.session_ended()
assert sm.state is State.IDLE_PENDING
assert not sm.wakeword_enabled
assert not sm.uplink_enabled
sm.sleep_played()
assert sm.state is State.IDLE
assert sm.wakeword_enabled
def test_session_ended_works_from_assistant_speaking():
sm = StateMachine()
sm.wake_fired()
sm.session_started()
sm.assistant_audio_arrived()
sm.session_ended()
assert sm.state is State.IDLE_PENDING
def test_session_ended_from_idle_is_noop():
sm = StateMachine()
sm.session_ended()
assert sm.state is State.IDLE
def test_sleep_played_outside_idle_pending_is_noop():
sm = StateMachine()
sm.sleep_played()
assert sm.state is State.IDLE