summaryrefslogtreecommitdiff
path: root/shared/tests
diff options
context:
space:
mode:
authorTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2026-04-01 16:07:05 +0900
committerTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2026-04-01 16:07:05 +0900
commite1bf24b2a639ba21361ae408ee6c1eebe37801aa (patch)
tree83127c396a78a70a3cd6317e11b140b3de5ed141 /shared/tests
parent558de36fdd886a117c66dee73850cc219c86b2a4 (diff)
feat(shared): add Telegram notification service
Diffstat (limited to 'shared/tests')
-rw-r--r--shared/tests/test_notifier.py177
1 files changed, 177 insertions, 0 deletions
diff --git a/shared/tests/test_notifier.py b/shared/tests/test_notifier.py
new file mode 100644
index 0000000..09e731a
--- /dev/null
+++ b/shared/tests/test_notifier.py
@@ -0,0 +1,177 @@
+"""Tests for Telegram notification service."""
+import os
+import uuid
+from decimal import Decimal
+from datetime import datetime, timezone
+from unittest.mock import AsyncMock, MagicMock, patch
+
+import pytest
+import pytest_asyncio
+
+from shared.models import Signal, Order, OrderSide, OrderType, OrderStatus, Position
+from shared.notifier import TelegramNotifier
+
+
+class TestTelegramNotifierEnabled:
+ """Test the enabled property."""
+
+ def test_disabled_when_no_token(self):
+ notifier = TelegramNotifier(bot_token="", chat_id="123")
+ assert notifier.enabled is False
+
+ def test_enabled_with_token(self):
+ notifier = TelegramNotifier(bot_token="fake-token", chat_id="123")
+ assert notifier.enabled is True
+
+ def test_disabled_when_token_is_empty_string(self):
+ notifier = TelegramNotifier(bot_token="", chat_id="")
+ assert notifier.enabled is False
+
+
+class TestTelegramNotifierSend:
+ """Test send method."""
+
+ @pytest.mark.asyncio
+ async def test_send_does_nothing_when_disabled(self):
+ notifier = TelegramNotifier(bot_token="", chat_id="123")
+ # Should not raise or do anything
+ await notifier.send("test message")
+
+ @pytest.mark.asyncio
+ async def test_send_posts_to_api(self):
+ notifier = TelegramNotifier(bot_token="fake-token", chat_id="12345")
+
+ mock_response = AsyncMock()
+ mock_response.status = 200
+ mock_response.json = AsyncMock(return_value={"ok": True})
+ mock_response.__aenter__ = AsyncMock(return_value=mock_response)
+ mock_response.__aexit__ = AsyncMock(return_value=False)
+
+ mock_session = AsyncMock()
+ mock_session.post = MagicMock(return_value=mock_response)
+
+ with patch.object(notifier, "_session", mock_session):
+ await notifier.send("Hello, world!")
+
+ mock_session.post.assert_called_once()
+ call_args = mock_session.post.call_args
+ assert "fake-token" in call_args[0][0]
+ assert call_args[1]["json"]["chat_id"] == "12345"
+ assert call_args[1]["json"]["text"] == "Hello, world!"
+ assert call_args[1]["json"]["parse_mode"] == "HTML"
+
+ @pytest.mark.asyncio
+ async def test_send_with_custom_parse_mode(self):
+ notifier = TelegramNotifier(bot_token="fake-token", chat_id="12345")
+
+ mock_response = AsyncMock()
+ mock_response.status = 200
+ mock_response.json = AsyncMock(return_value={"ok": True})
+ mock_response.__aenter__ = AsyncMock(return_value=mock_response)
+ mock_response.__aexit__ = AsyncMock(return_value=False)
+
+ mock_session = AsyncMock()
+ mock_session.post = MagicMock(return_value=mock_response)
+
+ with patch.object(notifier, "_session", mock_session):
+ await notifier.send("test", parse_mode="Markdown")
+
+ call_args = mock_session.post.call_args
+ assert call_args[1]["json"]["parse_mode"] == "Markdown"
+
+
+class TestTelegramNotifierFormatters:
+ """Test message formatting methods."""
+
+ @pytest.mark.asyncio
+ async def test_send_signal_formats_message(self):
+ notifier = TelegramNotifier(bot_token="fake-token", chat_id="123")
+ signal = Signal(
+ strategy="rsi_strategy",
+ symbol="BTCUSDT",
+ side=OrderSide.BUY,
+ price=Decimal("50000.00"),
+ quantity=Decimal("0.01"),
+ reason="RSI oversold",
+ )
+
+ with patch.object(notifier, "send", new_callable=AsyncMock) as mock_send:
+ await notifier.send_signal(signal)
+ mock_send.assert_called_once()
+ msg = mock_send.call_args[0][0]
+ assert "BUY" in msg
+ assert "rsi_strategy" in msg
+ assert "BTCUSDT" in msg
+ assert "50000.00" in msg
+ assert "0.01" in msg
+ assert "RSI oversold" in msg
+
+ @pytest.mark.asyncio
+ async def test_send_order_formats_message(self):
+ notifier = TelegramNotifier(bot_token="fake-token", chat_id="123")
+ order = Order(
+ signal_id=str(uuid.uuid4()),
+ symbol="ETHUSDT",
+ side=OrderSide.SELL,
+ type=OrderType.LIMIT,
+ price=Decimal("3000.50"),
+ quantity=Decimal("1.5"),
+ status=OrderStatus.FILLED,
+ )
+
+ with patch.object(notifier, "send", new_callable=AsyncMock) as mock_send:
+ await notifier.send_order(order)
+ mock_send.assert_called_once()
+ msg = mock_send.call_args[0][0]
+ assert "FILLED" in msg
+ assert "ETHUSDT" in msg
+ assert "SELL" in msg
+ assert "3000.50" in msg
+ assert "1.5" in msg
+
+ @pytest.mark.asyncio
+ async def test_send_error_formats_message(self):
+ notifier = TelegramNotifier(bot_token="fake-token", chat_id="123")
+
+ with patch.object(notifier, "send", new_callable=AsyncMock) as mock_send:
+ await notifier.send_error("Connection failed", service="executor")
+ mock_send.assert_called_once()
+ msg = mock_send.call_args[0][0]
+ assert "Connection failed" in msg
+ assert "executor" in msg
+
+ @pytest.mark.asyncio
+ async def test_send_daily_summary_formats_message(self):
+ notifier = TelegramNotifier(bot_token="fake-token", chat_id="123")
+ positions = [
+ Position(
+ symbol="BTCUSDT",
+ quantity=Decimal("0.1"),
+ avg_entry_price=Decimal("50000"),
+ current_price=Decimal("51000"),
+ ),
+ ]
+
+ with patch.object(notifier, "send", new_callable=AsyncMock) as mock_send:
+ await notifier.send_daily_summary(
+ positions=positions,
+ total_value=Decimal("5100.00"),
+ daily_pnl=Decimal("100.00"),
+ )
+ mock_send.assert_called_once()
+ msg = mock_send.call_args[0][0]
+ assert "BTCUSDT" in msg
+ assert "5100.00" in msg
+ assert "100.00" in msg
+
+
+class TestTelegramNotifierClose:
+ """Test close method."""
+
+ @pytest.mark.asyncio
+ async def test_close_closes_session(self):
+ notifier = TelegramNotifier(bot_token="fake-token", chat_id="123")
+ mock_session = AsyncMock()
+ notifier._session = mock_session
+ await notifier.close()
+ mock_session.close.assert_called_once()