"""Tests for TelegramClient (notify-only mode).""" from __future__ import annotations import json from decimal import Decimal import pytest from pytest_httpx import HTTPXMock from cerbero_bite.clients._base import HttpToolClient from cerbero_bite.clients.telegram import TelegramClient def _client() -> TelegramClient: http = HttpToolClient( service="telegram", base_url="http://mcp-telegram:9017", token="t", retry_max=1, ) return TelegramClient(http) def _request_body(httpx_mock: HTTPXMock) -> dict: request = httpx_mock.get_request() assert request is not None return json.loads(request.read()) @pytest.mark.asyncio async def test_notify_sends_message_with_priority(httpx_mock: HTTPXMock) -> None: httpx_mock.add_response( url="http://mcp-telegram:9017/tools/notify", json={"ok": True}, ) await _client().notify("hello", priority="high", tag="entry") body = _request_body(httpx_mock) assert body == {"message": "hello", "priority": "high", "tag": "entry"} @pytest.mark.asyncio async def test_notify_default_priority_normal(httpx_mock: HTTPXMock) -> None: httpx_mock.add_response(json={"ok": True}) await _client().notify("plain") body = _request_body(httpx_mock) assert body["priority"] == "normal" assert "tag" not in body @pytest.mark.asyncio async def test_notify_position_opened_serialises_decimals( httpx_mock: HTTPXMock, ) -> None: httpx_mock.add_response( url="http://mcp-telegram:9017/tools/notify_position_opened", json={"ok": True}, ) await _client().notify_position_opened( instrument="ETH-15MAY26-2475-P", side="SELL", size=2, strategy="bull_put", greeks={"delta": Decimal("-0.04"), "vega": Decimal("0.20")}, expected_pnl_usd=Decimal("45.00"), ) body = _request_body(httpx_mock) assert body["instrument"] == "ETH-15MAY26-2475-P" assert body["greeks"] == {"delta": -0.04, "vega": 0.20} assert body["expected_pnl"] == 45.0 assert body["size"] == 2.0 @pytest.mark.asyncio async def test_notify_position_closed(httpx_mock: HTTPXMock) -> None: httpx_mock.add_response(json={"ok": True}) await _client().notify_position_closed( instrument="ETH-15MAY26-2475-P_2350-P", realized_pnl_usd=Decimal("32.50"), reason="CLOSE_PROFIT", ) body = _request_body(httpx_mock) assert body == { "instrument": "ETH-15MAY26-2475-P_2350-P", "realized_pnl": 32.5, "reason": "CLOSE_PROFIT", } @pytest.mark.asyncio async def test_notify_alert(httpx_mock: HTTPXMock) -> None: httpx_mock.add_response(json={"ok": True}) await _client().notify_alert( source="kill_switch", message="armed manually", priority="critical" ) body = _request_body(httpx_mock) assert body == { "source": "kill_switch", "message": "armed manually", "priority": "critical", } @pytest.mark.asyncio async def test_notify_system_error(httpx_mock: HTTPXMock) -> None: httpx_mock.add_response(json={"ok": True}) await _client().notify_system_error( message="deribit feed anomaly", component="clients.deribit", ) body = _request_body(httpx_mock) assert body["message"] == "deribit feed anomaly" assert body["component"] == "clients.deribit" assert body["priority"] == "critical" def test_telegram_client_rejects_wrong_service() -> None: bad = HttpToolClient( service="macro", base_url="http://x:1", token="t", retry_max=1 ) with pytest.raises(ValueError, match="requires service 'telegram'"): TelegramClient(bad)