Переписал почти все тесты
feat: улучшено логирование и обработка скорингов в PostService и RagApiClient - Добавлены отладочные сообщения для передачи скорингов в функции обработки постов. - Обновлено логирование успешного получения скорингов из RAG API с дополнительной информацией. - Оптимизирована обработка скорингов в функции get_text_message для улучшения отладки. - Обновлены тесты для проверки новых функциональных возможностей и обработки ошибок.
This commit is contained in:
216
tests/test_s3_storage.py
Normal file
216
tests/test_s3_storage.py
Normal file
@@ -0,0 +1,216 @@
|
||||
"""
|
||||
Тесты для helper_bot.utils.s3_storage (S3StorageService).
|
||||
"""
|
||||
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from helper_bot.utils.s3_storage import S3StorageService
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
class TestS3StorageServiceInit:
|
||||
"""Тесты инициализации S3StorageService."""
|
||||
|
||||
def test_init_stores_params(self):
|
||||
"""Параметры сохраняются в атрибутах."""
|
||||
with patch("helper_bot.utils.s3_storage.aioboto3.Session"):
|
||||
service = S3StorageService(
|
||||
endpoint_url="http://s3",
|
||||
access_key="ak",
|
||||
secret_key="sk",
|
||||
bucket_name="bucket",
|
||||
region="eu-west-1",
|
||||
)
|
||||
assert service.endpoint_url == "http://s3"
|
||||
assert service.bucket_name == "bucket"
|
||||
assert service.region == "eu-west-1"
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
class TestS3StorageServiceGenerateS3Key:
|
||||
"""Тесты generate_s3_key."""
|
||||
|
||||
@pytest.fixture
|
||||
def service(self):
|
||||
"""Сервис без реального session."""
|
||||
with patch("helper_bot.utils.s3_storage.aioboto3.Session"):
|
||||
return S3StorageService(
|
||||
endpoint_url="http://s3",
|
||||
access_key="ak",
|
||||
secret_key="sk",
|
||||
bucket_name="b",
|
||||
)
|
||||
|
||||
def test_photo_key(self, service):
|
||||
"""Ключ для photo — photos/{id}.jpg."""
|
||||
key = service.generate_s3_key("photo", "file_123")
|
||||
assert key == "photos/file_123.jpg"
|
||||
|
||||
def test_video_key(self, service):
|
||||
"""Ключ для video — videos/{id}.mp4."""
|
||||
key = service.generate_s3_key("video", "vid_1")
|
||||
assert key == "videos/vid_1.mp4"
|
||||
|
||||
def test_audio_key(self, service):
|
||||
"""Ключ для audio — music/{id}.mp3."""
|
||||
key = service.generate_s3_key("audio", "a1")
|
||||
assert key == "music/a1.mp3"
|
||||
|
||||
def test_voice_key(self, service):
|
||||
"""Ключ для voice — voice/{id}.ogg."""
|
||||
key = service.generate_s3_key("voice", "v1")
|
||||
assert key == "voice/v1.ogg"
|
||||
|
||||
def test_other_key(self, service):
|
||||
"""Неизвестный тип — other/{id}.bin."""
|
||||
key = service.generate_s3_key("other", "x")
|
||||
assert key == "other/x.bin"
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.asyncio
|
||||
class TestS3StorageServiceUploadDownload:
|
||||
"""Тесты upload_file, download_file, file_exists, delete_file через мок session.client."""
|
||||
|
||||
@pytest.fixture
|
||||
def service(self):
|
||||
"""Сервис с замоканной session."""
|
||||
mock_session = MagicMock()
|
||||
mock_context = AsyncMock()
|
||||
mock_s3 = MagicMock()
|
||||
mock_s3.upload_file = AsyncMock()
|
||||
mock_s3.upload_fileobj = AsyncMock()
|
||||
mock_s3.download_file = AsyncMock()
|
||||
mock_s3.head_object = AsyncMock()
|
||||
mock_s3.delete_object = AsyncMock()
|
||||
mock_context.__aenter__.return_value = mock_s3
|
||||
mock_context.__aexit__.return_value = None
|
||||
mock_session.client.return_value = mock_context
|
||||
with patch("helper_bot.utils.s3_storage.aioboto3.Session", return_value=mock_session):
|
||||
s = S3StorageService(
|
||||
endpoint_url="http://s3",
|
||||
access_key="ak",
|
||||
secret_key="sk",
|
||||
bucket_name="bucket",
|
||||
)
|
||||
s._mock_s3 = mock_s3
|
||||
return s
|
||||
|
||||
async def test_upload_file_success(self, service):
|
||||
"""upload_file при успехе возвращает True."""
|
||||
result = await service.upload_file("/tmp/f", "key")
|
||||
assert result is True
|
||||
service._mock_s3.upload_file.assert_called_once()
|
||||
|
||||
async def test_upload_file_with_content_type(self, service):
|
||||
"""upload_file с content_type передаёт ExtraArgs."""
|
||||
await service.upload_file("/tmp/f", "key", content_type="image/jpeg")
|
||||
call_kwargs = service._mock_s3.upload_file.call_args[1]
|
||||
assert call_kwargs.get("ExtraArgs", {}).get("ContentType") == "image/jpeg"
|
||||
|
||||
async def test_upload_file_exception_returns_false(self, service):
|
||||
"""При исключении upload_file возвращает False."""
|
||||
service._mock_s3.upload_file = AsyncMock(side_effect=Exception("network error"))
|
||||
result = await service.upload_file("/tmp/f", "key")
|
||||
assert result is False
|
||||
|
||||
async def test_download_file_success(self, service):
|
||||
"""download_file при успехе возвращает True."""
|
||||
with patch("os.makedirs"):
|
||||
result = await service.download_file("key", "/tmp/out")
|
||||
assert result is True
|
||||
service._mock_s3.download_file.assert_called_once()
|
||||
|
||||
async def test_download_file_exception_returns_false(self, service):
|
||||
"""При исключении download_file возвращает False."""
|
||||
service._mock_s3.download_file = AsyncMock(side_effect=Exception("error"))
|
||||
with patch("os.makedirs"):
|
||||
result = await service.download_file("key", "/tmp/out")
|
||||
assert result is False
|
||||
|
||||
async def test_upload_fileobj_success(self, service):
|
||||
"""upload_fileobj при успехе возвращает True."""
|
||||
f = MagicMock()
|
||||
result = await service.upload_fileobj(f, "key")
|
||||
assert result is True
|
||||
service._mock_s3.upload_fileobj.assert_called_once()
|
||||
|
||||
async def test_file_exists_true(self, service):
|
||||
"""file_exists при успешном head_object возвращает True."""
|
||||
result = await service.file_exists("key")
|
||||
assert result is True
|
||||
|
||||
async def test_file_exists_false_on_exception(self, service):
|
||||
"""file_exists при исключении возвращает False."""
|
||||
service._mock_s3.head_object = AsyncMock(side_effect=Exception())
|
||||
result = await service.file_exists("key")
|
||||
assert result is False
|
||||
|
||||
async def test_delete_file_success(self, service):
|
||||
"""delete_file при успехе возвращает True."""
|
||||
result = await service.delete_file("key")
|
||||
assert result is True
|
||||
service._mock_s3.delete_object.assert_called_once_with(
|
||||
Bucket="bucket", Key="key"
|
||||
)
|
||||
|
||||
async def test_delete_file_exception_returns_false(self, service):
|
||||
"""При исключении delete_file возвращает False."""
|
||||
service._mock_s3.delete_object = AsyncMock(side_effect=Exception())
|
||||
result = await service.delete_file("key")
|
||||
assert result is False
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.asyncio
|
||||
class TestS3StorageServiceDownloadToTemp:
|
||||
"""Тесты download_to_temp."""
|
||||
|
||||
async def test_download_to_temp_success_returns_path(self):
|
||||
"""При успешном download возвращается путь к временному файлу."""
|
||||
mock_session = MagicMock()
|
||||
mock_context = AsyncMock()
|
||||
mock_s3 = MagicMock()
|
||||
mock_s3.download_file = AsyncMock()
|
||||
mock_context.__aenter__.return_value = mock_s3
|
||||
mock_context.__aexit__.return_value = None
|
||||
mock_session.client.return_value = mock_context
|
||||
with patch("helper_bot.utils.s3_storage.aioboto3.Session", return_value=mock_session):
|
||||
service = S3StorageService(
|
||||
endpoint_url="http://s3",
|
||||
access_key="ak",
|
||||
secret_key="sk",
|
||||
bucket_name="b",
|
||||
)
|
||||
with patch("os.makedirs"):
|
||||
path = await service.download_to_temp("photos/1.jpg")
|
||||
if path:
|
||||
assert Path(path).suffix in (".jpg", "")
|
||||
try:
|
||||
Path(path).unlink(missing_ok=True)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
async def test_download_to_temp_failure_returns_none(self):
|
||||
"""При неуспешном download возвращается None."""
|
||||
mock_session = MagicMock()
|
||||
mock_context = AsyncMock()
|
||||
mock_s3 = MagicMock()
|
||||
mock_s3.download_file = AsyncMock()
|
||||
mock_context.__aenter__.return_value = mock_s3
|
||||
mock_context.__aexit__.return_value = None
|
||||
mock_session.client.return_value = mock_context
|
||||
with patch("helper_bot.utils.s3_storage.aioboto3.Session", return_value=mock_session):
|
||||
service = S3StorageService(
|
||||
endpoint_url="http://s3",
|
||||
access_key="ak",
|
||||
secret_key="sk",
|
||||
bucket_name="b",
|
||||
)
|
||||
with patch.object(service, "download_file", AsyncMock(return_value=False)):
|
||||
path = await service.download_to_temp("key")
|
||||
assert path is None
|
||||
Reference in New Issue
Block a user