Files
hermes-agent/tests/gateway/test_telegram_media_read_timeout.py
T
kshitijk4poor c1693d7dcc refactor: remove 27 duplicate _ensure_telegram_mock() copies from gateway tests
tests/gateway/conftest.py already installs a comprehensive telegram mock
at collection time (line 330), before any test module's imports run.
The per-file copies were fully redundant — each was a simpler subset
(plain strings, setdefault, fewer error classes) of the conftest version
(which uses _fake_str_enum for PTB-faithful StrEnum semantics, sys.modules
overwrite to win over partial/broken imports, and a full error hierarchy
including BadRequest, Forbidden, RetryAfter, Conflict, InvalidToken).

Removed: function def + module-level call + now-unused imports (sys,
MagicMock where no longer referenced) + dangling comment blocks that
referenced the deleted mock, in 27 test files.
Left untouched: tests/gateway/conftest.py (canonical source) and
tests/e2e/conftest.py (separate conftest tree that may run in isolation).

Found by /simplify-code review of PR #90560.
2026-08-21 16:25:24 +05:30

107 lines
3.4 KiB
Python

"""Every Telegram media upload passes the long media read timeout.
Telegram processes an uploaded photo/video/document server-side before it
answers, so the wait for the response is unrelated to how fast the bytes went
out and can outlast the short read timeout the rest of the Bot API is tuned
for. ``_MEDIA_SEND_READ_TIMEOUT`` is the longer budget; a media send that
misses it fails on a slow upload and falls back to posting the bare URL as
text, so the picture never arrives as a picture.
``send_image`` was the gap: both of its ``send_photo`` calls -- the URL send
and the byte-upload fallback that handles up to 10MB -- went out on the short
timeout. Both are driven for real below and asserted on the ``read_timeout``
that actually reaches the Bot API.
"""
from __future__ import annotations
from unittest.mock import AsyncMock, MagicMock
import pytest
from gateway.config import PlatformConfig # noqa: E402
from plugins.platforms.telegram import adapter as tg # noqa: E402
from plugins.platforms.telegram.adapter import TelegramAdapter # noqa: E402
@pytest.fixture
def adapter():
a = TelegramAdapter(PlatformConfig(enabled=True, token="fake-token"))
a._bot = MagicMock()
a._metadata_thread_id = lambda metadata: None
a._thread_kwargs_for_send = lambda *args, **kwargs: {}
a._notification_kwargs = lambda metadata: {}
a._reply_to_message_id_for_send = lambda *args, **kwargs: None
async def _direct(fn, payload, *args, **kwargs):
return await fn(**payload)
a._send_with_dm_topic_reply_anchor_retry = _direct
return a
def _stub_download(monkeypatch, size: int):
"""Make the fallback's SSRF-safe client return ``size`` bytes."""
class _Resp:
content = b"x" * size
def raise_for_status(self):
return None
class _Client:
async def __aenter__(self):
return self
async def __aexit__(self, *exc):
return False
async def get(self, url):
return _Resp()
import tools.url_safety as url_safety
monkeypatch.setattr(url_safety, "create_ssrf_safe_async_client", lambda **kw: _Client())
@pytest.mark.asyncio
async def test_send_image_url_path_uses_media_read_timeout(adapter):
calls = []
async def _photo(**kwargs):
calls.append(kwargs)
msg = MagicMock()
msg.message_id = 1
return msg
adapter._bot.send_photo = AsyncMock(side_effect=_photo)
result = await adapter.send_image("123", "https://example.com/pic.png", caption="hi")
assert result.success
assert calls[0]["read_timeout"] == tg._MEDIA_SEND_READ_TIMEOUT
@pytest.mark.asyncio
async def test_send_image_upload_fallback_uses_media_read_timeout(adapter, monkeypatch):
"""The >5MB fallback is the slowest send in the file — it needs it most."""
_stub_download(monkeypatch, 8 * 1024 * 1024)
calls = []
async def _photo(**kwargs):
calls.append(kwargs)
if len(calls) == 1:
raise RuntimeError("Photo too big for a URL send")
msg = MagicMock()
msg.message_id = 2
return msg
adapter._bot.send_photo = AsyncMock(side_effect=_photo)
result = await adapter.send_image("123", "https://example.com/big.png", caption="hi")
assert result.success
assert len(calls) == 2, "expected the byte-upload fallback to run"
upload = calls[1]
assert isinstance(upload["photo"], (bytes, bytearray))
assert upload["read_timeout"] == tg._MEDIA_SEND_READ_TIMEOUT