This commit is contained in:
2025-11-16 12:36:02 +09:00
parent 3a25e6a4cb
commit eb3f3807fd
61 changed files with 1438 additions and 1139 deletions

View File

@@ -0,0 +1,163 @@
#!/usr/bin/env python3
"""
Тест всех новых функций: пакетного добавления счетов и админских хэндлеров
"""
import asyncio
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from src.core.database import async_session_maker, engine
from src.core.services import UserService, LotteryService, ParticipationService
from src.utils.account_utils import validate_account_number, format_account_number, mask_account_number
from src.display.winner_display import format_winner_display
import random
async def test_comprehensive_features():
print("🧪 Комплексное тестирование всех функций")
print("="*60)
async with async_session_maker() as session:
# 1. Создаем тестовых пользователей с номерами счетов
print("\n1. 📝 Создание тестовых пользователей:")
test_users = []
test_accounts = []
for i in range(5):
# Генерируем уникальные данные
unique_id = random.randint(10000000, 99999999)
account = f"{random.randint(10,99)}-{random.randint(10,99)}-{random.randint(10,99)}-{random.randint(10,99)}-{random.randint(10,99)}-{random.randint(10,99)}-{random.randint(10,99)}-{random.randint(10,99)}"
user = await UserService.get_or_create_user(
session,
telegram_id=unique_id,
username=f'test_user_{i}_{unique_id}',
first_name=f'Тестовый{i}',
last_name=f'Пользователь{i}'
)
# Устанавливаем номер счёта
success = await UserService.set_account_number(session, user.telegram_id, account)
if success:
test_users.append(user)
test_accounts.append(account)
print(f"✅ Пользователь {i+1}: {user.first_name} ({account})")
else:
print(f"Не удалось создать пользователя {i+1}")
# 2. Создаем тестовый розыгрыш
print(f"\n2. 🎯 Создание тестового розыгрыша:")
lottery = await LotteryService.create_lottery(
session,
title="Тест массовых операций",
description="Розыгрыш для тестирования массовых операций",
prizes=["Приз 1", "Приз 2"],
creator_id=1
)
print(f"✅ Розыгрыш создан: {lottery.title}")
# 3. Тестируем массовое добавление по номерам счетов
print(f"\n3. 🏦 Массовое добавление по номерам счетов:")
accounts_to_add = test_accounts[:3] # Первые 3
print(f"Добавляем {len(accounts_to_add)} счетов: {', '.join(accounts_to_add)}")
results = await ParticipationService.add_participants_by_accounts_bulk(
session, lottery.id, accounts_to_add
)
print(f"📊 Результат:")
print(f" ✅ Добавлено: {results['added']}")
print(f" ⚠️ Пропущено: {results['skipped']}")
print(f" ❌ Ошибок: {len(results['errors'])}")
# 4. Проверяем участников
print(f"\n4. 👥 Проверка участников:")
participants = await ParticipationService.get_participants(session, lottery.id)
print(f"Участников в розыгрыше: {len(participants)}")
for participant in participants:
print(f"{participant.first_name} ({participant.account_number})")
# 5. Тестируем настройки отображения победителей
print(f"\n5. 🎭 Тестирование настроек отображения:")
for display_type in ["username", "chat_id", "account_number"]:
await LotteryService.set_winner_display_type(session, lottery.id, display_type)
lottery.winner_display_type = display_type # Обновляем локально
if participants:
test_participant = participants[0]
public_display = format_winner_display(test_participant, lottery, show_sensitive_data=False)
admin_display = format_winner_display(test_participant, lottery, show_sensitive_data=True)
print(f" 📺 Тип {display_type}:")
print(f" 👥 Публично: {public_display}")
print(f" 🔧 Админ: {admin_display}")
# 6. Тестируем массовое удаление по счетам
print(f"\n6. 🗑️ Массовое удаление по номерам счетов:")
accounts_to_remove = test_accounts[:2] # Первые 2
print(f"Удаляем {len(accounts_to_remove)} счетов")
results = await ParticipationService.remove_participants_by_accounts_bulk(
session, lottery.id, accounts_to_remove
)
print(f"📊 Результат:")
print(f" ✅ Удалено: {results['removed']}")
print(f" ⚠️ Не найдено: {results['not_found']}")
print(f" ❌ Ошибок: {len(results['errors'])}")
# 7. Проверяем оставшихся участников
print(f"\n7. 👥 Проверка оставшихся участников:")
remaining_participants = await ParticipationService.get_participants(session, lottery.id)
print(f"Участников осталось: {len(remaining_participants)}")
for participant in remaining_participants:
print(f"{participant.first_name} ({participant.account_number})")
# 8. Тестируем методы управления розыгрышем
print(f"\n8. ⚙️ Тестирование управления розыгрышем:")
# Деактивируем
success = await LotteryService.set_lottery_active(session, lottery.id, False)
print(f" 🔴 Деактивация: {'' if success else ''}")
# Активируем обратно
success = await LotteryService.set_lottery_active(session, lottery.id, True)
print(f" 🟢 Активация: {'' if success else ''}")
# Завершаем
success = await LotteryService.complete_lottery(session, lottery.id)
print(f" 🏁 Завершение: {'' if success else ''}")
# 9. Тестируем валидацию счетов с неправильными форматами
print(f"\n9. 🔍 Тестирование валидации:")
invalid_accounts = [
"invalid-account",
"12345", # Слишком короткий
"12-34-56-78", # Неполный
"ab-cd-ef-gh-12-34-56-78", # С буквами
"12-34-56-78-90-12-34-56-78" # Слишком длинный
]
results = await ParticipationService.add_participants_by_accounts_bulk(
session, lottery.id, invalid_accounts
)
print(f"📊 Результат добавления невалидных счетов:")
print(f" ✅ Добавлено: {results['added']}")
print(f" 🚫 Неверных форматов: {len(results['invalid_accounts'])}")
print(f" ❌ Ошибок: {len(results['errors'])}")
if results['invalid_accounts']:
print(f" 🚫 Неверные форматы:")
for invalid in results['invalid_accounts']:
print(f"{invalid}")
print(f"\n🎉 Все тесты завершены успешно!")
print(f"✅ Массовое добавление и удаление по счетам работает")
print(f"✅ Настройка отображения победителей работает")
print(f"✅ Управление розыгрышами работает")
print(f"✅ Валидация счетов работает")
if __name__ == "__main__":
asyncio.run(test_comprehensive_features())

