tests: add some initial run_test() utilities
This commit is contained in:
2
.github/workflows/tests.yaml
vendored
2
.github/workflows/tests.yaml
vendored
@@ -49,4 +49,4 @@ jobs:
|
|||||||
- name: Test with pytest
|
- name: Test with pytest
|
||||||
run: |
|
run: |
|
||||||
source .venv/bin/activate
|
source .venv/bin/activate
|
||||||
pytest --ignore-glob="*to_be_updated*" --ignore-glob=*pipeline_source* src tests
|
pytest
|
||||||
|
|||||||
@@ -53,12 +53,6 @@ To keep things lightweight, only the core framework is included by default. If y
|
|||||||
pip install "pipecat-ai[option,...]"
|
pip install "pipecat-ai[option,...]"
|
||||||
```
|
```
|
||||||
|
|
||||||
Or you can install all of them with:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
pip install "pipecat-ai[all]"
|
|
||||||
```
|
|
||||||
|
|
||||||
Available options include:
|
Available options include:
|
||||||
|
|
||||||
| Category | Services | Install Command Example |
|
| Category | Services | Install Command Example |
|
||||||
@@ -195,7 +189,7 @@ pip install "path_to_this_repo[option,...]"
|
|||||||
From the root directory, run:
|
From the root directory, run:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
pytest --doctest-modules --ignore-glob="*to_be_updated*" --ignore-glob=*pipeline_source* src tests
|
pytest
|
||||||
```
|
```
|
||||||
|
|
||||||
## Setting up your editor
|
## Setting up your editor
|
||||||
|
|||||||
@@ -85,7 +85,10 @@ openrouter = [ "openai~=1.59.6" ]
|
|||||||
where = ["src"]
|
where = ["src"]
|
||||||
|
|
||||||
[tool.pytest.ini_options]
|
[tool.pytest.ini_options]
|
||||||
|
addopts = "--verbose --disable-warnings"
|
||||||
|
testpaths = ["tests"]
|
||||||
pythonpath = ["src"]
|
pythonpath = ["src"]
|
||||||
|
asyncio_default_fixture_loop_scope = "function"
|
||||||
|
|
||||||
[tool.setuptools_scm]
|
[tool.setuptools_scm]
|
||||||
local_scheme = "no-local-version"
|
local_scheme = "no-local-version"
|
||||||
|
|||||||
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
@@ -1,3 +1,9 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2024-2025 Daily
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import doctest
|
import doctest
|
||||||
import functools
|
import functools
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2024-2025 Daily
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
|
#
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from typing import AsyncGenerator
|
from typing import AsyncGenerator
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2024-2025 Daily
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
|
#
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
42
tests/test_filters.py
Normal file
42
tests/test_filters.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2024-2025 Daily
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
|
#
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from pipecat.frames.frames import (
|
||||||
|
TranscriptionFrame,
|
||||||
|
UserStartedSpeakingFrame,
|
||||||
|
UserStoppedSpeakingFrame,
|
||||||
|
)
|
||||||
|
from pipecat.processors.filters.identity_filter import IdentityFilter
|
||||||
|
from pipecat.processors.filters.wake_check_filter import WakeCheckFilter
|
||||||
|
from tests.utils import run_test
|
||||||
|
|
||||||
|
|
||||||
|
class TestIdentifyFilter(unittest.IsolatedAsyncioTestCase):
|
||||||
|
async def test_identity(self):
|
||||||
|
filter = IdentityFilter()
|
||||||
|
frames_to_send = [UserStartedSpeakingFrame(), UserStoppedSpeakingFrame()]
|
||||||
|
expected_returned_frames = [UserStartedSpeakingFrame, UserStoppedSpeakingFrame]
|
||||||
|
await run_test(filter, frames_to_send, expected_returned_frames)
|
||||||
|
|
||||||
|
|
||||||
|
class TestWakeCheckFilter(unittest.IsolatedAsyncioTestCase):
|
||||||
|
async def test_no_wake_word(self):
|
||||||
|
filter = WakeCheckFilter(wake_phrases=["Hey, Pipecat"])
|
||||||
|
frames_to_send = [TranscriptionFrame(user_id="test", text="Phrase 1", timestamp="")]
|
||||||
|
expected_returned_frames = []
|
||||||
|
await run_test(filter, frames_to_send, expected_returned_frames)
|
||||||
|
|
||||||
|
async def test_wake_word(self):
|
||||||
|
filter = WakeCheckFilter(wake_phrases=["Hey, Pipecat"])
|
||||||
|
frames_to_send = [
|
||||||
|
TranscriptionFrame(user_id="test", text="Hey, Pipecat", timestamp=""),
|
||||||
|
TranscriptionFrame(user_id="test", text="Phrase 1", timestamp=""),
|
||||||
|
]
|
||||||
|
expected_returned_frames = [TranscriptionFrame, TranscriptionFrame]
|
||||||
|
(received_down, _) = await run_test(filter, frames_to_send, expected_returned_frames)
|
||||||
|
assert received_down[-1].text == "Phrase 1"
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2024-2025 Daily
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2024-2025 Daily
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import unittest
|
import unittest
|
||||||
from unittest.mock import Mock
|
from unittest.mock import Mock
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2024-2025 Daily
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
|
#
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from pipecat.frames.frames import AudioRawFrame, TextFrame, TranscriptionFrame
|
from pipecat.frames.frames import AudioRawFrame, TextFrame, TranscriptionFrame
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2024-2025 Daily
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
|
#
|
||||||
|
|
||||||
# import asyncio
|
# import asyncio
|
||||||
# import unittest
|
# import unittest
|
||||||
# from unittest.mock import AsyncMock, patch, Mock
|
# from unittest.mock import AsyncMock, patch, Mock
|
||||||
|
|||||||
96
tests/utils.py
Normal file
96
tests/utils.py
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2024-2025 Daily
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
|
#
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Sequence, Tuple
|
||||||
|
|
||||||
|
from pipecat.clocks.system_clock import SystemClock
|
||||||
|
from pipecat.frames.frames import (
|
||||||
|
ControlFrame,
|
||||||
|
Frame,
|
||||||
|
StartFrame,
|
||||||
|
)
|
||||||
|
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class EndTestFrame(ControlFrame):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class QueuedFrameProcessor(FrameProcessor):
|
||||||
|
def __init__(self, queue: asyncio.Queue, ignore_start: bool = True):
|
||||||
|
super().__init__()
|
||||||
|
self._queue = queue
|
||||||
|
self._ignore_start = ignore_start
|
||||||
|
|
||||||
|
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
||||||
|
await super().process_frame(frame, direction)
|
||||||
|
if self._ignore_start and isinstance(frame, StartFrame):
|
||||||
|
return
|
||||||
|
await self._queue.put(frame)
|
||||||
|
|
||||||
|
|
||||||
|
async def run_test(
|
||||||
|
processor: FrameProcessor,
|
||||||
|
frames_to_send: Sequence[Frame],
|
||||||
|
expected_down_frames: Sequence[type],
|
||||||
|
expected_up_frames: Sequence[type] = [],
|
||||||
|
) -> Tuple[Sequence[Frame], Sequence[Frame]]:
|
||||||
|
received_up = asyncio.Queue()
|
||||||
|
received_down = asyncio.Queue()
|
||||||
|
up_processor = QueuedFrameProcessor(received_up)
|
||||||
|
down_processor = QueuedFrameProcessor(received_down)
|
||||||
|
|
||||||
|
up_processor.link(processor)
|
||||||
|
processor.link(down_processor)
|
||||||
|
|
||||||
|
await processor.queue_frame(StartFrame(clock=SystemClock()))
|
||||||
|
|
||||||
|
for frame in frames_to_send:
|
||||||
|
await processor.process_frame(frame, FrameDirection.DOWNSTREAM)
|
||||||
|
|
||||||
|
await processor.queue_frame(EndTestFrame())
|
||||||
|
await processor.queue_frame(EndTestFrame(), FrameDirection.UPSTREAM)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Down frames
|
||||||
|
#
|
||||||
|
received_down_frames: Sequence[Frame] = []
|
||||||
|
running = True
|
||||||
|
while running:
|
||||||
|
frame = await received_down.get()
|
||||||
|
running = not isinstance(frame, EndTestFrame)
|
||||||
|
if running:
|
||||||
|
received_down_frames.append(frame)
|
||||||
|
|
||||||
|
print("received DOWN frames =", received_down_frames)
|
||||||
|
|
||||||
|
assert len(received_down_frames) == len(expected_down_frames)
|
||||||
|
|
||||||
|
for real, expected in zip(received_down_frames, expected_down_frames):
|
||||||
|
assert isinstance(real, expected)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Up frames
|
||||||
|
#
|
||||||
|
received_up_frames: Sequence[Frame] = []
|
||||||
|
running = True
|
||||||
|
while running:
|
||||||
|
frame = await received_up.get()
|
||||||
|
running = not isinstance(frame, EndTestFrame)
|
||||||
|
if running:
|
||||||
|
received_up_frames.append(frame)
|
||||||
|
|
||||||
|
print("received UP frames =", received_up_frames)
|
||||||
|
|
||||||
|
assert len(received_up_frames) == len(expected_up_frames)
|
||||||
|
|
||||||
|
for real, expected in zip(received_up_frames, expected_up_frames):
|
||||||
|
assert isinstance(real, expected)
|
||||||
|
|
||||||
|
return (received_down_frames, received_up_frames)
|
||||||
Reference in New Issue
Block a user