Spaces:
Sleeping
Sleeping
| from unittest.mock import AsyncMock, MagicMock, patch | |
| import pytest | |
| from telegram.error import NetworkError, RetryAfter, TelegramError | |
| from messaging.platforms.telegram import TelegramPlatform | |
| def telegram_platform(): | |
| with patch("messaging.platforms.telegram.TELEGRAM_AVAILABLE", True): | |
| platform = TelegramPlatform(bot_token="test_token", allowed_user_id="12345") | |
| return platform | |
| async def test_telegram_retry_on_network_error(telegram_platform): | |
| mock_bot = AsyncMock() | |
| mock_msg = MagicMock() | |
| mock_msg.message_id = 999 | |
| # Fail twice, then succeed | |
| mock_bot.send_message.side_effect = [ | |
| NetworkError("Connection failed"), | |
| NetworkError("Connection failed"), | |
| mock_msg, | |
| ] | |
| telegram_platform._application = MagicMock() | |
| telegram_platform._application.bot = mock_bot | |
| # We need to patch asyncio.sleep to speed up the test | |
| with patch("asyncio.sleep", AsyncMock()) as mock_sleep: | |
| msg_id = await telegram_platform.send_message("chat_1", "hello") | |
| assert msg_id == "999" | |
| assert mock_bot.send_message.call_count == 3 | |
| assert mock_sleep.call_count == 2 | |
| async def test_telegram_retry_on_retry_after(telegram_platform): | |
| mock_bot = AsyncMock() | |
| mock_msg = MagicMock() | |
| mock_msg.message_id = 1000 | |
| # Fail with RetryAfter, then succeed | |
| mock_bot.send_message.side_effect = [RetryAfter(retry_after=5), mock_msg] | |
| telegram_platform._application = MagicMock() | |
| telegram_platform._application.bot = mock_bot | |
| with patch("asyncio.sleep", AsyncMock()) as mock_sleep: | |
| msg_id = await telegram_platform.send_message("chat_1", "hello") | |
| assert msg_id == "1000" | |
| assert mock_bot.send_message.call_count == 2 | |
| mock_sleep.assert_called_with(5) | |
| async def test_telegram_no_retry_on_bad_request(telegram_platform): | |
| mock_bot = AsyncMock() | |
| # Fail with generic TelegramError (should not retry unless specific conditions met) | |
| mock_bot.send_message.side_effect = TelegramError("Bad Request: some error") | |
| telegram_platform._application = MagicMock() | |
| telegram_platform._application.bot = mock_bot | |
| with pytest.raises(TelegramError): | |
| await telegram_platform.send_message("chat_1", "hello") | |
| assert mock_bot.send_message.call_count == 1 | |
| def test_handler_build_message_hardening(): | |
| # Formatting hardening now lives in TranscriptBuffer rendering. | |
| from messaging.rendering.telegram_markdown import ( | |
| escape_md_v2, | |
| escape_md_v2_code, | |
| mdv2_bold, | |
| mdv2_code_inline, | |
| render_markdown_to_mdv2, | |
| ) | |
| from messaging.transcript import RenderCtx, TranscriptBuffer | |
| ctx = RenderCtx( | |
| bold=mdv2_bold, | |
| code_inline=mdv2_code_inline, | |
| escape_code=escape_md_v2_code, | |
| escape_text=escape_md_v2, | |
| render_markdown=render_markdown_to_mdv2, | |
| ) | |
| # Case 1: Empty transcript + no status => empty string. | |
| t = TranscriptBuffer() | |
| msg = t.render(ctx, limit_chars=3900, status=None) | |
| assert msg == "" | |
| # Case 2: Truncation with code block closing and status preserved. | |
| t.apply({"type": "thinking_chunk", "text": ("thought " * 200)}) | |
| t.apply({"type": "text_chunk", "text": ("This is a very long message. " * 300)}) | |
| msg = t.render(ctx, limit_chars=3900, status="Finishing...") | |
| assert len(msg) <= 4096 | |
| assert "Finishing..." in msg | |
| if "```" in msg: | |
| assert msg.count("```") % 2 == 0 | |
| def test_render_output_never_exceeds_4096(): | |
| """Transcript render with various status lengths never exceeds Telegram 4096 limit.""" | |
| from messaging.rendering.telegram_markdown import ( | |
| escape_md_v2, | |
| escape_md_v2_code, | |
| mdv2_bold, | |
| mdv2_code_inline, | |
| render_markdown_to_mdv2, | |
| ) | |
| from messaging.transcript import RenderCtx, TranscriptBuffer | |
| ctx = RenderCtx( | |
| bold=mdv2_bold, | |
| code_inline=mdv2_code_inline, | |
| escape_code=escape_md_v2_code, | |
| escape_text=escape_md_v2, | |
| render_markdown=render_markdown_to_mdv2, | |
| ) | |
| t = TranscriptBuffer() | |
| t.apply({"type": "thinking_chunk", "text": "x" * 500}) | |
| t.apply({"type": "text_chunk", "text": "y" * 3500}) | |
| for status in [None, "Done", "✅ *Complete*", "A" * 100]: | |
| msg = t.render(ctx, limit_chars=3900, status=status) | |
| assert len(msg) <= 4096, f"status={status!r} produced len={len(msg)}" | |