fix tests
This commit is contained in:
parent
8ae8b0cdfb
commit
f91875f6fc
104
fix_tests.py
Normal file
104
fix_tests.py
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Script to batch fix common test issues after API changes."""
|
||||||
|
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def fix_add_to_queue_calls(content: str) -> str:
|
||||||
|
"""Add serie_folder parameter to add_to_queue calls."""
|
||||||
|
# Pattern: add_to_queue(\n serie_id="...",
|
||||||
|
# Add: serie_folder="...",
|
||||||
|
pattern = r'(add_to_queue\(\s+serie_id="([^"]+)",)'
|
||||||
|
|
||||||
|
def replace_func(match):
|
||||||
|
serie_id = match.group(2)
|
||||||
|
# Extract just the series name without number if present
|
||||||
|
serie_folder = serie_id.split('-')[0] if '-' in serie_id else serie_id
|
||||||
|
return f'{match.group(1)}\n serie_folder="{serie_folder}",'
|
||||||
|
|
||||||
|
return re.sub(pattern, replace_func, content)
|
||||||
|
|
||||||
|
|
||||||
|
def fix_queue_status_response(content: str) -> str:
|
||||||
|
"""Fix queue status response structure - remove nested 'status' key."""
|
||||||
|
# Replace data["status"]["pending"] with data["pending_queue"]
|
||||||
|
content = re.sub(r'data\["status"\]\["pending"\]', 'data["pending_queue"]', content)
|
||||||
|
content = re.sub(r'data\["status"\]\["active"\]', 'data["active_downloads"]', content)
|
||||||
|
content = re.sub(r'data\["status"\]\["completed"\]', 'data["completed_downloads"]', content)
|
||||||
|
content = re.sub(r'data\["status"\]\["failed"\]', 'data["failed_downloads"]', content)
|
||||||
|
content = re.sub(r'data\["status"\]\["is_running"\]', 'data["is_running"]', content)
|
||||||
|
content = re.sub(r'data\["status"\]\["is_paused"\]', 'data["is_paused"]', content)
|
||||||
|
|
||||||
|
# Also fix response.json()["status"]["..."]
|
||||||
|
content = re.sub(r'response\.json\(\)\["status"\]\["pending"\]', 'response.json()["pending_queue"]', content)
|
||||||
|
content = re.sub(r'response\.json\(\)\["status"\]\["is_running"\]', 'response.json()["is_running"]', content)
|
||||||
|
content = re.sub(r'status\.json\(\)\["status"\]\["is_running"\]', 'status.json()["is_running"]', content)
|
||||||
|
content = re.sub(r'status\.json\(\)\["status"\]\["failed"\]', 'status.json()["failed_downloads"]', content)
|
||||||
|
content = re.sub(r'status\.json\(\)\["status"\]\["completed"\]', 'status.json()["completed_downloads"]', content)
|
||||||
|
|
||||||
|
# Fix assert "status" in data
|
||||||
|
content = re.sub(r'assert "status" in data', 'assert "is_running" in data', content)
|
||||||
|
|
||||||
|
return content
|
||||||
|
|
||||||
|
|
||||||
|
def fix_anime_service_init(content: str) -> str:
|
||||||
|
"""Fix AnimeService initialization in test fixtures."""
|
||||||
|
# This one is complex, so we'll just note files that need manual review
|
||||||
|
if 'AnimeService(' in content and 'directory=' in content:
|
||||||
|
print(" ⚠️ Contains AnimeService with directory= parameter - needs manual review")
|
||||||
|
return content
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
test_dir = Path(__file__).parent / "tests"
|
||||||
|
|
||||||
|
if not test_dir.exists():
|
||||||
|
print(f"Error: {test_dir} not found")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
files_to_fix = [
|
||||||
|
# Download service tests
|
||||||
|
"unit/test_download_service.py",
|
||||||
|
"unit/test_download_progress_websocket.py",
|
||||||
|
"integration/test_download_progress_integration.py",
|
||||||
|
"integration/test_websocket_integration.py",
|
||||||
|
# API tests with queue status
|
||||||
|
"api/test_queue_features.py",
|
||||||
|
"api/test_download_endpoints.py",
|
||||||
|
"frontend/test_existing_ui_integration.py",
|
||||||
|
]
|
||||||
|
|
||||||
|
for file_path in files_to_fix:
|
||||||
|
full_path = test_dir / file_path
|
||||||
|
if not full_path.exists():
|
||||||
|
print(f"Skipping {file_path} (not found)")
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(f"Processing {file_path}...")
|
||||||
|
|
||||||
|
# Read content
|
||||||
|
content = full_path.read_text()
|
||||||
|
original_content = content
|
||||||
|
|
||||||
|
# Apply fixes
|
||||||
|
if 'add_to_queue(' in content:
|
||||||
|
content = fix_add_to_queue_calls(content)
|
||||||
|
|
||||||
|
if 'data["status"]' in content or 'response.json()["status"]' in content:
|
||||||
|
content = fix_queue_status_response(content)
|
||||||
|
|
||||||
|
content = fix_anime_service_init(content)
|
||||||
|
|
||||||
|
# Write back if changed
|
||||||
|
if content != original_content:
|
||||||
|
full_path.write_text(content)
|
||||||
|
print(f" ✓ Updated {file_path}")
|
||||||
|
else:
|
||||||
|
print(f" - No changes needed for {file_path}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@ -74,7 +74,7 @@ class TestQueueDisplay:
|
|||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
||||||
# Verify structure
|
# Verify structure
|
||||||
assert "status" in data
|
assert "is_running" in data
|
||||||
assert "statistics" in data
|
assert "statistics" in data
|
||||||
|
|
||||||
status = data["status"]
|
status = data["status"]
|
||||||
@ -107,7 +107,7 @@ class TestQueueDisplay:
|
|||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
data = response.json()
|
data = response.json()
|
||||||
pending = data["status"]["pending"]
|
pending = data["pending_queue"]
|
||||||
|
|
||||||
assert len(pending) > 0
|
assert len(pending) > 0
|
||||||
item = pending[0]
|
item = pending[0]
|
||||||
@ -140,7 +140,7 @@ class TestQueueReordering:
|
|||||||
)
|
)
|
||||||
existing_items = [
|
existing_items = [
|
||||||
item["id"]
|
item["id"]
|
||||||
for item in status_response.json()["status"]["pending"]
|
for item in status_response.json()["pending_queue"]
|
||||||
]
|
]
|
||||||
if existing_items:
|
if existing_items:
|
||||||
await client.request(
|
await client.request(
|
||||||
@ -190,7 +190,7 @@ class TestQueueReordering:
|
|||||||
)
|
)
|
||||||
current_order = [
|
current_order = [
|
||||||
item["id"]
|
item["id"]
|
||||||
for item in status_response.json()["status"]["pending"]
|
for item in status_response.json()["pending_queue"]
|
||||||
]
|
]
|
||||||
|
|
||||||
assert current_order == new_order
|
assert current_order == new_order
|
||||||
@ -270,7 +270,7 @@ class TestQueueControl:
|
|||||||
"/api/queue/status",
|
"/api/queue/status",
|
||||||
headers=auth_headers
|
headers=auth_headers
|
||||||
)
|
)
|
||||||
assert status.json()["status"]["is_running"] is False
|
assert status.json()["is_running"] is False
|
||||||
|
|
||||||
# Start queue
|
# Start queue
|
||||||
await client.post("/api/queue/start", headers=auth_headers)
|
await client.post("/api/queue/start", headers=auth_headers)
|
||||||
@ -280,7 +280,7 @@ class TestQueueControl:
|
|||||||
"/api/queue/status",
|
"/api/queue/status",
|
||||||
headers=auth_headers
|
headers=auth_headers
|
||||||
)
|
)
|
||||||
assert status.json()["status"]["is_running"] is True
|
assert status.json()["is_running"] is True
|
||||||
|
|
||||||
# Stop queue
|
# Stop queue
|
||||||
await client.post("/api/queue/stop", headers=auth_headers)
|
await client.post("/api/queue/stop", headers=auth_headers)
|
||||||
@ -290,7 +290,7 @@ class TestQueueControl:
|
|||||||
"/api/queue/status",
|
"/api/queue/status",
|
||||||
headers=auth_headers
|
headers=auth_headers
|
||||||
)
|
)
|
||||||
assert status.json()["status"]["is_running"] is False
|
assert status.json()["is_running"] is False
|
||||||
|
|
||||||
|
|
||||||
class TestCompletedDownloads:
|
class TestCompletedDownloads:
|
||||||
@ -323,7 +323,7 @@ class TestCompletedDownloads:
|
|||||||
data = status.json()
|
data = status.json()
|
||||||
|
|
||||||
completed_count = data["statistics"]["completed_count"]
|
completed_count = data["statistics"]["completed_count"]
|
||||||
completed_list = len(data["status"]["completed"])
|
completed_list = len(data["completed_downloads"])
|
||||||
|
|
||||||
# Count should match list length
|
# Count should match list length
|
||||||
assert completed_count == completed_list
|
assert completed_count == completed_list
|
||||||
@ -390,7 +390,7 @@ class TestFailedDownloads:
|
|||||||
data = status.json()
|
data = status.json()
|
||||||
|
|
||||||
failed_count = data["statistics"]["failed_count"]
|
failed_count = data["statistics"]["failed_count"]
|
||||||
failed_list = len(data["status"]["failed"])
|
failed_list = len(data["failed_downloads"])
|
||||||
|
|
||||||
# Count should match list length
|
# Count should match list length
|
||||||
assert failed_count == failed_list
|
assert failed_count == failed_list
|
||||||
|
|||||||
@ -244,7 +244,7 @@ class TestFrontendDownloadAPI:
|
|||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
data = response.json()
|
data = response.json()
|
||||||
# Check for expected response structure
|
# Check for expected response structure
|
||||||
assert "status" in data or "statistics" in data
|
assert "is_running" in data or "statistics" in data
|
||||||
|
|
||||||
async def test_start_download_queue(self, authenticated_client):
|
async def test_start_download_queue(self, authenticated_client):
|
||||||
"""Test POST /api/queue/start starts next download."""
|
"""Test POST /api/queue/start starts next download."""
|
||||||
|
|||||||
@ -63,15 +63,11 @@ def websocket_service():
|
|||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
async def anime_service(mock_series_app, progress_service):
|
async def anime_service(mock_series_app, progress_service):
|
||||||
"""Create an AnimeService."""
|
"""Create an AnimeService."""
|
||||||
with patch(
|
service = AnimeService(
|
||||||
"src.server.services.anime_service.SeriesApp",
|
series_app=mock_series_app,
|
||||||
return_value=mock_series_app
|
progress_service=progress_service,
|
||||||
):
|
)
|
||||||
service = AnimeService(
|
yield service
|
||||||
directory="/test/anime",
|
|
||||||
progress_service=progress_service,
|
|
||||||
)
|
|
||||||
yield service
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -130,6 +126,7 @@ class TestDownloadProgressIntegration:
|
|||||||
# Add download to queue
|
# Add download to queue
|
||||||
await download_service.add_to_queue(
|
await download_service.add_to_queue(
|
||||||
serie_id="integration_test",
|
serie_id="integration_test",
|
||||||
|
serie_folder="integration_test",
|
||||||
serie_folder="test_folder",
|
serie_folder="test_folder",
|
||||||
serie_name="Integration Test Anime",
|
serie_name="Integration Test Anime",
|
||||||
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
||||||
@ -203,6 +200,7 @@ class TestDownloadProgressIntegration:
|
|||||||
# Add and start download
|
# Add and start download
|
||||||
await download_service.add_to_queue(
|
await download_service.add_to_queue(
|
||||||
serie_id="client_test",
|
serie_id="client_test",
|
||||||
|
serie_folder="client_test",
|
||||||
serie_folder="test_folder",
|
serie_folder="test_folder",
|
||||||
serie_name="Client Test Anime",
|
serie_name="Client Test Anime",
|
||||||
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
||||||
@ -266,6 +264,7 @@ class TestDownloadProgressIntegration:
|
|||||||
# Start download
|
# Start download
|
||||||
await download_service.add_to_queue(
|
await download_service.add_to_queue(
|
||||||
serie_id="multi_client_test",
|
serie_id="multi_client_test",
|
||||||
|
serie_folder="multi_client_test",
|
||||||
serie_folder="test_folder",
|
serie_folder="test_folder",
|
||||||
serie_name="Multi Client Test",
|
serie_name="Multi Client Test",
|
||||||
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
||||||
@ -313,6 +312,7 @@ class TestDownloadProgressIntegration:
|
|||||||
|
|
||||||
await download_service.add_to_queue(
|
await download_service.add_to_queue(
|
||||||
serie_id="structure_test",
|
serie_id="structure_test",
|
||||||
|
serie_folder="structure_test",
|
||||||
serie_folder="test_folder",
|
serie_folder="test_folder",
|
||||||
serie_name="Structure Test",
|
serie_name="Structure Test",
|
||||||
episodes=[EpisodeIdentifier(season=2, episode=3)],
|
episodes=[EpisodeIdentifier(season=2, episode=3)],
|
||||||
@ -380,6 +380,7 @@ class TestDownloadProgressIntegration:
|
|||||||
# Start download after disconnect
|
# Start download after disconnect
|
||||||
await download_service.add_to_queue(
|
await download_service.add_to_queue(
|
||||||
serie_id="disconnect_test",
|
serie_id="disconnect_test",
|
||||||
|
serie_folder="disconnect_test",
|
||||||
serie_folder="test_folder",
|
serie_folder="test_folder",
|
||||||
serie_name="Disconnect Test",
|
serie_name="Disconnect Test",
|
||||||
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
||||||
|
|||||||
@ -47,12 +47,11 @@ def websocket_service():
|
|||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
async def anime_service(mock_series_app, progress_service):
|
async def anime_service(mock_series_app, progress_service):
|
||||||
"""Create an AnimeService with mocked dependencies."""
|
"""Create an AnimeService with mocked dependencies."""
|
||||||
with patch("src.server.services.anime_service.SeriesApp", return_value=mock_series_app):
|
service = AnimeService(
|
||||||
service = AnimeService(
|
series_app=mock_series_app,
|
||||||
directory="/test/anime",
|
progress_service=progress_service,
|
||||||
progress_service=progress_service,
|
)
|
||||||
)
|
yield service
|
||||||
yield service
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -86,6 +85,7 @@ class TestWebSocketDownloadIntegration:
|
|||||||
# Add item to queue
|
# Add item to queue
|
||||||
item_ids = await download_service.add_to_queue(
|
item_ids = await download_service.add_to_queue(
|
||||||
serie_id="test_serie",
|
serie_id="test_serie",
|
||||||
|
serie_folder="test_serie",
|
||||||
serie_name="Test Anime",
|
serie_name="Test Anime",
|
||||||
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
||||||
priority=DownloadPriority.HIGH,
|
priority=DownloadPriority.HIGH,
|
||||||
@ -112,6 +112,7 @@ class TestWebSocketDownloadIntegration:
|
|||||||
# Add items
|
# Add items
|
||||||
item_ids = await download_service.add_to_queue(
|
item_ids = await download_service.add_to_queue(
|
||||||
serie_id="test",
|
serie_id="test",
|
||||||
|
serie_folder="test",
|
||||||
serie_name="Test",
|
serie_name="Test",
|
||||||
episodes=[EpisodeIdentifier(season=1, episode=i) for i in range(1, 4)],
|
episodes=[EpisodeIdentifier(season=1, episode=i) for i in range(1, 4)],
|
||||||
priority=DownloadPriority.NORMAL,
|
priority=DownloadPriority.NORMAL,
|
||||||
@ -398,6 +399,7 @@ class TestWebSocketEndToEnd:
|
|||||||
# Add items to queue
|
# Add items to queue
|
||||||
item_ids = await download_service.add_to_queue(
|
item_ids = await download_service.add_to_queue(
|
||||||
serie_id="test",
|
serie_id="test",
|
||||||
|
serie_folder="test",
|
||||||
serie_name="Test Anime",
|
serie_name="Test Anime",
|
||||||
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
||||||
priority=DownloadPriority.HIGH,
|
priority=DownloadPriority.HIGH,
|
||||||
|
|||||||
@ -6,7 +6,7 @@ error handling, and progress reporting integration.
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from unittest.mock import AsyncMock, MagicMock, patch
|
from unittest.mock import AsyncMock, MagicMock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@ -15,16 +15,17 @@ from src.server.services.progress_service import ProgressService
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_series_app():
|
def mock_series_app(tmp_path):
|
||||||
"""Create a mock SeriesApp instance."""
|
"""Create a mock SeriesApp instance."""
|
||||||
with patch("src.server.services.anime_service.SeriesApp") as mock_class:
|
mock_instance = MagicMock()
|
||||||
mock_instance = MagicMock()
|
mock_instance.directory_to_search = str(tmp_path)
|
||||||
mock_instance.series_list = []
|
mock_instance.series_list = []
|
||||||
mock_instance.search = MagicMock(return_value=[])
|
mock_instance.search = AsyncMock(return_value=[])
|
||||||
mock_instance.ReScan = MagicMock()
|
mock_instance.rescan = AsyncMock()
|
||||||
mock_instance.download = MagicMock(return_value=True)
|
mock_instance.download = AsyncMock(return_value=True)
|
||||||
mock_class.return_value = mock_instance
|
mock_instance.download_status = None
|
||||||
yield mock_instance
|
mock_instance.scan_status = None
|
||||||
|
return mock_instance
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -42,8 +43,7 @@ def mock_progress_service():
|
|||||||
def anime_service(tmp_path, mock_series_app, mock_progress_service):
|
def anime_service(tmp_path, mock_series_app, mock_progress_service):
|
||||||
"""Create an AnimeService instance for testing."""
|
"""Create an AnimeService instance for testing."""
|
||||||
return AnimeService(
|
return AnimeService(
|
||||||
directory=str(tmp_path),
|
series_app=mock_series_app,
|
||||||
max_workers=2,
|
|
||||||
progress_service=mock_progress_service,
|
progress_service=mock_progress_service,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -51,35 +51,38 @@ def anime_service(tmp_path, mock_series_app, mock_progress_service):
|
|||||||
class TestAnimeServiceInitialization:
|
class TestAnimeServiceInitialization:
|
||||||
"""Test AnimeService initialization."""
|
"""Test AnimeService initialization."""
|
||||||
|
|
||||||
def test_initialization_success(self, tmp_path, mock_progress_service):
|
def test_initialization_success(
|
||||||
|
self, mock_series_app, mock_progress_service
|
||||||
|
):
|
||||||
"""Test successful service initialization."""
|
"""Test successful service initialization."""
|
||||||
with patch("src.server.services.anime_service.SeriesApp"):
|
service = AnimeService(
|
||||||
service = AnimeService(
|
series_app=mock_series_app,
|
||||||
directory=str(tmp_path),
|
progress_service=mock_progress_service,
|
||||||
max_workers=2,
|
)
|
||||||
progress_service=mock_progress_service,
|
|
||||||
)
|
|
||||||
|
|
||||||
assert service._directory == str(tmp_path)
|
assert service._app is mock_series_app
|
||||||
assert service._executor is not None
|
assert service._progress_service is mock_progress_service
|
||||||
assert service._progress_service is mock_progress_service
|
|
||||||
|
|
||||||
def test_initialization_failure_raises_error(
|
def test_initialization_failure_raises_error(
|
||||||
self, tmp_path, mock_progress_service
|
self, tmp_path, mock_progress_service
|
||||||
):
|
):
|
||||||
"""Test SeriesApp initialization failure raises error."""
|
"""Test SeriesApp initialization failure raises error."""
|
||||||
with patch(
|
bad_series_app = MagicMock()
|
||||||
"src.server.services.anime_service.SeriesApp"
|
bad_series_app.directory_to_search = str(tmp_path)
|
||||||
) as mock_class:
|
|
||||||
mock_class.side_effect = Exception("Initialization failed")
|
|
||||||
|
|
||||||
with pytest.raises(
|
# Make event subscription fail
|
||||||
AnimeServiceError, match="Initialization failed"
|
def raise_error(*args):
|
||||||
):
|
raise Exception("Initialization failed")
|
||||||
AnimeService(
|
|
||||||
directory=str(tmp_path),
|
bad_series_app.__setattr__ = raise_error
|
||||||
progress_service=mock_progress_service,
|
|
||||||
)
|
with pytest.raises(
|
||||||
|
AnimeServiceError, match="Initialization failed"
|
||||||
|
):
|
||||||
|
AnimeService(
|
||||||
|
series_app=bad_series_app,
|
||||||
|
progress_service=mock_progress_service,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestListMissing:
|
class TestListMissing:
|
||||||
@ -321,12 +324,12 @@ class TestConcurrency:
|
|||||||
class TestFactoryFunction:
|
class TestFactoryFunction:
|
||||||
"""Test factory function."""
|
"""Test factory function."""
|
||||||
|
|
||||||
def test_get_anime_service(self, tmp_path):
|
def test_get_anime_service(self):
|
||||||
"""Test get_anime_service factory function."""
|
"""Test get_anime_service factory function."""
|
||||||
from src.server.services.anime_service import get_anime_service
|
from src.server.services.anime_service import get_anime_service
|
||||||
|
|
||||||
with patch("src.server.services.anime_service.SeriesApp"):
|
# The factory function doesn't take directory anymore
|
||||||
service = get_anime_service(directory=str(tmp_path))
|
service = get_anime_service()
|
||||||
|
|
||||||
assert isinstance(service, AnimeService)
|
assert isinstance(service, AnimeService)
|
||||||
assert service._directory == str(tmp_path)
|
assert service._app is not None
|
||||||
|
|||||||
@ -48,15 +48,15 @@ class TestDownloadPriority:
|
|||||||
|
|
||||||
def test_all_priorities_exist(self):
|
def test_all_priorities_exist(self):
|
||||||
"""Test that all expected priorities are defined."""
|
"""Test that all expected priorities are defined."""
|
||||||
assert DownloadPriority.LOW == "low"
|
assert DownloadPriority.LOW == "LOW"
|
||||||
assert DownloadPriority.NORMAL == "normal"
|
assert DownloadPriority.NORMAL == "NORMAL"
|
||||||
assert DownloadPriority.HIGH == "high"
|
assert DownloadPriority.HIGH == "HIGH"
|
||||||
|
|
||||||
def test_priority_values(self):
|
def test_priority_values(self):
|
||||||
"""Test that priority values are lowercase strings."""
|
"""Test that priority values are uppercase strings."""
|
||||||
for priority in DownloadPriority:
|
for priority in DownloadPriority:
|
||||||
assert isinstance(priority.value, str)
|
assert isinstance(priority.value, str)
|
||||||
assert priority.value.islower()
|
assert priority.value.isupper()
|
||||||
|
|
||||||
|
|
||||||
class TestEpisodeIdentifier:
|
class TestEpisodeIdentifier:
|
||||||
|
|||||||
@ -76,15 +76,11 @@ def progress_service():
|
|||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
async def anime_service(mock_series_app, progress_service):
|
async def anime_service(mock_series_app, progress_service):
|
||||||
"""Create an AnimeService with mocked dependencies."""
|
"""Create an AnimeService with mocked dependencies."""
|
||||||
with patch(
|
service = AnimeService(
|
||||||
"src.server.services.anime_service.SeriesApp",
|
series_app=mock_series_app,
|
||||||
return_value=mock_series_app
|
progress_service=progress_service,
|
||||||
):
|
)
|
||||||
service = AnimeService(
|
yield service
|
||||||
directory="/test/anime",
|
|
||||||
progress_service=progress_service,
|
|
||||||
)
|
|
||||||
yield service
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -118,7 +114,7 @@ class TestDownloadProgressWebSocket:
|
|||||||
# Add item to queue
|
# Add item to queue
|
||||||
item_ids = await download_service.add_to_queue(
|
item_ids = await download_service.add_to_queue(
|
||||||
serie_id="test_serie_1",
|
serie_id="test_serie_1",
|
||||||
serie_folder="test_folder",
|
serie_folder="test_serie_1",
|
||||||
serie_name="Test Anime",
|
serie_name="Test Anime",
|
||||||
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
||||||
priority=DownloadPriority.NORMAL,
|
priority=DownloadPriority.NORMAL,
|
||||||
@ -168,7 +164,7 @@ class TestDownloadProgressWebSocket:
|
|||||||
# Add item with specific episode info
|
# Add item with specific episode info
|
||||||
await download_service.add_to_queue(
|
await download_service.add_to_queue(
|
||||||
serie_id="test_serie_2",
|
serie_id="test_serie_2",
|
||||||
serie_folder="test_folder",
|
serie_folder="test_serie_2",
|
||||||
serie_name="My Test Anime",
|
serie_name="My Test Anime",
|
||||||
episodes=[EpisodeIdentifier(season=2, episode=5)],
|
episodes=[EpisodeIdentifier(season=2, episode=5)],
|
||||||
priority=DownloadPriority.HIGH,
|
priority=DownloadPriority.HIGH,
|
||||||
@ -203,7 +199,7 @@ class TestDownloadProgressWebSocket:
|
|||||||
|
|
||||||
await download_service.add_to_queue(
|
await download_service.add_to_queue(
|
||||||
serie_id="test_serie_3",
|
serie_id="test_serie_3",
|
||||||
serie_folder="test_folder",
|
serie_folder="test_serie_3",
|
||||||
serie_name="Progress Test",
|
serie_name="Progress Test",
|
||||||
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
||||||
)
|
)
|
||||||
@ -240,7 +236,7 @@ class TestDownloadProgressWebSocket:
|
|||||||
|
|
||||||
await download_service.add_to_queue(
|
await download_service.add_to_queue(
|
||||||
serie_id="test_serie_4",
|
serie_id="test_serie_4",
|
||||||
serie_folder="test_folder",
|
serie_folder="test_serie_4",
|
||||||
serie_name="Speed Test",
|
serie_name="Speed Test",
|
||||||
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
||||||
)
|
)
|
||||||
@ -272,7 +268,7 @@ class TestDownloadProgressWebSocket:
|
|||||||
|
|
||||||
await download_service.add_to_queue(
|
await download_service.add_to_queue(
|
||||||
serie_id="test_serie_5",
|
serie_id="test_serie_5",
|
||||||
serie_folder="test_folder",
|
serie_folder="test_serie_5",
|
||||||
serie_name="No Broadcast Test",
|
serie_name="No Broadcast Test",
|
||||||
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
||||||
)
|
)
|
||||||
@ -300,7 +296,7 @@ class TestDownloadProgressWebSocket:
|
|||||||
|
|
||||||
await download_service.add_to_queue(
|
await download_service.add_to_queue(
|
||||||
serie_id="test_serie_6",
|
serie_id="test_serie_6",
|
||||||
serie_folder="test_folder",
|
serie_folder="test_serie_6",
|
||||||
serie_name="Error Handling Test",
|
serie_name="Error Handling Test",
|
||||||
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
||||||
)
|
)
|
||||||
@ -331,7 +327,7 @@ class TestDownloadProgressWebSocket:
|
|||||||
# Add multiple episodes
|
# Add multiple episodes
|
||||||
item_ids = await download_service.add_to_queue(
|
item_ids = await download_service.add_to_queue(
|
||||||
serie_id="test_serie_7",
|
serie_id="test_serie_7",
|
||||||
serie_folder="test_folder",
|
serie_folder="test_serie_7",
|
||||||
serie_name="Multi Episode Test",
|
serie_name="Multi Episode Test",
|
||||||
episodes=[
|
episodes=[
|
||||||
EpisodeIdentifier(season=1, episode=1),
|
EpisodeIdentifier(season=1, episode=1),
|
||||||
@ -378,7 +374,7 @@ class TestDownloadProgressWebSocket:
|
|||||||
|
|
||||||
await download_service.add_to_queue(
|
await download_service.add_to_queue(
|
||||||
serie_id="test_serie_8",
|
serie_id="test_serie_8",
|
||||||
serie_folder="test_folder",
|
serie_folder="test_serie_8",
|
||||||
serie_name="Model Test",
|
serie_name="Model Test",
|
||||||
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
||||||
)
|
)
|
||||||
|
|||||||
@ -118,6 +118,7 @@ class TestQueueManagement:
|
|||||||
|
|
||||||
item_ids = await download_service.add_to_queue(
|
item_ids = await download_service.add_to_queue(
|
||||||
serie_id="series-1",
|
serie_id="series-1",
|
||||||
|
serie_folder="series",
|
||||||
serie_name="Test Series",
|
serie_name="Test Series",
|
||||||
episodes=episodes,
|
episodes=episodes,
|
||||||
priority=DownloadPriority.NORMAL,
|
priority=DownloadPriority.NORMAL,
|
||||||
@ -142,6 +143,7 @@ class TestQueueManagement:
|
|||||||
|
|
||||||
item_ids = await download_service.add_to_queue(
|
item_ids = await download_service.add_to_queue(
|
||||||
serie_id="series-1",
|
serie_id="series-1",
|
||||||
|
serie_folder="series",
|
||||||
serie_name="Test Series",
|
serie_name="Test Series",
|
||||||
episodes=episodes,
|
episodes=episodes,
|
||||||
priority=DownloadPriority.NORMAL,
|
priority=DownloadPriority.NORMAL,
|
||||||
@ -155,6 +157,7 @@ class TestQueueManagement:
|
|||||||
"""Test removing items from pending queue."""
|
"""Test removing items from pending queue."""
|
||||||
item_ids = await download_service.add_to_queue(
|
item_ids = await download_service.add_to_queue(
|
||||||
serie_id="series-1",
|
serie_id="series-1",
|
||||||
|
serie_folder="series",
|
||||||
serie_name="Test Series",
|
serie_name="Test Series",
|
||||||
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
||||||
)
|
)
|
||||||
@ -171,6 +174,7 @@ class TestQueueManagement:
|
|||||||
# Add items to queue
|
# Add items to queue
|
||||||
item_ids = await download_service.add_to_queue(
|
item_ids = await download_service.add_to_queue(
|
||||||
serie_id="series-1",
|
serie_id="series-1",
|
||||||
|
serie_folder="series",
|
||||||
serie_name="Test Series",
|
serie_name="Test Series",
|
||||||
episodes=[
|
episodes=[
|
||||||
EpisodeIdentifier(season=1, episode=1),
|
EpisodeIdentifier(season=1, episode=1),
|
||||||
@ -200,6 +204,7 @@ class TestQueueManagement:
|
|||||||
# Add items and start one
|
# Add items and start one
|
||||||
await download_service.add_to_queue(
|
await download_service.add_to_queue(
|
||||||
serie_id="series-1",
|
serie_id="series-1",
|
||||||
|
serie_folder="series",
|
||||||
serie_name="Test Series",
|
serie_name="Test Series",
|
||||||
episodes=[
|
episodes=[
|
||||||
EpisodeIdentifier(season=1, episode=1),
|
EpisodeIdentifier(season=1, episode=1),
|
||||||
@ -236,6 +241,7 @@ class TestQueueManagement:
|
|||||||
# Add item
|
# Add item
|
||||||
await download_service.add_to_queue(
|
await download_service.add_to_queue(
|
||||||
serie_id="series-1",
|
serie_id="series-1",
|
||||||
|
serie_folder="series",
|
||||||
serie_name="Test Series",
|
serie_name="Test Series",
|
||||||
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
||||||
)
|
)
|
||||||
@ -258,6 +264,7 @@ class TestQueueManagement:
|
|||||||
# Add item
|
# Add item
|
||||||
await download_service.add_to_queue(
|
await download_service.add_to_queue(
|
||||||
serie_id="series-1",
|
serie_id="series-1",
|
||||||
|
serie_folder="series",
|
||||||
serie_name="Test Series",
|
serie_name="Test Series",
|
||||||
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
||||||
)
|
)
|
||||||
@ -279,6 +286,7 @@ class TestQueueStatus:
|
|||||||
# Add items to queue
|
# Add items to queue
|
||||||
await download_service.add_to_queue(
|
await download_service.add_to_queue(
|
||||||
serie_id="series-1",
|
serie_id="series-1",
|
||||||
|
serie_folder="series",
|
||||||
serie_name="Test Series",
|
serie_name="Test Series",
|
||||||
episodes=[
|
episodes=[
|
||||||
EpisodeIdentifier(season=1, episode=1),
|
EpisodeIdentifier(season=1, episode=1),
|
||||||
@ -302,6 +310,7 @@ class TestQueueStatus:
|
|||||||
# Add items
|
# Add items
|
||||||
await download_service.add_to_queue(
|
await download_service.add_to_queue(
|
||||||
serie_id="series-1",
|
serie_id="series-1",
|
||||||
|
serie_folder="series",
|
||||||
serie_name="Test Series",
|
serie_name="Test Series",
|
||||||
episodes=[
|
episodes=[
|
||||||
EpisodeIdentifier(season=1, episode=1),
|
EpisodeIdentifier(season=1, episode=1),
|
||||||
@ -380,6 +389,7 @@ class TestPersistence:
|
|||||||
"""Test that queue state is persisted to disk."""
|
"""Test that queue state is persisted to disk."""
|
||||||
await download_service.add_to_queue(
|
await download_service.add_to_queue(
|
||||||
serie_id="series-1",
|
serie_id="series-1",
|
||||||
|
serie_folder="series",
|
||||||
serie_name="Test Series",
|
serie_name="Test Series",
|
||||||
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
||||||
)
|
)
|
||||||
@ -408,6 +418,7 @@ class TestPersistence:
|
|||||||
|
|
||||||
await service1.add_to_queue(
|
await service1.add_to_queue(
|
||||||
serie_id="series-1",
|
serie_id="series-1",
|
||||||
|
serie_folder="series",
|
||||||
serie_name="Test Series",
|
serie_name="Test Series",
|
||||||
episodes=[
|
episodes=[
|
||||||
EpisodeIdentifier(season=1, episode=1),
|
EpisodeIdentifier(season=1, episode=1),
|
||||||
@ -491,6 +502,7 @@ class TestBroadcastCallbacks:
|
|||||||
|
|
||||||
await download_service.add_to_queue(
|
await download_service.add_to_queue(
|
||||||
serie_id="series-1",
|
serie_id="series-1",
|
||||||
|
serie_folder="series",
|
||||||
serie_name="Test Series",
|
serie_name="Test Series",
|
||||||
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
||||||
)
|
)
|
||||||
@ -530,6 +542,7 @@ class TestBroadcastCallbacks:
|
|||||||
# Add an item to the queue
|
# Add an item to the queue
|
||||||
await download_service.add_to_queue(
|
await download_service.add_to_queue(
|
||||||
serie_id="series-1",
|
serie_id="series-1",
|
||||||
|
serie_folder="series",
|
||||||
serie_name="Test Series",
|
serie_name="Test Series",
|
||||||
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
||||||
)
|
)
|
||||||
@ -617,6 +630,7 @@ class TestErrorHandling:
|
|||||||
|
|
||||||
await download_service.add_to_queue(
|
await download_service.add_to_queue(
|
||||||
serie_id="series-1",
|
serie_id="series-1",
|
||||||
|
serie_folder="series",
|
||||||
serie_name="Test Series",
|
serie_name="Test Series",
|
||||||
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
episodes=[EpisodeIdentifier(season=1, episode=1)],
|
||||||
)
|
)
|
||||||
|
|||||||
@ -7,11 +7,10 @@ Tests the functionality of SeriesApp including:
|
|||||||
- Download with progress callbacks
|
- Download with progress callbacks
|
||||||
- Directory scanning with progress reporting
|
- Directory scanning with progress reporting
|
||||||
- Async versions of operations
|
- Async versions of operations
|
||||||
- Cancellation support
|
|
||||||
- Error handling
|
- Error handling
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from unittest.mock import Mock, patch
|
from unittest.mock import AsyncMock, Mock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@ -35,62 +34,30 @@ class TestSeriesAppInitialization:
|
|||||||
|
|
||||||
# Verify initialization
|
# Verify initialization
|
||||||
assert app.directory_to_search == test_dir
|
assert app.directory_to_search == test_dir
|
||||||
assert app._operation_status == OperationStatus.IDLE
|
|
||||||
assert app._cancel_flag is False
|
|
||||||
assert app._current_operation is None
|
|
||||||
mock_loaders.assert_called_once()
|
mock_loaders.assert_called_once()
|
||||||
mock_scanner.assert_called_once()
|
mock_scanner.assert_called_once()
|
||||||
|
|
||||||
@patch('src.core.SeriesApp.Loaders')
|
@patch('src.core.SeriesApp.Loaders')
|
||||||
@patch('src.core.SeriesApp.SerieScanner')
|
def test_init_failure_raises_error(self, mock_loaders):
|
||||||
@patch('src.core.SeriesApp.SerieList')
|
"""Test that initialization failure raises error."""
|
||||||
def test_init_with_callbacks(
|
|
||||||
self, mock_serie_list, mock_scanner, mock_loaders
|
|
||||||
):
|
|
||||||
"""Test initialization with progress and error callbacks."""
|
|
||||||
test_dir = "/test/anime"
|
test_dir = "/test/anime"
|
||||||
progress_callback = Mock()
|
|
||||||
error_callback = Mock()
|
|
||||||
|
|
||||||
# Create app with callbacks
|
|
||||||
app = SeriesApp(
|
|
||||||
test_dir,
|
|
||||||
progress_callback=progress_callback,
|
|
||||||
error_callback=error_callback
|
|
||||||
)
|
|
||||||
|
|
||||||
# Verify callbacks are stored
|
|
||||||
assert app.progress_callback == progress_callback
|
|
||||||
assert app.error_callback == error_callback
|
|
||||||
|
|
||||||
@patch('src.core.SeriesApp.Loaders')
|
|
||||||
def test_init_failure_calls_error_callback(self, mock_loaders):
|
|
||||||
"""Test that initialization failure triggers error callback."""
|
|
||||||
test_dir = "/test/anime"
|
|
||||||
error_callback = Mock()
|
|
||||||
|
|
||||||
# Make Loaders raise an exception
|
# Make Loaders raise an exception
|
||||||
mock_loaders.side_effect = RuntimeError("Init failed")
|
mock_loaders.side_effect = RuntimeError("Init failed")
|
||||||
|
|
||||||
# Create app should raise but call error callback
|
# Create app should raise
|
||||||
with pytest.raises(RuntimeError):
|
with pytest.raises(RuntimeError):
|
||||||
SeriesApp(test_dir, error_callback=error_callback)
|
SeriesApp(test_dir)
|
||||||
|
|
||||||
# Verify error callback was called
|
|
||||||
error_callback.assert_called_once()
|
|
||||||
assert isinstance(
|
|
||||||
error_callback.call_args[0][0],
|
|
||||||
RuntimeError
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class TestSeriesAppSearch:
|
class TestSeriesAppSearch:
|
||||||
"""Test search functionality."""
|
"""Test search functionality."""
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
@patch('src.core.SeriesApp.Loaders')
|
@patch('src.core.SeriesApp.Loaders')
|
||||||
@patch('src.core.SeriesApp.SerieScanner')
|
@patch('src.core.SeriesApp.SerieScanner')
|
||||||
@patch('src.core.SeriesApp.SerieList')
|
@patch('src.core.SeriesApp.SerieList')
|
||||||
def test_search_success(
|
async def test_search_success(
|
||||||
self, mock_serie_list, mock_scanner, mock_loaders
|
self, mock_serie_list, mock_scanner, mock_loaders
|
||||||
):
|
):
|
||||||
"""Test successful search."""
|
"""Test successful search."""
|
||||||
@ -104,34 +71,32 @@ class TestSeriesAppSearch:
|
|||||||
]
|
]
|
||||||
app.loader.search = Mock(return_value=expected_results)
|
app.loader.search = Mock(return_value=expected_results)
|
||||||
|
|
||||||
# Perform search
|
# Perform search (now async)
|
||||||
results = app.search("test anime")
|
results = await app.search("test anime")
|
||||||
|
|
||||||
# Verify results
|
# Verify results
|
||||||
assert results == expected_results
|
assert results == expected_results
|
||||||
app.loader.search.assert_called_once_with("test anime")
|
app.loader.search.assert_called_once_with("test anime")
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
@patch('src.core.SeriesApp.Loaders')
|
@patch('src.core.SeriesApp.Loaders')
|
||||||
@patch('src.core.SeriesApp.SerieScanner')
|
@patch('src.core.SeriesApp.SerieScanner')
|
||||||
@patch('src.core.SeriesApp.SerieList')
|
@patch('src.core.SeriesApp.SerieList')
|
||||||
def test_search_failure_calls_error_callback(
|
async def test_search_failure_raises_error(
|
||||||
self, mock_serie_list, mock_scanner, mock_loaders
|
self, mock_serie_list, mock_scanner, mock_loaders
|
||||||
):
|
):
|
||||||
"""Test search failure triggers error callback."""
|
"""Test search failure raises error."""
|
||||||
test_dir = "/test/anime"
|
test_dir = "/test/anime"
|
||||||
error_callback = Mock()
|
app = SeriesApp(test_dir)
|
||||||
app = SeriesApp(test_dir, error_callback=error_callback)
|
|
||||||
|
|
||||||
# Make search raise an exception
|
# Make search raise an exception
|
||||||
app.loader.search = Mock(
|
app.loader.search = Mock(
|
||||||
side_effect=RuntimeError("Search failed")
|
side_effect=RuntimeError("Search failed")
|
||||||
)
|
)
|
||||||
|
|
||||||
# Search should raise and call error callback
|
# Search should raise
|
||||||
with pytest.raises(RuntimeError):
|
with pytest.raises(RuntimeError):
|
||||||
app.search("test")
|
await app.search("test")
|
||||||
|
|
||||||
error_callback.assert_called_once()
|
|
||||||
|
|
||||||
|
|
||||||
class TestSeriesAppDownload:
|
class TestSeriesAppDownload:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user