hermes-agent/tests/gateway/test_telegram_slash_confirm.py
Teknium 5600105478 refactor(gateway): migrate slack/dingtalk/whatsapp/matrix/feishu/telegram/wecom/email/sms adapters to bundled plugins
Salvage of PR #41284 onto current main. Relocates the last 9 inline messaging
adapters (+ satellites: telegram_network, feishu_comment/_rules/meeting_invite,
wecom_crypto, wecom_callback) from gateway/platforms/ into self-contained
bundled plugins under plugins/platforms/<x>/, discovered via the platform
registry. Strips the per-platform core touchpoints from gateway/run.py,
gateway/config.py, hermes_cli/gateway.py, hermes_cli/setup.py, and
tools/send_message_tool.py.

Carries forward the migration fixes (explicit enabled:false honored,
get_connected_platforms forces discovery, plugin is_connected via
gateway.get_env_value, logs --component gateway matches plugins.platforms.*,
matrix hidden on Windows).

Additionally ports config keys main added since the PR base: the matrix
plugin's _apply_yaml_config now also covers allowed_users,
ignore_user_patterns, process_notices, and session_scope (the inline
gateway/config.py matrix block gained these in the 1340 commits the PR sat
open; they would otherwise have been silently dropped on deletion).
2026-06-20 10:26:45 -07:00

109 lines
3.5 KiB
Python

"""Regression guard: send_slash_confirm must use format_message + MARKDOWN_V2."""
import sys
from pathlib import Path
from types import SimpleNamespace
from unittest.mock import AsyncMock, MagicMock
import pytest
_repo = str(Path(__file__).resolve().parents[2])
if _repo not in sys.path:
sys.path.insert(0, _repo)
def _ensure_telegram_mock():
if "telegram" in sys.modules and hasattr(sys.modules["telegram"], "__file__"):
return
mod = MagicMock()
mod.ext.ContextTypes.DEFAULT_TYPE = type(None)
mod.constants.ParseMode.MARKDOWN = "Markdown"
mod.constants.ParseMode.MARKDOWN_V2 = "MarkdownV2"
mod.constants.ParseMode.HTML = "HTML"
mod.constants.ChatType.PRIVATE = "private"
mod.constants.ChatType.GROUP = "group"
mod.constants.ChatType.SUPERGROUP = "supergroup"
mod.constants.ChatType.CHANNEL = "channel"
mod.error.NetworkError = type("NetworkError", (OSError,), {})
mod.error.TimedOut = type("TimedOut", (OSError,), {})
mod.error.BadRequest = type("BadRequest", (Exception,), {})
for name in ("telegram", "telegram.ext", "telegram.constants", "telegram.request"):
sys.modules.setdefault(name, mod)
sys.modules.setdefault("telegram.error", mod.error)
_ensure_telegram_mock()
from plugins.platforms.telegram.adapter import TelegramAdapter
from gateway.config import PlatformConfig
def _make_adapter():
config = PlatformConfig(enabled=True, token="test-token", extra={})
adapter = TelegramAdapter(config)
adapter._bot = AsyncMock()
adapter._app = MagicMock()
return adapter
class TestSendSlashConfirm:
@pytest.mark.asyncio
async def test_uses_markdown_v2_and_escapes_special_chars(self):
"""send_slash_confirm must pass preview through format_message and use
MARKDOWN_V2 — so commands with underscores, dots, or brackets don't
raise BadRequest: Can't parse entities."""
adapter = _make_adapter()
sent = {}
async def mock_send(**kwargs):
sent.update(kwargs)
return SimpleNamespace(message_id=7)
adapter._bot.send_message = AsyncMock(side_effect=mock_send)
result = await adapter.send_slash_confirm(
chat_id="100",
title="Confirm",
message="/run script_name.sh --flag=value [option]",
session_key="sk",
confirm_id="cid1",
)
assert result.success is True
assert "MARKDOWN_V2" in repr(sent["parse_mode"])
# Underscores and dots must be escaped by format_message
assert "script\\_name" in sent["text"]
assert "\\." in sent["text"]
@pytest.mark.asyncio
async def test_stores_slash_confirm_state(self):
adapter = _make_adapter()
adapter._bot.send_message = AsyncMock(
return_value=SimpleNamespace(message_id=8)
)
await adapter.send_slash_confirm(
chat_id="100",
title="Confirm",
message="reload-mcp",
session_key="my-session",
confirm_id="cid2",
)
assert adapter._slash_confirm_state["cid2"] == "my-session"
@pytest.mark.asyncio
async def test_not_connected_returns_failure(self):
adapter = _make_adapter()
adapter._bot = None
result = await adapter.send_slash_confirm(
chat_id="100",
title="Confirm",
message="reload-mcp",
session_key="sk",
confirm_id="cid3",
)
assert result.success is False