Add comprehensive NFO and media download tests
- Add 23 new unit tests for media downloads in test_nfo_service.py - Create test_nfo_integration.py with 10 integration tests - Test all media download scenarios (poster/logo/fanart) - Test various image sizes and configurations - Test concurrent NFO operations - Test error handling and edge cases - All 44 NFO service tests passing - All 10 integration tests passing
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
"""Unit tests for NFO service."""
|
||||
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from src.core.services.nfo_service import NFOService
|
||||
from src.core.services.tmdb_client import TMDBAPIError
|
||||
|
||||
@@ -408,3 +409,245 @@ class TestNFOServiceEdgeCases:
|
||||
# NFO now exists
|
||||
exists = await nfo_service.check_nfo_exists("Test Series")
|
||||
assert exists
|
||||
|
||||
|
||||
class TestMediaDownloads:
|
||||
"""Test media file (poster, logo, fanart) download functionality."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_download_media_all_enabled(self, nfo_service, tmp_path, mock_tmdb_data):
|
||||
"""Test downloading all media files when enabled."""
|
||||
series_folder = tmp_path / "Test Series"
|
||||
series_folder.mkdir()
|
||||
|
||||
with patch.object(nfo_service.image_downloader, 'download_all_media', new_callable=AsyncMock) as mock_download:
|
||||
mock_download.return_value = {
|
||||
"poster": True,
|
||||
"logo": True,
|
||||
"fanart": True
|
||||
}
|
||||
|
||||
results = await nfo_service._download_media_files(
|
||||
mock_tmdb_data,
|
||||
series_folder,
|
||||
download_poster=True,
|
||||
download_logo=True,
|
||||
download_fanart=True
|
||||
)
|
||||
|
||||
assert results["poster"] is True
|
||||
assert results["logo"] is True
|
||||
assert results["fanart"] is True
|
||||
mock_download.assert_called_once()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_download_media_poster_only(self, nfo_service, tmp_path, mock_tmdb_data):
|
||||
"""Test downloading only poster."""
|
||||
series_folder = tmp_path / "Test Series"
|
||||
series_folder.mkdir()
|
||||
|
||||
with patch.object(nfo_service.image_downloader, 'download_all_media', new_callable=AsyncMock) as mock_download:
|
||||
mock_download.return_value = {"poster": True}
|
||||
|
||||
results = await nfo_service._download_media_files(
|
||||
mock_tmdb_data,
|
||||
series_folder,
|
||||
download_poster=True,
|
||||
download_logo=False,
|
||||
download_fanart=False
|
||||
)
|
||||
|
||||
# Verify only poster URL was passed
|
||||
call_args = mock_download.call_args
|
||||
assert call_args.kwargs['poster_url'] is not None
|
||||
assert call_args.kwargs['logo_url'] is None
|
||||
assert call_args.kwargs['fanart_url'] is None
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_download_media_with_image_size(self, nfo_service, tmp_path, mock_tmdb_data):
|
||||
"""Test that image size configuration is used."""
|
||||
nfo_service.image_size = "w500"
|
||||
series_folder = tmp_path / "Test Series"
|
||||
series_folder.mkdir()
|
||||
|
||||
with patch.object(nfo_service.image_downloader, 'download_all_media', new_callable=AsyncMock) as mock_download:
|
||||
mock_download.return_value = {"poster": True}
|
||||
|
||||
await nfo_service._download_media_files(
|
||||
mock_tmdb_data,
|
||||
series_folder,
|
||||
download_poster=True,
|
||||
download_logo=False,
|
||||
download_fanart=False
|
||||
)
|
||||
|
||||
# Verify image size was used for poster
|
||||
call_args = mock_download.call_args
|
||||
poster_url = call_args.kwargs['poster_url']
|
||||
assert "w500" in poster_url
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_download_media_missing_poster_path(self, nfo_service, tmp_path):
|
||||
"""Test media download when poster path is missing."""
|
||||
series_folder = tmp_path / "Test Series"
|
||||
series_folder.mkdir()
|
||||
|
||||
tmdb_data_no_poster = {
|
||||
"id": 1,
|
||||
"name": "Test",
|
||||
"poster_path": None,
|
||||
"backdrop_path": "/backdrop.jpg",
|
||||
"images": {"logos": [{"file_path": "/logo.png"}]}
|
||||
}
|
||||
|
||||
with patch.object(nfo_service.image_downloader, 'download_all_media', new_callable=AsyncMock) as mock_download:
|
||||
mock_download.return_value = {}
|
||||
|
||||
await nfo_service._download_media_files(
|
||||
tmdb_data_no_poster,
|
||||
series_folder,
|
||||
download_poster=True,
|
||||
download_logo=True,
|
||||
download_fanart=True
|
||||
)
|
||||
|
||||
# Poster URL should be None
|
||||
call_args = mock_download.call_args
|
||||
assert call_args.kwargs['poster_url'] is None
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_download_media_no_logo_available(self, nfo_service, tmp_path):
|
||||
"""Test media download when logo is not available."""
|
||||
series_folder = tmp_path / "Test Series"
|
||||
series_folder.mkdir()
|
||||
|
||||
tmdb_data_no_logo = {
|
||||
"id": 1,
|
||||
"name": "Test",
|
||||
"poster_path": "/poster.jpg",
|
||||
"backdrop_path": "/backdrop.jpg",
|
||||
"images": {"logos": []} # Empty logos array
|
||||
}
|
||||
|
||||
with patch.object(nfo_service.image_downloader, 'download_all_media', new_callable=AsyncMock) as mock_download:
|
||||
mock_download.return_value = {"poster": True, "fanart": True}
|
||||
|
||||
await nfo_service._download_media_files(
|
||||
tmdb_data_no_logo,
|
||||
series_folder,
|
||||
download_poster=True,
|
||||
download_logo=True,
|
||||
download_fanart=True
|
||||
)
|
||||
|
||||
# Logo URL should be None
|
||||
call_args = mock_download.call_args
|
||||
assert call_args.kwargs['logo_url'] is None
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_download_media_all_disabled(self, nfo_service, tmp_path, mock_tmdb_data):
|
||||
"""Test that no downloads occur when all disabled."""
|
||||
series_folder = tmp_path / "Test Series"
|
||||
series_folder.mkdir()
|
||||
|
||||
with patch.object(nfo_service.image_downloader, 'download_all_media', new_callable=AsyncMock) as mock_download:
|
||||
mock_download.return_value = {}
|
||||
|
||||
await nfo_service._download_media_files(
|
||||
mock_tmdb_data,
|
||||
series_folder,
|
||||
download_poster=False,
|
||||
download_logo=False,
|
||||
download_fanart=False
|
||||
)
|
||||
|
||||
# All URLs should be None
|
||||
call_args = mock_download.call_args
|
||||
assert call_args.kwargs['poster_url'] is None
|
||||
assert call_args.kwargs['logo_url'] is None
|
||||
assert call_args.kwargs['fanart_url'] is None
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_download_media_fanart_uses_original_size(self, nfo_service, tmp_path, mock_tmdb_data):
|
||||
"""Test that fanart always uses original size regardless of config."""
|
||||
nfo_service.image_size = "w500"
|
||||
series_folder = tmp_path / "Test Series"
|
||||
series_folder.mkdir()
|
||||
|
||||
with patch.object(nfo_service.image_downloader, 'download_all_media', new_callable=AsyncMock) as mock_download:
|
||||
mock_download.return_value = {"fanart": True}
|
||||
|
||||
await nfo_service._download_media_files(
|
||||
mock_tmdb_data,
|
||||
series_folder,
|
||||
download_poster=False,
|
||||
download_logo=False,
|
||||
download_fanart=True
|
||||
)
|
||||
|
||||
# Fanart should use original size
|
||||
call_args = mock_download.call_args
|
||||
fanart_url = call_args.kwargs['fanart_url']
|
||||
assert "original" in fanart_url
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_download_media_logo_uses_original_size(self, nfo_service, tmp_path, mock_tmdb_data):
|
||||
"""Test that logo always uses original size."""
|
||||
nfo_service.image_size = "w500"
|
||||
series_folder = tmp_path / "Test Series"
|
||||
series_folder.mkdir()
|
||||
|
||||
with patch.object(nfo_service.image_downloader, 'download_all_media', new_callable=AsyncMock) as mock_download:
|
||||
mock_download.return_value = {"logo": True}
|
||||
|
||||
await nfo_service._download_media_files(
|
||||
mock_tmdb_data,
|
||||
series_folder,
|
||||
download_poster=False,
|
||||
download_logo=True,
|
||||
download_fanart=False
|
||||
)
|
||||
|
||||
# Logo should use original size
|
||||
call_args = mock_download.call_args
|
||||
logo_url = call_args.kwargs['logo_url']
|
||||
assert "original" in logo_url
|
||||
|
||||
|
||||
class TestNFOServiceConfiguration:
|
||||
"""Test NFO service with various configuration settings."""
|
||||
|
||||
def test_nfo_service_default_config(self, tmp_path):
|
||||
"""Test NFO service initialization with default config."""
|
||||
service = NFOService(
|
||||
tmdb_api_key="test_key",
|
||||
anime_directory=str(tmp_path)
|
||||
)
|
||||
|
||||
assert service.image_size == "original"
|
||||
assert service.auto_create is True
|
||||
|
||||
def test_nfo_service_custom_config(self, tmp_path):
|
||||
"""Test NFO service initialization with custom config."""
|
||||
service = NFOService(
|
||||
tmdb_api_key="test_key",
|
||||
anime_directory=str(tmp_path),
|
||||
image_size="w500",
|
||||
auto_create=False
|
||||
)
|
||||
|
||||
assert service.image_size == "w500"
|
||||
assert service.auto_create is False
|
||||
|
||||
def test_nfo_service_image_sizes(self, tmp_path):
|
||||
"""Test NFO service with various image sizes."""
|
||||
sizes = ["original", "w500", "w780", "w342"]
|
||||
|
||||
for size in sizes:
|
||||
service = NFOService(
|
||||
tmdb_api_key="test_key",
|
||||
anime_directory=str(tmp_path),
|
||||
image_size=size
|
||||
)
|
||||
assert service.image_size == size
|
||||
|
||||
|
||||
Reference in New Issue
Block a user