View File

@@ -0,0 +1,111 @@
"""
Простой тест основной функциональности без многопоточности
"""
import asyncio
import sys
import os
# Добавляем путь к проекту
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from src.core.database import init_db, async_session_maker
from src.core.services import UserService, LotteryService
from src.utils.account_utils import generate_account_number, validate_account_number, mask_account_number
from src.display.winner_display import format_winner_display, validate_display_type
async def test_basic_functionality():
"""Простой тест основной функциональности"""
print("🧪 Тестирование основной функциональности")
print("=" * 50)
# Инициализируем базу данных
await init_db()
async with async_session_maker() as session:
# 1. Тест создания пользователя с номером счёта
print("\n1. 👤 Создание пользователя с номером счёта:")
test_account = "12-34-56-78-90-12-34-56"
user = await UserService.get_or_create_user(
session,
telegram_id=999999999,
username='test_client',
first_name='Тестовый',
last_name='Клиент'
)
success = await UserService.set_account_number(
session, user.telegram_id, test_account
)
if success:
print(f"✅ Пользователь создан и счёт {test_account} установлен")
else:
print(f"❌ Ошибка установки номера счёта")
# 2. Тест валидации номеров
print("\n2. 📋 Тестирование валидации номеров:")
test_cases = [
("12-34-56-78-90-12-34-56", True),
("invalid-number", False),
("12345678901234567890", False)
]
for number, expected in test_cases:
result = validate_account_number(number)
status = "" if result == expected else ""
print(f"{status} '{number}' -> {result}")
# 3. Тест маскирования
print("\n3. 🎭 Тестирование маскирования:")
masked = mask_account_number(test_account, show_last_digits=4)
print(f"Полный номер: {test_account}")
print(f"Маскированный: {masked}")
# 4. Тест поиска по счёту
print("\n4. 🔍 Тестирование поиска по номеру счёта:")
found_user = await UserService.get_user_by_account(session, test_account)
if found_user:
print(f"✅ Пользователь найден по номеру счёта: {found_user.first_name}")
else:
print(f"❌ Пользователь не найден")
# 5. Тест отображения победителей
print("\n5. 🎨 Тестирование отображения победителей:")
# Создаём тестовый розыгрыш
lottery = await LotteryService.create_lottery(
session,
title="Тест отображения",
description="Тестовый розыгрыш",
prizes=["Приз 1"],
creator_id=1
)
display_types = ['username', 'chat_id', 'account_number']
for display_type in display_types:
await LotteryService.set_winner_display_type(
session, lottery.id, display_type
)
updated_lottery = await LotteryService.get_lottery(session, lottery.id)
if updated_lottery:
public = format_winner_display(user, updated_lottery, show_sensitive_data=False)
admin = format_winner_display(user, updated_lottery, show_sensitive_data=True)
print(f"\n📺 Тип: {display_type}")
print(f" 👥 Публично: {public}")
print(f" 🔧 Админ: {admin}")
print("\n🎉 Основные тесты завершены успешно!")
if __name__ == "__main__":
asyncio.run(test_basic_functionality())

