176 lines
6.0 KiB
Python
176 lines
6.0 KiB
Python
import uuid
|
|
import pytest
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
from aiogram.types import Message, InlineKeyboardMarkup, CallbackQuery
|
|
from aiogram.filters import CommandObject
|
|
from datetime import datetime
|
|
|
|
from src.bot.handlers import get_router, AccessMiddleware
|
|
from src.processor.dto import EnrichedNewsItemDTO
|
|
|
|
@pytest.fixture
|
|
def mock_item():
|
|
return EnrichedNewsItemDTO(
|
|
title="Breakthrough in Quantum Computing",
|
|
url="https://example.com/quantum-breakthrough",
|
|
content_text="Researchers have achieved a new milestone in quantum supremacy...",
|
|
source="Example Domain News",
|
|
timestamp=datetime.now(),
|
|
relevance_score=9,
|
|
summary_ru="Исследователи достигли нового рубежа в квантовом превосходстве.",
|
|
anomalies_detected=["Quantum supremacy", "Room temperature superconductors"],
|
|
category="Science"
|
|
)
|
|
|
|
@pytest.fixture
|
|
def mock_storage(mock_item):
|
|
storage = AsyncMock()
|
|
storage.search.return_value = [mock_item]
|
|
storage.get_by_id.return_value = mock_item
|
|
storage.get_stats.return_value = {"total": 1, "AI": 1}
|
|
return storage
|
|
|
|
@pytest.fixture
|
|
def allowed_chat_id():
|
|
return "123456789"
|
|
|
|
@pytest.fixture
|
|
def router(mock_storage, allowed_chat_id):
|
|
return get_router(mock_storage, allowed_chat_id)
|
|
|
|
def get_handler(router, callback_name):
|
|
for handler in router.message.handlers:
|
|
if handler.callback.__name__ == callback_name:
|
|
return handler.callback
|
|
raise ValueError(f"Handler {callback_name} not found")
|
|
|
|
def get_callback_handler(router, callback_name):
|
|
for handler in router.callback_query.handlers:
|
|
if handler.callback.__name__ == callback_name:
|
|
return handler.callback
|
|
raise ValueError(f"Handler {callback_name} not found")
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_command_start_handler(router, allowed_chat_id):
|
|
handler = get_handler(router, "command_start_handler")
|
|
message = AsyncMock()
|
|
message.chat.id = int(allowed_chat_id)
|
|
message.from_user = MagicMock()
|
|
message.from_user.full_name = "Test User"
|
|
message.answer = AsyncMock()
|
|
|
|
await handler(message)
|
|
|
|
message.answer.assert_called_once()
|
|
args, kwargs = message.answer.call_args
|
|
assert "Welcome" in args[0] or "Trend-Scout" in args[0]
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_command_help_handler(router, allowed_chat_id):
|
|
handler = get_handler(router, "command_help_handler")
|
|
message = AsyncMock()
|
|
message.chat.id = int(allowed_chat_id)
|
|
message.answer = AsyncMock()
|
|
|
|
await handler(message)
|
|
|
|
message.answer.assert_called_once()
|
|
args, kwargs = message.answer.call_args
|
|
assert "/start" in args[0]
|
|
assert "/latest" in args[0]
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_command_latest_handler(router, mock_storage, allowed_chat_id):
|
|
handler = get_handler(router, "command_latest_handler")
|
|
message = AsyncMock()
|
|
message.chat.id = int(allowed_chat_id)
|
|
message.answer = AsyncMock()
|
|
command = CommandObject(prefix="/", command="latest", args=None)
|
|
|
|
await handler(message=message, command=command)
|
|
|
|
message.answer.assert_called_once()
|
|
args, kwargs = message.answer.call_args
|
|
assert "Latest news:" in args[0]
|
|
assert "reply_markup" in kwargs
|
|
assert isinstance(kwargs["reply_markup"], InlineKeyboardMarkup)
|
|
assert len(kwargs["reply_markup"].inline_keyboard) == 1
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_command_search_handler(router, mock_storage, allowed_chat_id):
|
|
handler = get_handler(router, "command_search_handler")
|
|
message = AsyncMock()
|
|
message.chat.id = int(allowed_chat_id)
|
|
message.answer = AsyncMock()
|
|
command = CommandObject(prefix="/", command="search", args="quantum")
|
|
|
|
await handler(message=message, command=command)
|
|
|
|
message.answer.assert_called_once()
|
|
args, kwargs = message.answer.call_args
|
|
assert "Search results:" in args[0]
|
|
assert "reply_markup" in kwargs
|
|
mock_storage.search.assert_called_once_with(query="quantum", limit=10)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_detail_callback_handler(router, mock_storage, mock_item):
|
|
handler = get_callback_handler(router, "detail_callback_handler")
|
|
callback = AsyncMock(spec=CallbackQuery)
|
|
item_id = str(uuid.uuid5(uuid.NAMESPACE_URL, mock_item.url))
|
|
callback.data = f"detail:{item_id}"
|
|
callback.message = AsyncMock()
|
|
callback.message.answer = AsyncMock()
|
|
callback.answer = AsyncMock()
|
|
|
|
await handler(callback)
|
|
|
|
mock_storage.get_by_id.assert_called_once_with(item_id)
|
|
callback.message.answer.assert_called_once()
|
|
args, kwargs = callback.message.answer.call_args
|
|
assert mock_item.title in args[0]
|
|
assert mock_item.summary_ru in args[0]
|
|
callback.answer.assert_called_once()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_command_stats_handler(router, mock_storage, allowed_chat_id):
|
|
handler = get_handler(router, "command_stats_handler")
|
|
message = AsyncMock()
|
|
message.chat.id = int(allowed_chat_id)
|
|
message.answer = AsyncMock()
|
|
|
|
await handler(message=message)
|
|
|
|
message.answer.assert_called_once()
|
|
args, kwargs = message.answer.call_args
|
|
assert "Database Statistics" in args[0]
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_access_middleware_allowed(allowed_chat_id):
|
|
middleware = AccessMiddleware(allowed_chat_id)
|
|
handler = AsyncMock()
|
|
event = MagicMock(spec=Message)
|
|
event.chat = MagicMock()
|
|
event.chat.id = int(allowed_chat_id)
|
|
event.answer = AsyncMock()
|
|
data = {}
|
|
|
|
await middleware(handler, event, data)
|
|
|
|
handler.assert_called_once_with(event, data)
|
|
event.answer.assert_not_called()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_access_middleware_denied(allowed_chat_id):
|
|
middleware = AccessMiddleware(allowed_chat_id)
|
|
handler = AsyncMock()
|
|
event = MagicMock(spec=Message)
|
|
event.chat = MagicMock()
|
|
event.chat.id = 999999999 # Different ID
|
|
event.answer = AsyncMock()
|
|
data = {}
|
|
|
|
await middleware(handler, event, data)
|
|
|
|
handler.assert_not_called()
|
|
event.answer.assert_called_once_with("Access Denied")
|