test(gateway): cover photo burst interrupt regressions
Add regression coverage for non-album Telegram photo burst batching, photo follow-ups that should queue without interrupting active runs, and the gateway priority-interrupt path for photo events.
This commit is contained in:
parent
4ae1334287
commit
fef710aca8
3 changed files with 96 additions and 1 deletions
|
|
@ -11,7 +11,7 @@ import asyncio
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from gateway.config import Platform, PlatformConfig
|
from gateway.config import Platform, PlatformConfig
|
||||||
from gateway.platforms.base import BasePlatformAdapter, MessageEvent, SendResult
|
from gateway.platforms.base import BasePlatformAdapter, MessageEvent, MessageType, SendResult
|
||||||
from gateway.session import SessionSource, build_session_key
|
from gateway.session import SessionSource, build_session_key
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -122,3 +122,29 @@ class TestInterruptKeyConsistency:
|
||||||
|
|
||||||
# Interrupt event was set
|
# Interrupt event was set
|
||||||
assert adapter._active_sessions[session_key].is_set()
|
assert adapter._active_sessions[session_key].is_set()
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_photo_followup_is_queued_without_interrupt(self):
|
||||||
|
"""Photo follow-ups should queue behind the active run instead of interrupting it."""
|
||||||
|
adapter = StubAdapter()
|
||||||
|
adapter.set_message_handler(lambda event: asyncio.sleep(0, result=None))
|
||||||
|
|
||||||
|
source = _source("-1001234", "group")
|
||||||
|
session_key = build_session_key(source)
|
||||||
|
interrupt_event = asyncio.Event()
|
||||||
|
adapter._active_sessions[session_key] = interrupt_event
|
||||||
|
|
||||||
|
event = MessageEvent(
|
||||||
|
text="caption",
|
||||||
|
source=source,
|
||||||
|
message_type=MessageType.PHOTO,
|
||||||
|
message_id="2",
|
||||||
|
media_urls=["/tmp/photo-a.jpg"],
|
||||||
|
media_types=["image/jpeg"],
|
||||||
|
)
|
||||||
|
await adapter.handle_message(event)
|
||||||
|
|
||||||
|
queued = adapter._pending_messages[session_key]
|
||||||
|
assert queued is event
|
||||||
|
assert queued.media_urls == ["/tmp/photo-a.jpg"]
|
||||||
|
assert interrupt_event.is_set() is False
|
||||||
|
|
|
||||||
|
|
@ -352,6 +352,26 @@ class TestDocumentDownloadBlock:
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
class TestMediaGroups:
|
class TestMediaGroups:
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_non_album_photo_burst_is_buffered_and_combined(self, adapter):
|
||||||
|
first_photo = _make_photo(_make_file_obj(b"first"))
|
||||||
|
second_photo = _make_photo(_make_file_obj(b"second"))
|
||||||
|
|
||||||
|
msg1 = _make_message(caption="two images", photo=[first_photo])
|
||||||
|
msg2 = _make_message(photo=[second_photo])
|
||||||
|
|
||||||
|
with patch("gateway.platforms.telegram.cache_image_from_bytes", side_effect=["/tmp/burst-one.jpg", "/tmp/burst-two.jpg"]):
|
||||||
|
await adapter._handle_media_message(_make_update(msg1), MagicMock())
|
||||||
|
await adapter._handle_media_message(_make_update(msg2), MagicMock())
|
||||||
|
assert adapter.handle_message.await_count == 0
|
||||||
|
await asyncio.sleep(adapter.MEDIA_GROUP_WAIT_SECONDS + 0.05)
|
||||||
|
|
||||||
|
adapter.handle_message.assert_awaited_once()
|
||||||
|
event = adapter.handle_message.await_args.args[0]
|
||||||
|
assert event.text == "two images"
|
||||||
|
assert event.media_urls == ["/tmp/burst-one.jpg", "/tmp/burst-two.jpg"]
|
||||||
|
assert len(event.media_types) == 2
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_photo_album_is_buffered_and_combined(self, adapter):
|
async def test_photo_album_is_buffered_and_combined(self, adapter):
|
||||||
first_photo = _make_photo(_make_file_obj(b"first"))
|
first_photo = _make_photo(_make_file_obj(b"first"))
|
||||||
|
|
|
||||||
49
tests/gateway/test_telegram_photo_interrupts.py
Normal file
49
tests/gateway/test_telegram_photo_interrupts.py
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
import asyncio
|
||||||
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from gateway.config import GatewayConfig, Platform, PlatformConfig
|
||||||
|
from gateway.platforms.base import MessageEvent, MessageType
|
||||||
|
from gateway.session import SessionSource, build_session_key
|
||||||
|
from gateway.run import GatewayRunner
|
||||||
|
|
||||||
|
|
||||||
|
class _PendingAdapter:
|
||||||
|
def __init__(self):
|
||||||
|
self._pending_messages = {}
|
||||||
|
|
||||||
|
|
||||||
|
def _make_runner():
|
||||||
|
runner = object.__new__(GatewayRunner)
|
||||||
|
runner.config = GatewayConfig(platforms={Platform.TELEGRAM: PlatformConfig(enabled=True, token="***")})
|
||||||
|
runner.adapters = {Platform.TELEGRAM: _PendingAdapter()}
|
||||||
|
runner._running_agents = {}
|
||||||
|
runner._pending_messages = {}
|
||||||
|
runner._pending_approvals = {}
|
||||||
|
runner._voice_mode = {}
|
||||||
|
runner._is_user_authorized = lambda _source: True
|
||||||
|
return runner
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_handle_message_does_not_priority_interrupt_photo_followup():
|
||||||
|
runner = _make_runner()
|
||||||
|
source = SessionSource(platform=Platform.TELEGRAM, chat_id="12345", chat_type="dm")
|
||||||
|
session_key = build_session_key(source)
|
||||||
|
running_agent = MagicMock()
|
||||||
|
runner._running_agents[session_key] = running_agent
|
||||||
|
|
||||||
|
event = MessageEvent(
|
||||||
|
text="caption",
|
||||||
|
message_type=MessageType.PHOTO,
|
||||||
|
source=source,
|
||||||
|
media_urls=["/tmp/photo-a.jpg"],
|
||||||
|
media_types=["image/jpeg"],
|
||||||
|
)
|
||||||
|
|
||||||
|
result = await runner._handle_message(event)
|
||||||
|
|
||||||
|
assert result is None
|
||||||
|
running_agent.interrupt.assert_not_called()
|
||||||
|
assert runner.adapters[Platform.TELEGRAM]._pending_messages[session_key] is event
|
||||||
Loading…
Add table
Add a link
Reference in a new issue