View File

@@ -0,0 +1,93 @@
#!/usr/bin/env python3
"""
Тест функциональности с чистыми данными
"""
import asyncio
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from src.core.database import async_session_maker, engine
from src.core.services import UserService, LotteryService
from src.utils.account_utils import validate_account_number, format_account_number, mask_account_number
from src.display.winner_display import format_winner_display
import random
async def test_features():
print("🧪 Тестирование с чистыми данными")
print("="*50)
async with async_session_maker() as session:
# Генерируем уникальные тестовые данные
unique_id = random.randint(1000000, 9999999)
test_account = f"{random.randint(10, 99)}-{random.randint(10, 99)}-{random.randint(10, 99)}-{random.randint(10, 99)}-{random.randint(10, 99)}-{random.randint(10, 99)}-{random.randint(10, 99)}-{random.randint(10, 99)}"
print(f"🆔 Используем уникальный ID: {unique_id}")
print(f"🔢 Используем номер счёта: {test_account}")
# 1. Создание пользователя
print(f"\n1. 👤 Создание пользователя:")
user = await UserService.get_or_create_user(
session,
telegram_id=unique_id,
username=f'test_user_{unique_id}',
first_name='Тестовый',
last_name='Пользователь'
)
print(f"✅ Пользователь создан: {user.first_name} {user.last_name}")
# 2. Установка номера счёта
print(f"\n2. 🔢 Установка номера счёта:")
success = await UserService.set_account_number(
session, user.telegram_id, test_account
)
if success:
print(f"✅ Номер счёта {test_account} установлен")
# Обновляем данные пользователя
await session.refresh(user)
print(f"✅ Подтверждено: {user.account_number}")
else:
print(f"Не удалось установить номер счёта")
return
# 3. Поиск пользователя по номеру
print(f"\n3. 🔍 Поиск по номеру счёта:")
found_user = await UserService.get_user_by_account(session, test_account)
if found_user:
print(f"✅ Пользователь найден: {found_user.first_name} {found_user.last_name}")
else:
print("❌ Пользователь не найден")
# 4. Тестирование маскирования
print(f"\n4. 🎭 Тестирование маскирования:")
masked = mask_account_number(test_account)
print(f"Полный номер: {test_account}")
print(f"Маскированный: {masked}")
# 5. Создание розыгрыша с типами отображения
print(f"\n5. 🎨 Тестирование отображения победителей:")
lottery = await LotteryService.create_lottery(
session,
title="Тест отображения",
description="Тестовый розыгрыш",
prizes=["Приз 1"],
creator_id=1
)
# Тестируем все типы отображения
for display_type in ["username", "chat_id", "account_number"]:
await LotteryService.set_winner_display_type(session, lottery.id, display_type)
lottery.winner_display_type = display_type # Обновляем локально
public_display = format_winner_display(user, lottery, show_sensitive_data=False)
admin_display = format_winner_display(user, lottery, show_sensitive_data=True)
print(f"\n📺 Тип: {display_type}")
print(f" 👥 Публично: {public_display}")
print(f" 🔧 Админ: {admin_display}")
print(f"\n🎉 Все тесты завершены успешно!")
if __name__ == "__main__":
asyncio.run(test_features())

View File

@@ -0,0 +1,57 @@
#!/usr/bin/env python3
"""
Тест для проверки смены типа отображения победителей
"""
import asyncio
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from src.core.database import async_session_maker
from src.core.services import LotteryService
from src.display.winner_display import validate_display_type
async def test_display_type_change():
"""Тестируем смену типа отображения"""
print("🧪 Тестирование смены типа отображения...")
async with async_session_maker() as session:
# Получаем первый розыгрыш
lottery = await LotteryService.get_lottery(session, 1)
if not lottery:
print("❌ Розыгрыш не найден")
return
print(f"📋 Розыгрыш: {lottery.title}")
print(f"🎭 Текущий тип: {getattr(lottery, 'winner_display_type', 'username')}")
# Проверяем валидацию разных типов
test_types = ['username', 'chat_id', 'account_number', 'invalid_type']
for test_type in test_types:
print(f"\n🧪 Тестируем тип: {test_type}")
is_valid = validate_display_type(test_type)
print(f" Валидация: {'' if is_valid else ''}")
if is_valid:
# Пытаемся изменить тип
success = await LotteryService.set_winner_display_type(session, lottery.id, test_type)
print(f" Сохранение: {'' if success else ''}")
if success:
# Проверяем что изменение применилось
updated_lottery = await LotteryService.get_lottery(session, lottery.id)
actual_type = getattr(updated_lottery, 'winner_display_type', 'username')
print(f" Новый тип: {actual_type}")
if actual_type == test_type:
print(f" Результат: ✅ Тип успешно изменен")
else:
print(f" Результат: ❌ Тип не изменился (ожидали {test_type}, получили {actual_type})")
else:
print(f" Результат: ❌ Ошибка при сохранении")
else:
print(f" Результат: ⚠️ Неверный тип (ожидаемо)")
if __name__ == "__main__":
asyncio.run(test_display_type_change())

