test: add first unit test for VAD agent
Mocking audio input probabilities, checking whether it publishes audio data on the output socket. ref: N25B-213
This commit is contained in:
45
test/unit/agents/test_vad_streaming.py
Normal file
45
test/unit/agents/test_vad_streaming.py
Normal file
@@ -0,0 +1,45 @@
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from control_backend.agents.vad_agent import Streaming
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def audio_in_socket():
|
||||
return AsyncMock()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def audio_out_socket():
|
||||
return AsyncMock()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def streaming(audio_in_socket, audio_out_socket):
|
||||
return Streaming(audio_in_socket, audio_out_socket)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_voice_activity_detected(audio_in_socket, audio_out_socket, streaming):
|
||||
# After three chunks of audio with speech probability of 1.0, then four chunks of audio with
|
||||
# speech probability of 0.0, it should send a message over the audio out socket
|
||||
probabilities = [1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0]
|
||||
model_item = MagicMock()
|
||||
model_item.item.side_effect = probabilities
|
||||
streaming.model = MagicMock()
|
||||
streaming.model.return_value = model_item
|
||||
|
||||
audio_in_poller = AsyncMock()
|
||||
audio_in_poller.poll.return_value = np.empty(shape=512, dtype=np.float32)
|
||||
streaming.audio_in_poller = audio_in_poller
|
||||
|
||||
for _ in probabilities:
|
||||
await streaming.run()
|
||||
|
||||
audio_out_socket.send.assert_called_once()
|
||||
data = audio_out_socket.send.call_args[0][0]
|
||||
assert isinstance(data, bytes)
|
||||
# each sample has 512 frames of 4 bytes, expecting 5 chunks (3 with speech, 2 as padding)
|
||||
assert len(data) == 512*4*5
|
||||
37
test/unit/conftest.py
Normal file
37
test/unit/conftest.py
Normal file
@@ -0,0 +1,37 @@
|
||||
import sys
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import sys
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
def pytest_configure(config):
|
||||
"""
|
||||
This hook runs at the start of the pytest session, before any tests are
|
||||
collected. It mocks heavy or unavailable modules to prevent ImportErrors.
|
||||
"""
|
||||
# --- Mock spade and spade-bdi ---
|
||||
mock_spade = MagicMock()
|
||||
mock_spade.agent = MagicMock()
|
||||
mock_spade.behaviour = MagicMock()
|
||||
mock_spade_bdi = MagicMock()
|
||||
mock_spade_bdi.bdi = MagicMock()
|
||||
|
||||
mock_spade.agent.Message = MagicMock()
|
||||
mock_spade.behaviour.CyclicBehaviour = type('CyclicBehaviour', (object,), {})
|
||||
mock_spade_bdi.bdi.BDIAgent = type('BDIAgent', (object,), {})
|
||||
|
||||
sys.modules['spade'] = mock_spade
|
||||
sys.modules['spade.agent'] = mock_spade.agent
|
||||
sys.modules['spade.behaviour'] = mock_spade.behaviour
|
||||
sys.modules['spade_bdi'] = mock_spade_bdi
|
||||
sys.modules['spade_bdi.bdi'] = mock_spade_bdi.bdi
|
||||
|
||||
# --- Mock the config module to prevent Pydantic ImportError ---
|
||||
mock_config_module = MagicMock()
|
||||
|
||||
# The code under test does `from ... import settings`, so our mock module
|
||||
# must have a `settings` attribute. We'll make it a MagicMock so we can
|
||||
# configure it later in our tests using mocker.patch.
|
||||
mock_config_module.settings = MagicMock()
|
||||
|
||||
sys.modules['control_backend.core.config'] = mock_config_module
|
||||
Reference in New Issue
Block a user