#!/usr/bin/env python3 """ Скрипт для тестирования rate limiting решения """ import asyncio import time from unittest.mock import AsyncMock, MagicMock from aiogram.types import Message, User, Chat from helper_bot.utils.rate_limiter import send_with_rate_limit from helper_bot.utils.rate_limit_monitor import rate_limit_monitor, get_rate_limit_summary async def test_rate_limiting(): """Тестирует rate limiting с имитацией отправки сообщений""" print("🚀 Начинаем тестирование rate limiting...") # Создаем мок объекты mock_bot = MagicMock() mock_user = User(id=123, is_bot=False, first_name="Test") mock_chat = Chat(id=456, type="private") # Создаем Message с bot в конструкторе mock_message = Message( message_id=1, date=int(time.time()), chat=mock_chat, from_user=mock_user, content_type="text", bot=mock_bot ) # Настраиваем мок для send_voice mock_bot.send_voice = AsyncMock(return_value=MagicMock(message_id=1)) # Функция для отправки голосового сообщения async def send_voice_test(): return await mock_bot.send_voice( chat_id=mock_chat.id, voice="test_voice_id" ) print("📊 Отправляем 5 сообщений подряд...") # Отправляем несколько сообщений подряд start_time = time.time() for i in range(5): print(f" Отправка сообщения {i+1}/5...") try: result = await send_with_rate_limit(send_voice_test, mock_chat.id) print(f" ✅ Сообщение {i+1} отправлено успешно") except Exception as e: print(f" ❌ Ошибка при отправке сообщения {i+1}: {e}") end_time = time.time() total_time = end_time - start_time print(f"\n⏱️ Общее время выполнения: {total_time:.2f} секунд") print(f"📈 Среднее время на сообщение: {total_time/5:.2f} секунд") # Показываем статистику print("\n📊 Статистика rate limiting:") summary = get_rate_limit_summary() for key, value in summary.items(): if isinstance(value, float): print(f" {key}: {value:.2f}") else: print(f" {key}: {value}") # Показываем детальную статистику print("\n🔍 Детальная статистика:") global_stats = rate_limit_monitor.get_global_stats() print(f" Всего запросов: {global_stats.total_requests}") print(f" Успешных: {global_stats.successful_requests}") print(f" Неудачных: {global_stats.failed_requests}") print(f" Процент успеха: {global_stats.success_rate:.1%}") print(f" Среднее время ожидания: {global_stats.average_wait_time:.2f}с") # Проверяем что rate limiting работает if total_time > 8: # Должно занять больше 8 секунд (5 сообщений * 1.6с минимум) print("\n✅ Rate limiting работает корректно - сообщения отправляются с задержкой") else: print("\n⚠️ Rate limiting может работать некорректно - сообщения отправлены слишком быстро") print("\n🎉 Тестирование завершено!") async def test_error_handling(): """Тестирует обработку ошибок""" print("\n🧪 Тестируем обработку ошибок...") # Создаем мок который будет падать с RetryAfter from aiogram.exceptions import TelegramRetryAfter mock_bot = MagicMock() mock_chat = Chat(id=789, type="private") call_count = 0 async def failing_send(): nonlocal call_count call_count += 1 if call_count <= 2: raise TelegramRetryAfter( method=MagicMock(), message="Flood control exceeded", retry_after=1 ) return MagicMock(message_id=call_count) mock_bot.send_voice = failing_send print("📤 Отправляем сообщение с имитацией RetryAfter ошибки...") start_time = time.time() try: result = await send_with_rate_limit(failing_send, mock_chat.id) end_time = time.time() print(f"✅ Сообщение отправлено после {call_count} попыток за {end_time - start_time:.2f}с") except Exception as e: print(f"❌ Ошибка: {e}") print("🎯 Тест обработки ошибок завершен!") async def main(): """Основная функция""" print("🔧 Тестирование решения Flood Control") print("=" * 50) # Сбрасываем статистику rate_limit_monitor.reset_stats() # Запускаем тесты await test_rate_limiting() await test_error_handling() print("\n" + "=" * 50) print("📋 Итоговая статистика:") summary = get_rate_limit_summary() for key, value in summary.items(): if isinstance(value, float): print(f" {key}: {value:.2f}") else: print(f" {key}: {value}") if __name__ == "__main__": asyncio.run(main())