223 lines
7.6 KiB
Python
223 lines
7.6 KiB
Python
"""Тесты для AutoModerationService."""
|
||
|
||
from unittest.mock import AsyncMock, MagicMock, patch
|
||
|
||
import pytest
|
||
from helper_bot.handlers.private.services import AutoModerationService, BotSettings
|
||
|
||
|
||
class TestAutoModerationService:
|
||
"""Тесты для сервиса авто-модерации."""
|
||
|
||
@pytest.fixture
|
||
def mock_db(self):
|
||
"""Создает мок базы данных."""
|
||
db = MagicMock()
|
||
db.get_auto_moderation_settings = AsyncMock()
|
||
return db
|
||
|
||
@pytest.fixture
|
||
def settings(self):
|
||
"""Создает настройки бота."""
|
||
return BotSettings(
|
||
group_for_posts="-123",
|
||
group_for_message="-456",
|
||
main_public="@test_channel",
|
||
group_for_logs="-789",
|
||
important_logs="-999",
|
||
preview_link="false",
|
||
logs="false",
|
||
test="false",
|
||
)
|
||
|
||
@pytest.fixture
|
||
def service(self, mock_db, settings):
|
||
"""Создает экземпляр сервиса."""
|
||
return AutoModerationService(mock_db, settings)
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_check_auto_action_returns_manual_when_score_is_none(
|
||
self, service, mock_db
|
||
):
|
||
"""Тест: возвращает manual когда score равен None."""
|
||
result = await service.check_auto_action(None)
|
||
assert result == "manual"
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_check_auto_action_returns_publish_when_score_above_threshold(
|
||
self, service, mock_db
|
||
):
|
||
"""Тест: возвращает publish когда score выше порога."""
|
||
mock_db.get_auto_moderation_settings.return_value = {
|
||
"auto_publish_enabled": True,
|
||
"auto_decline_enabled": False,
|
||
"auto_publish_threshold": 0.8,
|
||
"auto_decline_threshold": 0.4,
|
||
}
|
||
|
||
result = await service.check_auto_action(0.9)
|
||
|
||
assert result == "publish"
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_check_auto_action_returns_decline_when_score_below_threshold(
|
||
self, service, mock_db
|
||
):
|
||
"""Тест: возвращает decline когда score ниже порога."""
|
||
mock_db.get_auto_moderation_settings.return_value = {
|
||
"auto_publish_enabled": False,
|
||
"auto_decline_enabled": True,
|
||
"auto_publish_threshold": 0.8,
|
||
"auto_decline_threshold": 0.4,
|
||
}
|
||
|
||
result = await service.check_auto_action(0.3)
|
||
|
||
assert result == "decline"
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_check_auto_action_returns_manual_when_disabled(
|
||
self, service, mock_db
|
||
):
|
||
"""Тест: возвращает manual когда авто-действия отключены."""
|
||
mock_db.get_auto_moderation_settings.return_value = {
|
||
"auto_publish_enabled": False,
|
||
"auto_decline_enabled": False,
|
||
"auto_publish_threshold": 0.8,
|
||
"auto_decline_threshold": 0.4,
|
||
}
|
||
|
||
result = await service.check_auto_action(0.9)
|
||
|
||
assert result == "manual"
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_check_auto_action_returns_manual_when_score_in_middle(
|
||
self, service, mock_db
|
||
):
|
||
"""Тест: возвращает manual когда score между порогами."""
|
||
mock_db.get_auto_moderation_settings.return_value = {
|
||
"auto_publish_enabled": True,
|
||
"auto_decline_enabled": True,
|
||
"auto_publish_threshold": 0.8,
|
||
"auto_decline_threshold": 0.4,
|
||
}
|
||
|
||
result = await service.check_auto_action(0.6)
|
||
|
||
assert result == "manual"
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_check_auto_action_publish_at_exact_threshold(
|
||
self, service, mock_db
|
||
):
|
||
"""Тест: возвращает publish когда score равен порогу."""
|
||
mock_db.get_auto_moderation_settings.return_value = {
|
||
"auto_publish_enabled": True,
|
||
"auto_decline_enabled": False,
|
||
"auto_publish_threshold": 0.8,
|
||
"auto_decline_threshold": 0.4,
|
||
}
|
||
|
||
result = await service.check_auto_action(0.8)
|
||
|
||
assert result == "publish"
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_check_auto_action_decline_at_exact_threshold(
|
||
self, service, mock_db
|
||
):
|
||
"""Тест: возвращает decline когда score равен порогу."""
|
||
mock_db.get_auto_moderation_settings.return_value = {
|
||
"auto_publish_enabled": False,
|
||
"auto_decline_enabled": True,
|
||
"auto_publish_threshold": 0.8,
|
||
"auto_decline_threshold": 0.4,
|
||
}
|
||
|
||
result = await service.check_auto_action(0.4)
|
||
|
||
assert result == "decline"
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_log_auto_action_publish(self, service, settings):
|
||
"""Тест отправки лога для авто-публикации."""
|
||
mock_bot = MagicMock()
|
||
mock_bot.send_message = AsyncMock()
|
||
|
||
await service.log_auto_action(
|
||
bot=mock_bot,
|
||
action="publish",
|
||
author_id=12345,
|
||
author_name="Test User",
|
||
author_username="testuser",
|
||
rag_score=0.85,
|
||
post_text="Test post text",
|
||
)
|
||
|
||
mock_bot.send_message.assert_called_once()
|
||
call_kwargs = mock_bot.send_message.call_args[1]
|
||
assert call_kwargs["chat_id"] == settings.important_logs
|
||
assert "АВТО-ПУБЛИКАЦИЯ" in call_kwargs["text"]
|
||
assert "Test User" in call_kwargs["text"]
|
||
assert "0.85" in call_kwargs["text"]
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_log_auto_action_decline(self, service, settings):
|
||
"""Тест отправки лога для авто-отклонения."""
|
||
mock_bot = MagicMock()
|
||
mock_bot.send_message = AsyncMock()
|
||
|
||
await service.log_auto_action(
|
||
bot=mock_bot,
|
||
action="decline",
|
||
author_id=12345,
|
||
author_name="Test User",
|
||
author_username="testuser",
|
||
rag_score=0.25,
|
||
post_text="Test post text",
|
||
)
|
||
|
||
mock_bot.send_message.assert_called_once()
|
||
call_kwargs = mock_bot.send_message.call_args[1]
|
||
assert "АВТО-ОТКЛОНЕНИЕ" in call_kwargs["text"]
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_log_auto_action_handles_exception(self, service):
|
||
"""Тест обработки исключения при отправке лога."""
|
||
mock_bot = MagicMock()
|
||
mock_bot.send_message = AsyncMock(side_effect=Exception("Network error"))
|
||
|
||
# Не должно выбрасывать исключение
|
||
await service.log_auto_action(
|
||
bot=mock_bot,
|
||
action="publish",
|
||
author_id=12345,
|
||
author_name="Test User",
|
||
author_username="testuser",
|
||
rag_score=0.85,
|
||
post_text="Test post text",
|
||
)
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_log_auto_action_truncates_long_text(self, service):
|
||
"""Тест обрезки длинного текста в логе."""
|
||
mock_bot = MagicMock()
|
||
mock_bot.send_message = AsyncMock()
|
||
|
||
long_text = "a" * 300
|
||
|
||
await service.log_auto_action(
|
||
bot=mock_bot,
|
||
action="publish",
|
||
author_id=12345,
|
||
author_name="Test User",
|
||
author_username="testuser",
|
||
rag_score=0.85,
|
||
post_text=long_text,
|
||
)
|
||
|
||
call_kwargs = mock_bot.send_message.call_args[1]
|
||
# Текст должен быть обрезан до 200 символов + "..."
|
||
assert "..." in call_kwargs["text"]
|