fix linter, fix ci, fix tests

This commit is contained in:
2026-02-02 00:46:44 +03:00
parent 68041037bd
commit d87d4e492e
93 changed files with 1042 additions and 862 deletions

View File

@@ -7,19 +7,16 @@ from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from aiogram import types
from aiogram.fsm.context import FSMContext
from helper_bot.handlers.admin.admin_handlers import (
admin_panel,
cancel_ban_process,
confirm_ban,
get_banned_users,
get_last_users,
get_ml_stats,
process_ban_duration,
process_ban_reason,
process_ban_target,
start_ban_process,
)
from helper_bot.handlers.admin.admin_handlers import (admin_panel,
cancel_ban_process,
confirm_ban,
get_banned_users,
get_last_users,
get_ml_stats,
process_ban_duration,
process_ban_reason,
process_ban_target,
start_ban_process)
from helper_bot.handlers.admin.services import User as AdminUser
@@ -61,7 +58,9 @@ class TestAdminHandlers:
return db
@patch("helper_bot.handlers.admin.admin_handlers.get_reply_keyboard_admin")
async def test_admin_panel_sets_state_and_answers(self, mock_keyboard, mock_message, mock_state):
async def test_admin_panel_sets_state_and_answers(
self, mock_keyboard, mock_message, mock_state
):
"""admin_panel устанавливает состояние ADMIN и отправляет приветствие."""
mock_keyboard.return_value = MagicMock()
@@ -69,10 +68,18 @@ class TestAdminHandlers:
mock_state.set_state.assert_awaited_once_with("ADMIN")
mock_message.answer.assert_awaited_once()
assert "админк" in mock_message.answer.call_args[0][0].lower() or "добро" in mock_message.answer.call_args[0][0].lower()
assert (
"админк" in mock_message.answer.call_args[0][0].lower()
or "добро" in mock_message.answer.call_args[0][0].lower()
)
@patch("helper_bot.handlers.admin.admin_handlers.return_to_admin_menu", new_callable=AsyncMock)
async def test_cancel_ban_process_returns_to_menu(self, mock_return, mock_message, mock_state):
@patch(
"helper_bot.handlers.admin.admin_handlers.return_to_admin_menu",
new_callable=AsyncMock,
)
async def test_cancel_ban_process_returns_to_menu(
self, mock_return, mock_message, mock_state
):
"""cancel_ban_process вызывает return_to_admin_menu."""
mock_state.get_state = AsyncMock(return_value="AWAIT_BAN_TARGET")
@@ -101,7 +108,10 @@ class TestAdminHandlers:
mock_service.get_last_users.assert_awaited_once()
mock_keyboard.assert_called_once()
mock_message.answer.assert_awaited_once()
assert "Список пользователей" in mock_message.answer.call_args[1]["text"] or "пользователей" in mock_message.answer.call_args[1]["text"]
assert (
"Список пользователей" in mock_message.answer.call_args[1]["text"]
or "пользователей" in mock_message.answer.call_args[1]["text"]
)
@patch("helper_bot.handlers.admin.admin_handlers.create_keyboard_with_pagination")
@patch("helper_bot.handlers.admin.admin_handlers.AdminService")
@@ -110,16 +120,23 @@ class TestAdminHandlers:
):
"""get_banned_users при пустом списке отправляет сообщение 'никого нет'."""
mock_service = MagicMock()
mock_service.get_banned_users_for_display = AsyncMock(return_value=("Текст", []))
mock_service.get_banned_users_for_display = AsyncMock(
return_value=("Текст", [])
)
mock_service_cls.return_value = mock_service
await get_banned_users(mock_message, mock_state, bot_db=mock_bot_db)
mock_message.answer.assert_awaited_once()
assert "никого нет" in mock_message.answer.call_args[1]["text"] or "заблокированных" in mock_message.answer.call_args[1]["text"]
assert (
"никого нет" in mock_message.answer.call_args[1]["text"]
or "заблокированных" in mock_message.answer.call_args[1]["text"]
)
@patch("helper_bot.handlers.admin.admin_handlers.get_global_instance")
async def test_get_ml_stats_disabled_answers_message(self, mock_get_global, mock_message, mock_state):
async def test_get_ml_stats_disabled_answers_message(
self, mock_get_global, mock_message, mock_state
):
"""get_ml_stats при отключённом scoring_manager отправляет сообщение об отключении."""
mock_bdf = MagicMock()
mock_bdf.get_scoring_manager.return_value = None
@@ -128,16 +145,31 @@ class TestAdminHandlers:
await get_ml_stats(mock_message, mock_state)
mock_message.answer.assert_awaited_once()
assert "ML" in mock_message.answer.call_args[0][0] or "RAG" in mock_message.answer.call_args[0][0] or "отключен" in mock_message.answer.call_args[0][0].lower()
assert (
"ML" in mock_message.answer.call_args[0][0]
or "RAG" in mock_message.answer.call_args[0][0]
or "отключен" in mock_message.answer.call_args[0][0].lower()
)
@patch("helper_bot.handlers.admin.admin_handlers.get_global_instance")
async def test_get_ml_stats_with_rag_and_deepseek(self, mock_get_global, mock_message, mock_state):
async def test_get_ml_stats_with_rag_and_deepseek(
self, mock_get_global, mock_message, mock_state
):
"""get_ml_stats при включённом scoring возвращает статистику."""
mock_scoring = MagicMock()
mock_scoring.get_stats = AsyncMock(return_value={
"rag": {"model_loaded": True, "vector_store": {"positive_count": 1, "negative_count": 0, "total_count": 1}},
"deepseek": {"enabled": True, "model": "test", "timeout": 30},
})
mock_scoring.get_stats = AsyncMock(
return_value={
"rag": {
"model_loaded": True,
"vector_store": {
"positive_count": 1,
"negative_count": 0,
"total_count": 1,
},
},
"deepseek": {"enabled": True, "model": "test", "timeout": 30},
}
)
mock_bdf = MagicMock()
mock_bdf.get_scoring_manager.return_value = mock_scoring
mock_get_global.return_value = mock_bdf
@@ -148,7 +180,9 @@ class TestAdminHandlers:
text = mock_message.answer.call_args[0][0]
assert "ML" in text or "RAG" in text or "DeepSeek" in text
async def test_start_ban_process_by_nick_sets_state_await_target(self, mock_message, mock_state):
async def test_start_ban_process_by_nick_sets_state_await_target(
self, mock_message, mock_state
):
"""start_ban_process при 'Бан по нику' устанавливает ban_type username и AWAIT_BAN_TARGET."""
mock_message.text = "Бан по нику"
@@ -159,9 +193,14 @@ class TestAdminHandlers:
assert call_kw.get("ban_type") == "username"
mock_state.set_state.assert_awaited_once_with("AWAIT_BAN_TARGET")
mock_message.answer.assert_awaited_once()
assert "username" in mock_message.answer.call_args[0][0].lower() or "ник" in mock_message.answer.call_args[0][0].lower()
assert (
"username" in mock_message.answer.call_args[0][0].lower()
or "ник" in mock_message.answer.call_args[0][0].lower()
)
async def test_start_ban_process_by_id_sets_ban_type_id(self, mock_message, mock_state):
async def test_start_ban_process_by_id_sets_ban_type_id(
self, mock_message, mock_state
):
"""start_ban_process при 'Бан по ID' устанавливает ban_type id."""
mock_message.text = "Бан по ID"
@@ -172,11 +211,20 @@ class TestAdminHandlers:
@patch("helper_bot.handlers.admin.admin_handlers.create_keyboard_for_ban_reason")
@patch("helper_bot.handlers.admin.admin_handlers.format_user_info")
@patch("helper_bot.handlers.admin.admin_handlers.return_to_admin_menu", new_callable=AsyncMock)
@patch(
"helper_bot.handlers.admin.admin_handlers.return_to_admin_menu",
new_callable=AsyncMock,
)
@patch("helper_bot.handlers.admin.admin_handlers.AdminService")
async def test_process_ban_target_user_not_found_returns_to_menu(
self, mock_service_cls, mock_return, mock_format, mock_keyboard,
mock_message, mock_state, mock_bot_db
self,
mock_service_cls,
mock_return,
mock_format,
mock_keyboard,
mock_message,
mock_state,
mock_bot_db,
):
"""process_ban_target при ненайденном пользователе по username возвращает в меню."""
mock_service = MagicMock()
@@ -196,8 +244,7 @@ class TestAdminHandlers:
@patch("helper_bot.handlers.admin.admin_handlers.format_user_info")
@patch("helper_bot.handlers.admin.admin_handlers.AdminService")
async def test_process_ban_reason_sets_state_await_duration(
self, mock_service_cls, mock_format, mock_keyboard,
mock_message, mock_state
self, mock_service_cls, mock_format, mock_keyboard, mock_message, mock_state
):
"""process_ban_reason сохраняет причину и переводит в AWAIT_BAN_DURATION."""
mock_state.get_state = AsyncMock(return_value="AWAIT_BAN_DETAILS")
@@ -218,12 +265,14 @@ class TestAdminHandlers:
self, mock_format, mock_keyboard, mock_message, mock_state
):
"""process_ban_duration при 'Навсегда' устанавливает ban_days=None."""
mock_state.get_data = AsyncMock(return_value={
"target_user_id": 1,
"target_username": "u",
"target_full_name": "U",
"ban_reason": "Спам",
})
mock_state.get_data = AsyncMock(
return_value={
"target_user_id": 1,
"target_username": "u",
"target_full_name": "U",
"ban_reason": "Спам",
}
)
mock_message.text = "Навсегда"
mock_format.return_value = "Подтверждение"
mock_keyboard.return_value = MagicMock()