- Removed the MetricsManager initialization from `run_helper.py` to avoid duplication, as metrics are now handled in `main.py`. - Updated logging levels in `server_prometheus.py` and `metrics_middleware.py` to use debug instead of info for less critical messages. - Added metrics configuration to `BaseDependencyFactory` for better management of metrics settings. - Deleted the obsolete `metrics_exporter.py` file to streamline the codebase. - Updated various tests to reflect changes in the metrics handling and ensure proper functionality.
243 lines
11 KiB
Python
243 lines
11 KiB
Python
import pytest
|
||
from unittest.mock import Mock, AsyncMock, patch, MagicMock
|
||
from pathlib import Path
|
||
from datetime import datetime
|
||
|
||
from helper_bot.handlers.voice.services import VoiceBotService
|
||
from helper_bot.handlers.voice.exceptions import VoiceMessageError, AudioProcessingError
|
||
|
||
|
||
class TestVoiceBotService:
|
||
"""Тесты для VoiceBotService"""
|
||
|
||
@pytest.fixture
|
||
def mock_bot_db(self):
|
||
"""Мок для базы данных"""
|
||
mock_db = Mock()
|
||
mock_db.settings = {
|
||
'Settings': {'logs': True},
|
||
'Telegram': {'important_logs': 'test_chat_id'}
|
||
}
|
||
return mock_db
|
||
|
||
@pytest.fixture
|
||
def mock_settings(self):
|
||
"""Мок для настроек"""
|
||
return {
|
||
'Settings': {'logs': True},
|
||
'Telegram': {'preview_link': True}
|
||
}
|
||
|
||
@pytest.fixture
|
||
def voice_service(self, mock_bot_db, mock_settings):
|
||
"""Экземпляр VoiceBotService для тестов"""
|
||
return VoiceBotService(mock_bot_db, mock_settings)
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_get_welcome_sticker_success(self, voice_service, mock_settings):
|
||
"""Тест успешного получения стикера"""
|
||
with patch('pathlib.Path.rglob') as mock_rglob:
|
||
mock_rglob.return_value = ['/path/to/sticker1.tgs', '/path/to/sticker2.tgs']
|
||
|
||
sticker = await voice_service.get_welcome_sticker()
|
||
|
||
assert sticker is not None
|
||
mock_rglob.assert_called_once()
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_get_welcome_sticker_no_stickers(self, voice_service, mock_settings):
|
||
"""Тест получения стикера когда их нет"""
|
||
with patch('pathlib.Path.rglob') as mock_rglob:
|
||
mock_rglob.return_value = []
|
||
|
||
sticker = await voice_service.get_welcome_sticker()
|
||
|
||
assert sticker is None
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_get_welcome_sticker_only_webp_files(self, voice_service, mock_settings):
|
||
"""Тест получения стикера когда есть только webp файлы"""
|
||
with patch('pathlib.Path.rglob') as mock_rglob:
|
||
mock_rglob.return_value = ['/path/to/sticker1.webp', '/path/to/sticker2.webp']
|
||
|
||
sticker = await voice_service.get_welcome_sticker()
|
||
|
||
# Проверяем, что стикер не None (метод ищет файлы по паттерну Hello_*)
|
||
assert sticker is not None
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_get_welcome_sticker_mixed_files(self, voice_service, mock_settings):
|
||
"""Тест получения стикера когда есть смешанные файлы"""
|
||
with patch('pathlib.Path.rglob') as mock_rglob:
|
||
mock_rglob.return_value = [
|
||
'/path/to/sticker1.webp',
|
||
'/path/to/sticker2.tgs',
|
||
'/path/to/sticker3.webp'
|
||
]
|
||
|
||
sticker = await voice_service.get_welcome_sticker()
|
||
|
||
assert sticker is not None
|
||
# Проверяем, что стикер не None (метод возвращает FSInputFile объект)
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_get_random_audio_success(self, voice_service, mock_bot_db):
|
||
"""Тест успешного получения случайного аудио"""
|
||
mock_bot_db.check_listen_audio = AsyncMock(return_value=['audio1', 'audio2'])
|
||
mock_bot_db.get_user_id_by_file_name = AsyncMock(return_value=123)
|
||
mock_bot_db.get_date_by_file_name = AsyncMock(return_value='2025-01-01 12:00:00')
|
||
mock_bot_db.get_user_emoji = AsyncMock(return_value='😊')
|
||
|
||
result = await voice_service.get_random_audio(456)
|
||
|
||
assert result is not None
|
||
assert len(result) == 3
|
||
# Проверяем, что результат содержит ожидаемые данные, но не проверяем точное значение audio
|
||
assert result[0] in ['audio1', 'audio2']
|
||
assert result[1] == '2025-01-01 12:00:00'
|
||
assert result[2] == '😊'
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_get_random_audio_no_audio(self, voice_service, mock_bot_db):
|
||
"""Тест получения аудио когда их нет"""
|
||
mock_bot_db.check_listen_audio = AsyncMock(return_value=[])
|
||
|
||
result = await voice_service.get_random_audio(456)
|
||
|
||
assert result is None
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_get_random_audio_single_audio(self, voice_service, mock_bot_db):
|
||
"""Тест получения аудио когда есть только одно"""
|
||
mock_bot_db.check_listen_audio = AsyncMock(return_value=['audio1'])
|
||
mock_bot_db.get_user_id_by_file_name = AsyncMock(return_value=123)
|
||
mock_bot_db.get_date_by_file_name = AsyncMock(return_value='2025-01-01 12:00:00')
|
||
mock_bot_db.get_user_emoji = AsyncMock(return_value='😊')
|
||
|
||
result = await voice_service.get_random_audio(456)
|
||
|
||
assert result is not None
|
||
assert len(result) == 3
|
||
assert result[0] == 'audio1'
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_mark_audio_as_listened_success(self, voice_service, mock_bot_db):
|
||
"""Тест успешной пометки аудио как прослушанного"""
|
||
mock_bot_db.mark_listened_audio = AsyncMock()
|
||
|
||
await voice_service.mark_audio_as_listened('test_audio', 123)
|
||
|
||
mock_bot_db.mark_listened_audio.assert_called_once_with('test_audio', user_id=123)
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_clear_user_listenings_success(self, voice_service, mock_bot_db):
|
||
"""Тест успешной очистки прослушиваний"""
|
||
mock_bot_db.delete_listen_count_for_user = AsyncMock()
|
||
|
||
await voice_service.clear_user_listenings(123)
|
||
|
||
mock_bot_db.delete_listen_count_for_user.assert_called_once_with(123)
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_get_remaining_audio_count_success(self, voice_service, mock_bot_db):
|
||
"""Тест получения количества оставшихся аудио"""
|
||
mock_bot_db.check_listen_audio = AsyncMock(return_value=['audio1', 'audio2', 'audio3'])
|
||
|
||
result = await voice_service.get_remaining_audio_count(123)
|
||
|
||
assert result == 3
|
||
mock_bot_db.check_listen_audio.assert_called_once_with(user_id=123)
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_get_remaining_audio_count_zero(self, voice_service, mock_bot_db):
|
||
"""Тест получения количества оставшихся аудио когда их нет"""
|
||
mock_bot_db.check_listen_audio = AsyncMock(return_value=[])
|
||
|
||
result = await voice_service.get_remaining_audio_count(123)
|
||
|
||
assert result == 0
|
||
mock_bot_db.check_listen_audio.assert_called_once_with(user_id=123)
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_send_welcome_messages_success(self, voice_service, mock_bot_db, mock_settings):
|
||
"""Тест успешной отправки приветственных сообщений"""
|
||
mock_message = Mock()
|
||
mock_message.from_user.id = 123
|
||
mock_message.answer = AsyncMock()
|
||
mock_message.answer.return_value = Mock()
|
||
mock_message.answer_sticker = AsyncMock()
|
||
|
||
with patch.object(voice_service, 'get_welcome_sticker') as mock_sticker:
|
||
mock_sticker.return_value = 'test_sticker.tgs'
|
||
|
||
await voice_service.send_welcome_messages(mock_message, '😊')
|
||
|
||
# Проверяем, что сообщения отправлены
|
||
assert mock_message.answer.call_count >= 1
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_send_welcome_messages_no_sticker(self, voice_service, mock_bot_db, mock_settings):
|
||
"""Тест отправки приветственных сообщений без стикера"""
|
||
mock_message = Mock()
|
||
mock_message.from_user.id = 123
|
||
mock_message.answer = AsyncMock()
|
||
mock_message.answer.return_value = Mock()
|
||
|
||
with patch.object(voice_service, 'get_welcome_sticker') as mock_sticker:
|
||
mock_sticker.return_value = None
|
||
|
||
await voice_service.send_welcome_messages(mock_message, '😊')
|
||
|
||
# Проверяем, что сообщения отправлены
|
||
assert mock_message.answer.call_count >= 1
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_send_welcome_messages_with_sticker(self, voice_service, mock_bot_db, mock_settings):
|
||
"""Тест отправки приветственных сообщений со стикером"""
|
||
mock_message = Mock()
|
||
mock_message.from_user.id = 123
|
||
mock_message.answer = AsyncMock()
|
||
mock_message.answer.return_value = Mock()
|
||
mock_message.answer_sticker = AsyncMock()
|
||
|
||
with patch.object(voice_service, 'get_welcome_sticker') as mock_sticker:
|
||
mock_sticker.return_value = 'test_sticker.tgs'
|
||
|
||
await voice_service.send_welcome_messages(mock_message, '😊')
|
||
|
||
# Проверяем, что сообщения отправлены
|
||
assert mock_message.answer.call_count >= 1
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_get_welcome_sticker_with_tgs_files(self, voice_service, mock_settings):
|
||
"""Тест получения стикера когда есть .tgs файлы"""
|
||
with patch('pathlib.Path.rglob') as mock_rglob:
|
||
mock_rglob.return_value = ['/path/to/sticker1.tgs', '/path/to/sticker2.tgs']
|
||
|
||
sticker = await voice_service.get_welcome_sticker()
|
||
|
||
assert sticker is not None
|
||
# Проверяем, что стикер не None (метод возвращает FSInputFile объект)
|
||
|
||
def test_service_initialization(self, mock_bot_db, mock_settings):
|
||
"""Тест инициализации сервиса"""
|
||
service = VoiceBotService(mock_bot_db, mock_settings)
|
||
|
||
assert service.bot_db == mock_bot_db
|
||
assert service.settings == mock_settings
|
||
|
||
def test_service_attributes(self, voice_service):
|
||
"""Тест атрибутов сервиса"""
|
||
assert hasattr(voice_service, 'bot_db')
|
||
assert hasattr(voice_service, 'settings')
|
||
assert hasattr(voice_service, 'get_welcome_sticker')
|
||
assert hasattr(voice_service, 'get_random_audio')
|
||
assert hasattr(voice_service, 'mark_audio_as_listened')
|
||
assert hasattr(voice_service, 'clear_user_listenings')
|
||
assert hasattr(voice_service, 'get_remaining_audio_count')
|
||
assert hasattr(voice_service, 'send_welcome_messages')
|
||
|
||
|
||
if __name__ == '__main__':
|
||
pytest.main([__file__])
|