196 lines
6.7 KiB
Python
196 lines
6.7 KiB
Python
"""
|
||
Тесты для helper_bot.handlers.admin.dependencies: AdminAccessMiddleware, get_bot_db, get_settings.
|
||
"""
|
||
|
||
from unittest.mock import AsyncMock, MagicMock, patch
|
||
|
||
import pytest
|
||
from helper_bot.handlers.admin.dependencies import (
|
||
AdminAccessMiddleware,
|
||
get_bot_db,
|
||
get_settings,
|
||
)
|
||
|
||
|
||
@pytest.mark.unit
|
||
@pytest.mark.asyncio
|
||
class TestAdminAccessMiddleware:
|
||
"""Тесты для AdminAccessMiddleware."""
|
||
|
||
@pytest.fixture
|
||
def middleware(self):
|
||
"""Экземпляр middleware."""
|
||
return AdminAccessMiddleware()
|
||
|
||
@pytest.fixture
|
||
def mock_handler(self):
|
||
"""Мок handler."""
|
||
return AsyncMock(return_value="handler_result")
|
||
|
||
@patch(
|
||
"helper_bot.handlers.admin.dependencies.check_access", new_callable=AsyncMock
|
||
)
|
||
async def test_access_granted_calls_handler(
|
||
self, mock_check_access, middleware, mock_handler
|
||
):
|
||
"""При доступе разрешён вызывается handler с event и data."""
|
||
mock_check_access.return_value = True
|
||
event = MagicMock()
|
||
event.from_user = MagicMock()
|
||
event.from_user.id = 123
|
||
event.from_user.username = "admin"
|
||
data = {"bot_db": MagicMock()}
|
||
|
||
result = await middleware(mock_handler, event, data)
|
||
|
||
mock_check_access.assert_awaited_once_with(123, data["bot_db"])
|
||
mock_handler.assert_awaited_once_with(event, data)
|
||
assert result == "handler_result"
|
||
|
||
@patch(
|
||
"helper_bot.handlers.admin.dependencies.check_access", new_callable=AsyncMock
|
||
)
|
||
async def test_access_denied_answers_and_does_not_call_handler(
|
||
self, mock_check_access, middleware, mock_handler
|
||
):
|
||
"""При доступе запрещён отправляется ответ и handler не вызывается."""
|
||
mock_check_access.return_value = False
|
||
event = MagicMock()
|
||
event.from_user = MagicMock()
|
||
event.from_user.id = 456
|
||
event.from_user.username = "user"
|
||
event.answer = AsyncMock()
|
||
data = {"bot_db": MagicMock()}
|
||
|
||
result = await middleware(mock_handler, event, data)
|
||
|
||
mock_check_access.assert_awaited_once()
|
||
event.answer.assert_awaited_once_with("Доступ запрещен!")
|
||
mock_handler.assert_not_awaited()
|
||
assert result is None
|
||
|
||
@patch(
|
||
"helper_bot.handlers.admin.dependencies.check_access", new_callable=AsyncMock
|
||
)
|
||
@patch("helper_bot.handlers.admin.dependencies.get_global_instance")
|
||
async def test_fallback_get_db_from_global_when_bot_db_missing(
|
||
self, mock_get_global, mock_check_access, middleware, mock_handler
|
||
):
|
||
"""Если bot_db нет в data, берётся из get_global_instance().get_db()."""
|
||
mock_check_access.return_value = True
|
||
mock_bdf = MagicMock()
|
||
mock_bdf.get_db.return_value = MagicMock()
|
||
mock_get_global.return_value = mock_bdf
|
||
event = MagicMock()
|
||
event.from_user = MagicMock()
|
||
event.from_user.id = 1
|
||
event.from_user.username = "u"
|
||
data = {}
|
||
|
||
await middleware(mock_handler, event, data)
|
||
|
||
mock_get_global.assert_called_once()
|
||
mock_bdf.get_db.assert_called_once()
|
||
mock_check_access.assert_awaited_once_with(1, mock_bdf.get_db.return_value)
|
||
|
||
@patch(
|
||
"helper_bot.handlers.admin.dependencies.check_access", new_callable=AsyncMock
|
||
)
|
||
async def test_event_without_from_user_calls_handler(
|
||
self, mock_check_access, middleware, mock_handler
|
||
):
|
||
"""Если у event нет from_user, handler вызывается (проверка доступа не выполняется)."""
|
||
|
||
class EventWithoutUser:
|
||
pass
|
||
|
||
event = EventWithoutUser()
|
||
data = {}
|
||
|
||
result = await middleware(mock_handler, event, data)
|
||
|
||
mock_check_access.assert_not_awaited()
|
||
mock_handler.assert_awaited_once_with(event, data)
|
||
assert result == "handler_result"
|
||
|
||
@patch(
|
||
"helper_bot.handlers.admin.dependencies.check_access", new_callable=AsyncMock
|
||
)
|
||
async def test_handler_typeerror_missing_data_calls_handler_without_data(
|
||
self, mock_check_access, middleware
|
||
):
|
||
"""При TypeError из-за отсутствия data вызывается handler(event) без data."""
|
||
mock_check_access.return_value = True
|
||
call_count = 0
|
||
|
||
async def handler(event, data=None):
|
||
nonlocal call_count
|
||
call_count += 1
|
||
if call_count == 1 and data is not None:
|
||
raise TypeError("missing 1 required positional argument: 'data'")
|
||
return "ok"
|
||
|
||
handler.__name__ = "test_handler"
|
||
event = MagicMock()
|
||
event.from_user = MagicMock()
|
||
event.from_user.id = 1
|
||
event.from_user.username = "u"
|
||
data = {"bot_db": MagicMock()}
|
||
|
||
result = await middleware(handler, event, data)
|
||
|
||
assert call_count == 2
|
||
assert result == "ok"
|
||
|
||
@patch(
|
||
"helper_bot.handlers.admin.dependencies.check_access", new_callable=AsyncMock
|
||
)
|
||
async def test_handler_other_exception_reraises(
|
||
self, mock_check_access, middleware
|
||
):
|
||
"""При другом исключении в handler оно пробрасывается."""
|
||
mock_check_access.return_value = True
|
||
|
||
async def handler(event, data):
|
||
raise ValueError("other error")
|
||
|
||
event = MagicMock()
|
||
event.from_user = MagicMock()
|
||
event.from_user.id = 1
|
||
event.from_user.username = "u"
|
||
data = {"bot_db": MagicMock()}
|
||
|
||
with pytest.raises(ValueError, match="other error"):
|
||
await middleware(handler, event, data)
|
||
|
||
|
||
@pytest.mark.unit
|
||
class TestDependencyProviders:
|
||
"""Тесты для get_bot_db и get_settings."""
|
||
|
||
@patch("helper_bot.handlers.admin.dependencies.get_global_instance")
|
||
def test_get_bot_db_returns_bdf_get_db(self, mock_get_global):
|
||
"""get_bot_db возвращает bdf.get_db()."""
|
||
mock_bdf = MagicMock()
|
||
mock_db = MagicMock()
|
||
mock_bdf.get_db.return_value = mock_db
|
||
mock_get_global.return_value = mock_bdf
|
||
|
||
result = get_bot_db()
|
||
|
||
mock_get_global.assert_called_once()
|
||
mock_bdf.get_db.assert_called_once()
|
||
assert result is mock_db
|
||
|
||
@patch("helper_bot.handlers.admin.dependencies.get_global_instance")
|
||
def test_get_settings_returns_bdf_settings(self, mock_get_global):
|
||
"""get_settings возвращает bdf.settings."""
|
||
mock_bdf = MagicMock()
|
||
mock_bdf.settings = {"Telegram": {"bot_token": "x"}}
|
||
mock_get_global.return_value = mock_bdf
|
||
|
||
result = get_settings()
|
||
|
||
mock_get_global.assert_called_once()
|
||
assert result == {"Telegram": {"bot_token": "x"}}
|