277
tests/test_new_features.py Normal file
View File

@@ -0,0 +1,277 @@
"""
Тест новой функциональности: клиентские счета и многопоточность
"""
import asyncio
import sys
import os
# Добавляем путь к проекту
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from src.core.database import init_db, async_session_maker
from src.core.services import UserService, LotteryService
from src.utils.account_utils import generate_account_number, validate_account_number, mask_account_number
from src.utils.task_manager import task_manager, TaskPriority
from src.display.winner_display import format_winner_display, validate_display_type
from src.utils.async_decorators import get_task_stats, format_task_stats
import time
async def test_account_functionality():
"""Тест функций работы со счетами"""
print("🧪 Тестирование функций работы со счетами")
print("=" * 50)
async with async_session_maker() as session:
# Создаём тестовых пользователей
users_data = [
{
'telegram_id': 777000001,
'username': 'client1',
'first_name': 'Клиент',
'last_name': 'Первый',
'account': '12-34-56-78-90-12-34-56'
},
{
'telegram_id': 777000002,
'username': 'client2',
'first_name': 'Клиент',
'last_name': 'Второй',
'account': '11-22-33-44-55-66-77-88'
},
{
'telegram_id': 777000003,
'username': 'client3',
'first_name': 'Клиент',
'last_name': 'Третий',
'account': None # Без счёта
}
]
created_users = []
for user_data in users_data:
# Создаём пользователя
user = await UserService.get_or_create_user(
session,
telegram_id=user_data['telegram_id'],
username=user_data['username'],
first_name=user_data['first_name'],
last_name=user_data['last_name']
)
# Устанавливаем номер счёта, если есть
if user_data['account']:
success = await UserService.set_account_number(
session, user.telegram_id, user_data['account']
)
if success:
print(f"✅ Создан пользователь {user.first_name} со счётом {user_data['account']}")
else:
print(f"❌ Ошибка установки счёта для {user.first_name}")
else:
print(f"✅ Создан пользователь {user.first_name} без счёта")
created_users.append(user)
# Тесты валидации
print("\n📋 Тестирование валидации номеров счетов:")
test_numbers = [
("12-34-56-78-90-12-34-56", True), # Корректный
("12345678901234567890123456", False), # Без дефисов
("12-34-56-78-90-12-34", False), # Короткий
("12-34-56-78-90-12-34-56-78", False), # Длинный
("ab-cd-ef-gh-ij-kl-mn-op", False), # Буквы
("", False) # Пустой
]
for number, should_be_valid in test_numbers:
is_valid = validate_account_number(number)
status = "" if is_valid == should_be_valid else ""
print(f"{status} {number} -> {'Корректный' if is_valid else 'Некорректный'}")
# Тест маскирования
print("\n🎭 Тестирование маскирования номеров:")
test_account = "12-34-56-78-90-12-34-56"
for digits in [4, 6, 8]:
masked = mask_account_number(test_account, show_last_digits=digits)
print(f"Показать последние {digits} цифр: {masked}")
# Тест поиска по счёту
print("\n🔍 Тестирование поиска по номеру счёта:")
async with async_session_maker() as session:
# Полный номер
user = await UserService.get_user_by_account(session, "12-34-56-78-90-12-34-56")
if user:
print(f"✅ Найден пользователь по полному номеру: {user.first_name}")
# Поиск по части номера
users = await UserService.search_by_account(session, "12-34")
print(f"🔍 Найдено пользователей по шаблону '12-34': {len(users)}")
for user in users:
if user.account_number:
masked = mask_account_number(user.account_number, show_last_digits=6)
print(f"{user.first_name}: {masked}")
async def test_display_types():
"""Тест различных типов отображения победителей"""
print("\n🎨 Тестирование типов отображения победителей")
print("=" * 50)
async with async_session_maker() as session:
# Создаём розыгрыш
lottery = await LotteryService.create_lottery(
session,
title="Тест отображения победителей",
description="Розыгрыш для тестирования различных типов отображения",
prizes=["Первый приз", "Второй приз"],
creator_id=1
)
# Получаем пользователя со счётом
user = await UserService.get_user_by_account(session, "12-34-56-78-90-12-34-56")
if user and lottery:
print(f"👤 Тестируем отображение для пользователя: {user.first_name}")
print(f"💳 Номер счёта: {user.account_number}")
# Тестируем разные типы отображения
display_types = ['username', 'chat_id', 'account_number']
for display_type in display_types:
# Устанавливаем тип отображения
success = await LotteryService.set_winner_display_type(
session, lottery.id, display_type
)
if success:
# Получаем обновлённый розыгрыш
updated_lottery = await LotteryService.get_lottery(session, lottery.id)
# Тестируем отображение
public_display = format_winner_display(user, updated_lottery, show_sensitive_data=False)
admin_display = format_winner_display(user, updated_lottery, show_sensitive_data=True)
print(f"\n📺 Тип отображения: {display_type}")
print(f" 👥 Публичное: {public_display}")
print(f" 🔧 Админское: {admin_display}")
else:
print(f"❌ Ошибка установки типа отображения {display_type}")
else:
print("Не удалось создать тестовые данные")
async def test_multithreading():
"""Тест многопоточности"""
print("\n⚡ Тестирование системы многопоточности")
print("=" * 50)
# Запускаем менеджер задач
await task_manager.start()
# Функция-заглушка для тестирования
async def test_task(task_name: str, duration: float, user_id_arg: int):
print(f"🔄 Запуск задачи {task_name} для пользователя {user_id_arg}")
await asyncio.sleep(duration)
print(f"✅ Завершена задача {task_name} для пользователя {user_id_arg}")
return f"Результат {task_name}"
# Добавляем задачи разных приоритетов
tasks = [
("critical_task", 2.0, 100, TaskPriority.CRITICAL),
("high_task_1", 1.5, 200, TaskPriority.HIGH),
("normal_task_1", 1.0, 300, TaskPriority.NORMAL),
("normal_task_2", 1.2, 300, TaskPriority.NORMAL),
("high_task_2", 0.8, 200, TaskPriority.HIGH),
("low_task", 0.5, 400, TaskPriority.LOW)
]
print(f"📤 Добавляем {len(tasks)} задач...")
for task_name, duration, user_id, priority in tasks:
try:
task_id = await task_manager.add_task(
task_id=f"{task_name}_{int(time.time())}",
user_id=user_id,
func=test_task,
priority=priority,
timeout=10.0,
task_name=task_name,
duration=duration,
user_id_arg=user_id
)
print(f" Добавлена задача {task_name} (приоритет: {priority.name})")
except ValueError as e:
print(f" ❌ Ошибка добавления задачи {task_name}: {e}")
# Показываем статистику
print("\n📊 Начальная статистика:")
stats_text = await format_task_stats()
print(stats_text)
# Ждём выполнения задач
print("\n⏳ Ожидание выполнения задач...")
await asyncio.sleep(5.0)
# Показываем финальную статистику
print("\n📈 Финальная статистика:")
final_stats = await format_task_stats()
print(final_stats)
# Тестируем лимиты пользователя
print("\n🚧 Тестирование лимитов пользователя:")
# Пробуем добавить много задач одному пользователю
user_id = 999
added_tasks = 0
for i in range(8): # Больше чем лимит (5)
try:
await task_manager.add_task(
task_id=f"limit_test_{i}_{int(time.time())}",
user_id=user_id,
func=test_task,
priority=TaskPriority.NORMAL,
task_name=f"limit_test_{i}",
duration=0.1,
user_id_arg=user_id
)
added_tasks += 1
except ValueError as e:
print(f" 🛑 Лимит достигнут после {added_tasks} задач: {e}")
break
# Ждём немного и останавливаем менеджер
await asyncio.sleep(2.0)
await task_manager.stop()
async def main():
"""Главная функция теста"""
print("🚀 Запуск тестирования новой функциональности")
print("=" * 60)
# Инициализируем базу данных
await init_db()
try:
# Запускаем тесты
await test_account_functionality()
await test_display_types()
await test_multithreading()
print("\n🎉 Все тесты завершены успешно!")
print("=" * 60)
except Exception as e:
print(f"\n❌ Ошибка во время тестирования: {e}")
import traceback
traceback.print_exc()
if __name__ == "__main__":
asyncio.run(main())