Files
remnawave-bedolaga-telegram…/tests/middlewares/test_channel_checker_payload.py
T
2026-03-10 14:29:29 +05:00

273 lines
12 KiB
Python

"""Тесты для функций сохранения/получения pending_start_payload в channel_checker."""
import sys
from pathlib import Path
from types import SimpleNamespace
from unittest.mock import AsyncMock, MagicMock, patch
ROOT_DIR = Path(__file__).resolve().parents[2]
if str(ROOT_DIR) not in sys.path:
sys.path.insert(0, str(ROOT_DIR))
from aiogram.types import Message
class TestRedisPayloadFunctions:
"""Тесты для Redis-функций сохранения payload."""
async def test_save_pending_payload_to_redis_success(self, monkeypatch):
"""Тест успешного сохранения payload в Redis."""
from app.middlewares import channel_checker
mock_redis = AsyncMock()
mock_redis.set = AsyncMock(return_value=True)
mock_redis.aclose = AsyncMock()
with patch('app.middlewares.channel_checker.aioredis') as mock_aioredis:
mock_aioredis.from_url = MagicMock(return_value=mock_redis)
result = await channel_checker.save_pending_payload_to_redis(123456, 'ref_test123')
assert result is True
mock_redis.set.assert_awaited_once()
call_args = mock_redis.set.await_args
assert 'pending_start_payload:123456' in call_args.args[0]
assert call_args.args[1] == 'ref_test123'
assert call_args.kwargs.get('ex') == 3600
mock_redis.aclose.assert_awaited_once()
async def test_save_pending_payload_to_redis_failure(self, monkeypatch):
"""Тест обработки ошибки при сохранении в Redis."""
from app.middlewares import channel_checker
with patch('app.middlewares.channel_checker.aioredis') as mock_aioredis:
mock_aioredis.from_url = MagicMock(side_effect=Exception('Redis connection failed'))
result = await channel_checker.save_pending_payload_to_redis(123456, 'ref_test123')
assert result is False
async def test_get_pending_payload_from_redis_success(self, monkeypatch):
"""Тест успешного получения payload из Redis."""
from app.middlewares import channel_checker
mock_redis = AsyncMock()
mock_redis.get = AsyncMock(return_value=b'ref_test123')
mock_redis.aclose = AsyncMock()
with patch('app.middlewares.channel_checker.aioredis') as mock_aioredis:
mock_aioredis.from_url = MagicMock(return_value=mock_redis)
result = await channel_checker.get_pending_payload_from_redis(123456)
assert result == 'ref_test123'
mock_redis.get.assert_awaited_once()
mock_redis.aclose.assert_awaited_once()
async def test_get_pending_payload_from_redis_not_found(self, monkeypatch):
"""Тест когда payload не найден в Redis."""
from app.middlewares import channel_checker
mock_redis = AsyncMock()
mock_redis.get = AsyncMock(return_value=None)
mock_redis.aclose = AsyncMock()
with patch('app.middlewares.channel_checker.aioredis') as mock_aioredis:
mock_aioredis.from_url = MagicMock(return_value=mock_redis)
result = await channel_checker.get_pending_payload_from_redis(123456)
assert result is None
async def test_get_pending_payload_from_redis_failure(self, monkeypatch):
"""Тест обработки ошибки при получении из Redis."""
from app.middlewares import channel_checker
with patch('app.middlewares.channel_checker.aioredis') as mock_aioredis:
mock_aioredis.from_url = MagicMock(side_effect=Exception('Redis connection failed'))
result = await channel_checker.get_pending_payload_from_redis(123456)
assert result is None
async def test_delete_pending_payload_from_redis(self, monkeypatch):
"""Тест удаления payload из Redis."""
from app.middlewares import channel_checker
mock_redis = AsyncMock()
mock_redis.delete = AsyncMock(return_value=1)
mock_redis.aclose = AsyncMock()
with patch('app.middlewares.channel_checker.aioredis') as mock_aioredis:
mock_aioredis.from_url = MagicMock(return_value=mock_redis)
# Не должно бросать исключение
await channel_checker.delete_pending_payload_from_redis(123456)
mock_redis.delete.assert_awaited_once()
async def test_delete_pending_payload_from_redis_handles_error(self, monkeypatch):
"""Тест что удаление не бросает исключение при ошибке."""
from app.middlewares import channel_checker
with patch('app.middlewares.channel_checker.aioredis') as mock_aioredis:
mock_aioredis.from_url = MagicMock(side_effect=Exception('Redis error'))
# Не должно бросать исключение
await channel_checker.delete_pending_payload_from_redis(123456)
def _create_mock_message(text: str, user_id: int):
"""Создаёт мок Message с нужными атрибутами."""
mock_msg = MagicMock(spec=Message)
mock_msg.text = text
mock_msg.from_user = SimpleNamespace(id=user_id)
return mock_msg
class TestCaptureStartPayload:
"""Тесты для метода _capture_start_payload."""
async def test_capture_saves_to_fsm_state(self, monkeypatch):
"""Тест сохранения payload в FSM state."""
from app.middlewares.channel_checker import ChannelCheckerMiddleware
middleware = ChannelCheckerMiddleware()
mock_state = AsyncMock()
mock_state.get_data = AsyncMock(return_value={})
mock_state.set_data = AsyncMock()
mock_message = _create_mock_message('/start ref_abc123', 123456)
with patch(
'app.middlewares.channel_checker.save_pending_payload_to_redis', new_callable=AsyncMock
) as mock_save_redis:
await middleware._capture_start_payload(mock_state, mock_message, None)
mock_state.set_data.assert_awaited_once()
saved_data = mock_state.set_data.await_args.args[0]
assert saved_data['pending_start_payload'] == 'ref_abc123'
# Также должен сохраняться в Redis
mock_save_redis.assert_awaited_once_with(123456, 'ref_abc123')
async def test_capture_saves_to_redis_when_state_none(self, monkeypatch):
"""Тест сохранения payload в Redis когда FSM state недоступен."""
from app.middlewares.channel_checker import ChannelCheckerMiddleware
middleware = ChannelCheckerMiddleware()
mock_message = _create_mock_message('/start ref_xyz789', 999888)
with patch(
'app.middlewares.channel_checker.save_pending_payload_to_redis', new_callable=AsyncMock
) as mock_save_redis:
await middleware._capture_start_payload(None, mock_message, None)
# Должен сохраняться в Redis даже если state=None
mock_save_redis.assert_awaited_once_with(999888, 'ref_xyz789')
async def test_capture_ignores_message_without_payload(self, monkeypatch):
"""Тест что сообщение без payload игнорируется."""
from app.middlewares.channel_checker import ChannelCheckerMiddleware
middleware = ChannelCheckerMiddleware()
mock_state = AsyncMock()
mock_state.get_data = AsyncMock(return_value={})
mock_state.set_data = AsyncMock()
mock_message = _create_mock_message('/start', 123456) # Без payload
with patch(
'app.middlewares.channel_checker.save_pending_payload_to_redis', new_callable=AsyncMock
) as mock_save_redis:
await middleware._capture_start_payload(mock_state, mock_message, None)
mock_state.set_data.assert_not_awaited()
mock_save_redis.assert_not_awaited()
async def test_capture_ignores_non_start_message(self, monkeypatch):
"""Тест что не-start сообщения игнорируются."""
from app.middlewares.channel_checker import ChannelCheckerMiddleware
middleware = ChannelCheckerMiddleware()
mock_state = AsyncMock()
mock_state.get_data = AsyncMock(return_value={})
mock_state.set_data = AsyncMock()
mock_message = _create_mock_message('/help something', 123456) # Не /start
with patch(
'app.middlewares.channel_checker.save_pending_payload_to_redis', new_callable=AsyncMock
) as mock_save_redis:
await middleware._capture_start_payload(mock_state, mock_message, None)
mock_state.set_data.assert_not_awaited()
mock_save_redis.assert_not_awaited()
async def test_capture_does_not_overwrite_same_payload(self, monkeypatch):
"""Тест что одинаковый payload не перезаписывается в FSM state."""
from app.middlewares.channel_checker import ChannelCheckerMiddleware
middleware = ChannelCheckerMiddleware()
mock_state = AsyncMock()
mock_state.get_data = AsyncMock(return_value={'pending_start_payload': 'ref_same'})
mock_state.set_data = AsyncMock()
mock_message = _create_mock_message('/start ref_same', 123456) # Тот же payload
with patch(
'app.middlewares.channel_checker.save_pending_payload_to_redis', new_callable=AsyncMock
) as mock_save_redis:
await middleware._capture_start_payload(mock_state, mock_message, None)
# FSM state не должен перезаписываться
mock_state.set_data.assert_not_awaited()
# Но в Redis всё равно сохраняем (для надёжности)
mock_save_redis.assert_awaited_once()
class TestPayloadIntegration:
"""Интеграционные тесты для потока сохранения/восстановления payload."""
async def test_full_flow_fsm_state_works(self, monkeypatch):
"""Тест полного потока когда FSM state работает корректно."""
from app.middlewares.channel_checker import ChannelCheckerMiddleware
middleware = ChannelCheckerMiddleware()
# Сохраняем payload
state_storage = {}
mock_state = AsyncMock()
mock_state.get_data = AsyncMock(return_value=state_storage)
mock_state.set_data = AsyncMock(side_effect=state_storage.update)
mock_message = _create_mock_message('/start ref_flow_test', 111222)
with patch('app.middlewares.channel_checker.save_pending_payload_to_redis', new_callable=AsyncMock):
await middleware._capture_start_payload(mock_state, mock_message, None)
# Проверяем что payload сохранён
assert state_storage.get('pending_start_payload') == 'ref_flow_test'
async def test_payload_retrieved_from_redis_fallback(self, monkeypatch):
"""Тест что payload восстанавливается из Redis если в FSM state его нет."""
from app.middlewares.channel_checker import get_pending_payload_from_redis
mock_redis = AsyncMock()
mock_redis.get = AsyncMock(return_value=b'ref_from_redis')
mock_redis.aclose = AsyncMock()
with patch('app.middlewares.channel_checker.aioredis') as mock_aioredis:
mock_aioredis.from_url = MagicMock(return_value=mock_redis)
result = await get_pending_payload_from_redis(333444)
assert result == 'ref_from_redis'