Files
telegram-helper-bot/tests/test_auto_unban_integration.py

252 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import pytest
import sqlite3
import os
from datetime import datetime, timezone, timedelta
from unittest.mock import Mock, patch, AsyncMock
from helper_bot.utils.auto_unban_scheduler import AutoUnbanScheduler
class TestAutoUnbanIntegration:
"""Интеграционные тесты для автоматического разбана"""
@pytest.fixture
def test_db_path(self):
"""Путь к тестовой базе данных"""
return 'database/test_auto_unban.db'
@pytest.fixture
def setup_test_db(self, test_db_path):
"""Создает тестовую базу данных с таблицей blacklist"""
# Удаляем старую тестовую базу если она существует
if os.path.exists(test_db_path):
os.remove(test_db_path)
# Создаем новую базу данных
conn = sqlite3.connect(test_db_path)
cursor = conn.cursor()
# Создаем таблицу blacklist
cursor.execute('''
CREATE TABLE IF NOT EXISTS blacklist (
user_id INTEGER PRIMARY KEY,
user_name TEXT,
message_for_user TEXT,
date_to_unban TEXT
)
''')
# Добавляем тестовые данные
today = datetime.now(timezone(timedelta(hours=3))).strftime("%Y-%m-%d")
tomorrow = (datetime.now(timezone(timedelta(hours=3))) + timedelta(days=1)).strftime("%Y-%m-%d")
test_data = [
(123, "test_user1", "Test ban 1", today), # Разблокируется сегодня
(456, "test_user2", "Test ban 2", today), # Разблокируется сегодня
(789, "test_user3", "Test ban 3", tomorrow), # Разблокируется завтра
(999, "test_user4", "Test ban 4", None), # Навсегда заблокирован
]
cursor.executemany(
"INSERT INTO blacklist (user_id, user_name, message_for_user, date_to_unban) VALUES (?, ?, ?, ?)",
test_data
)
conn.commit()
conn.close()
yield test_db_path
# Очистка после тестов
if os.path.exists(test_db_path):
os.remove(test_db_path)
@pytest.fixture
def mock_bdf(self, test_db_path):
"""Создает мок фабрики зависимостей с тестовой базой"""
mock_factory = Mock()
mock_factory.settings = {
'Telegram': {
'group_for_logs': '-1001234567890',
'important_logs': '-1001234567891'
}
}
# Создаем реальный экземпляр базы данных с тестовым файлом
from database.db import BotDB
import os
current_dir = os.getcwd()
mock_factory.database = BotDB(current_dir, test_db_path)
return mock_factory
@pytest.fixture
def mock_bot(self):
"""Создает мок бота"""
mock_bot = Mock()
mock_bot.send_message = AsyncMock()
return mock_bot
@pytest.mark.asyncio
@patch('helper_bot.utils.auto_unban_scheduler.get_global_instance')
async def test_auto_unban_with_real_db(self, mock_get_instance, setup_test_db, mock_bdf, mock_bot):
"""Тест автоматического разбана с реальной базой данных"""
# Настройка моков
mock_get_instance.return_value = mock_bdf
# Создаем планировщик
scheduler = AutoUnbanScheduler()
scheduler.bot_db = mock_bdf.database
scheduler.set_bot(mock_bot)
# Проверяем начальное состояние базы
conn = sqlite3.connect(setup_test_db)
cursor = conn.cursor()
cursor.execute("SELECT COUNT(*) FROM blacklist")
initial_count = cursor.fetchone()[0]
assert initial_count == 4
# Выполняем автоматический разбан
await scheduler.auto_unban_users()
# Проверяем, что пользователи с сегодняшней датой разблокированы
cursor.execute("SELECT COUNT(*) FROM blacklist WHERE date_to_unban = ?",
(datetime.now(timezone(timedelta(hours=3))).strftime("%Y-%m-%d"),))
today_count = cursor.fetchone()[0]
assert today_count == 0
# Проверяем, что пользователи с завтрашней датой остались
tomorrow = (datetime.now(timezone(timedelta(hours=3))) + timedelta(days=1)).strftime("%Y-%m-%d")
cursor.execute("SELECT COUNT(*) FROM blacklist WHERE date_to_unban = ?", (tomorrow,))
tomorrow_count = cursor.fetchone()[0]
assert tomorrow_count == 1
# Проверяем, что навсегда заблокированные пользователи остались
cursor.execute("SELECT COUNT(*) FROM blacklist WHERE date_to_unban IS NULL")
permanent_count = cursor.fetchone()[0]
assert permanent_count == 1
# Проверяем общее количество записей
cursor.execute("SELECT COUNT(*) FROM blacklist")
final_count = cursor.fetchone()[0]
assert final_count == 2 # Остались только завтрашние и навсегда заблокированные
conn.close()
# Проверяем, что отчет был отправлен
mock_bot.send_message.assert_called_once()
@pytest.mark.asyncio
@patch('helper_bot.utils.auto_unban_scheduler.get_global_instance')
async def test_auto_unban_no_users_today(self, mock_get_instance, setup_test_db, mock_bdf, mock_bot):
"""Тест разбана когда нет пользователей для разблокировки сегодня"""
# Настройка моков
mock_get_instance.return_value = mock_bdf
# Удаляем пользователей с сегодняшней датой
conn = sqlite3.connect(setup_test_db)
cursor = conn.cursor()
today = datetime.now(timezone(timedelta(hours=3))).strftime("%Y-%m-%d")
cursor.execute("DELETE FROM blacklist WHERE date_to_unban = ?", (today,))
conn.commit()
conn.close()
# Создаем планировщик
scheduler = AutoUnbanScheduler()
scheduler.bot_db = mock_bdf.database
scheduler.set_bot(mock_bot)
# Выполняем автоматический разбан
await scheduler.auto_unban_users()
# Проверяем, что отчет не был отправлен (нет пользователей для разблокировки)
mock_bot.send_message.assert_not_called()
@pytest.mark.asyncio
@patch('helper_bot.utils.auto_unban_scheduler.get_global_instance')
async def test_auto_unban_database_error(self, mock_get_instance, setup_test_db, mock_bdf, mock_bot):
"""Тест обработки ошибок базы данных"""
# Настройка моков
mock_get_instance.return_value = mock_bdf
# Создаем планировщик
scheduler = AutoUnbanScheduler()
scheduler.bot_db = mock_bdf.database
scheduler.set_bot(mock_bot)
# Удаляем таблицу чтобы вызвать ошибку
conn = sqlite3.connect(setup_test_db)
cursor = conn.cursor()
cursor.execute("DROP TABLE blacklist")
conn.commit()
conn.close()
# Выполняем автоматический разбан
await scheduler.auto_unban_users()
# Проверяем, что отчет об ошибке был отправлен
mock_bot.send_message.assert_called_once()
call_args = mock_bot.send_message.call_args
assert call_args[1]['chat_id'] == '-1001234567891' # important_logs
assert "Ошибка автоматического разбана" in call_args[1]['text']
def test_date_format_consistency(self, setup_test_db, mock_bdf):
"""Тест консистентности формата дат"""
scheduler = AutoUnbanScheduler()
scheduler.bot_db = mock_bdf.database
# Проверяем, что дата в базе соответствует ожидаемому формату
conn = sqlite3.connect(setup_test_db)
cursor = conn.cursor()
cursor.execute("SELECT date_to_unban FROM blacklist WHERE date_to_unban IS NOT NULL LIMIT 1")
result = cursor.fetchone()
conn.close()
if result and result[0]:
date_str = result[0]
# Проверяем формат YYYY-MM-DD
assert len(date_str) == 10
assert date_str.count('-') == 2
assert date_str[:4].isdigit() # Год
assert date_str[5:7].isdigit() # Месяц
assert date_str[8:10].isdigit() # День
class TestSchedulerLifecycle:
"""Тесты жизненного цикла планировщика"""
def test_scheduler_start_stop(self):
"""Тест запуска и остановки планировщика"""
scheduler = AutoUnbanScheduler()
# Запускаем планировщик
scheduler.start_scheduler()
assert scheduler.scheduler.running
# Останавливаем планировщик (должно пройти без ошибок)
scheduler.stop_scheduler()
# APScheduler может не сразу остановиться, но это нормально
def test_scheduler_job_creation(self):
"""Тест создания задачи в планировщике"""
scheduler = AutoUnbanScheduler()
with patch.object(scheduler.scheduler, 'add_job') as mock_add_job:
scheduler.start_scheduler()
# Проверяем, что задача была создана с правильными параметрами
mock_add_job.assert_called_once()
call_args = mock_add_job.call_args
# Проверяем функцию
assert call_args[0][0] == scheduler.auto_unban_users
# Проверяем триггер (должен быть CronTrigger)
from apscheduler.triggers.cron import CronTrigger
assert isinstance(call_args[0][1], CronTrigger)
# Проверяем ID и имя задачи
assert call_args[1]['id'] == 'auto_unban_users'
assert call_args[1]['name'] == 'Автоматический разбан пользователей'
assert call_args[1]['replace_existing'] is True