summaryrefslogtreecommitdiff
path: root/tests/edge_cases/test_notifier_failures.py
diff options
context:
space:
mode:
authorTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2026-04-01 17:11:51 +0900
committerTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2026-04-01 17:11:51 +0900
commit66368d580cf569b50a33e438f2287a977e6fc704 (patch)
tree8a3b9e538333abf4564846849affec1ef1279e05 /tests/edge_cases/test_notifier_failures.py
parent2d1530f210f4b4f679a5d3b3597c4815904398a7 (diff)
test: add edge case tests for zero volume, empty data, extreme values
Diffstat (limited to 'tests/edge_cases/test_notifier_failures.py')
-rw-r--r--tests/edge_cases/test_notifier_failures.py85
1 files changed, 85 insertions, 0 deletions
diff --git a/tests/edge_cases/test_notifier_failures.py b/tests/edge_cases/test_notifier_failures.py
new file mode 100644
index 0000000..4ba781f
--- /dev/null
+++ b/tests/edge_cases/test_notifier_failures.py
@@ -0,0 +1,85 @@
+"""Tests for TelegramNotifier failure modes."""
+
+import asyncio
+import logging
+import sys
+from pathlib import Path
+from unittest.mock import AsyncMock, MagicMock, patch
+
+import aiohttp
+import pytest
+
+sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "services" / "strategy-engine"))
+sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "services" / "backtester" / "src"))
+
+from shared.notifier import TelegramNotifier
+
+
+@pytest.fixture
+def notifier():
+ return TelegramNotifier(bot_token="fake-token", chat_id="12345")
+
+
+class TestSendConnectionError:
+ """TelegramNotifier.send() when session.post raises ConnectionError should not crash."""
+
+ @pytest.mark.asyncio
+ async def test_connection_error_does_not_crash(self, notifier, caplog):
+ mock_session = AsyncMock(spec=aiohttp.ClientSession)
+ mock_session.closed = False
+ mock_session.post = MagicMock(side_effect=aiohttp.ClientError("Connection refused"))
+ notifier._session = mock_session
+
+ with caplog.at_level(logging.WARNING):
+ await notifier.send("test message")
+ # Should not raise, should log the error
+
+
+class TestSendRateLimited:
+ """TelegramNotifier.send() when API returns 429 should retry."""
+
+ @pytest.mark.asyncio
+ async def test_rate_limit_retries(self, notifier):
+ mock_response_429 = AsyncMock()
+ mock_response_429.status = 429
+ mock_response_429.json = AsyncMock(return_value={"description": "Too Many Requests"})
+ mock_response_429.__aenter__ = AsyncMock(return_value=mock_response_429)
+ mock_response_429.__aexit__ = AsyncMock(return_value=False)
+
+ mock_response_200 = AsyncMock()
+ mock_response_200.status = 200
+ mock_response_200.__aenter__ = AsyncMock(return_value=mock_response_200)
+ mock_response_200.__aexit__ = AsyncMock(return_value=False)
+
+ mock_session = AsyncMock(spec=aiohttp.ClientSession)
+ mock_session.closed = False
+ # First two calls return 429, third returns 200
+ mock_session.post = MagicMock(
+ side_effect=[mock_response_429, mock_response_429, mock_response_200]
+ )
+ notifier._session = mock_session
+
+ with patch("shared.notifier.asyncio.sleep", new_callable=AsyncMock):
+ await notifier.send("test message")
+
+ # Should have been called 3 times (2 retries + 1 success)
+ assert mock_session.post.call_count == 3
+
+
+class TestCloseAlreadyClosed:
+ """TelegramNotifier.close() when session already closed should not crash."""
+
+ @pytest.mark.asyncio
+ async def test_close_no_session(self):
+ notifier = TelegramNotifier(bot_token="fake", chat_id="123")
+ # No session created yet
+ await notifier.close() # Should not raise
+
+ @pytest.mark.asyncio
+ async def test_close_already_closed_session(self, notifier):
+ mock_session = AsyncMock(spec=aiohttp.ClientSession)
+ mock_session.close = AsyncMock()
+ notifier._session = mock_session
+
+ await notifier.close()
+ await notifier.close() # Second close should not crash