refactor: simplify NFO handling, remove legacy services
- Drop nfo_factory, nfo_repair_service, nfo_service, series_manager_service - Delete key_resolution_service, consolidate into folder_rename_service - Remove bulk of NFO-related tests (coverage via integration tests) - Streamline SeriesApp, background_loader, initialization services - Add folder_rename_service to scheduler Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -458,40 +458,21 @@ class TestNFOScanFunctions:
|
||||
|
||||
|
||||
class TestExecuteNFOScan:
|
||||
"""Test NFO scan execution."""
|
||||
"""Test NFO scan execution - NFO service removed."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_execute_nfo_scan_without_progress(self):
|
||||
"""Test executing NFO scan without progress service."""
|
||||
mock_manager = MagicMock()
|
||||
mock_manager.scan_and_process_nfo = AsyncMock()
|
||||
mock_manager.close = AsyncMock()
|
||||
|
||||
with patch('src.core.services.series_manager_service.SeriesManagerService') as mock_sms:
|
||||
mock_sms.from_settings.return_value = mock_manager
|
||||
|
||||
await _execute_nfo_scan()
|
||||
|
||||
mock_manager.scan_and_process_nfo.assert_called_once()
|
||||
mock_manager.close.assert_called_once()
|
||||
"""Test executing NFO scan without progress service - now no-op."""
|
||||
# NFO service removed, so _execute_nfo_scan should be a no-op
|
||||
await _execute_nfo_scan()
|
||||
# If we got here without exception, the no-op worked
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_execute_nfo_scan_with_progress(self):
|
||||
"""Test executing NFO scan with progress updates."""
|
||||
mock_manager = MagicMock()
|
||||
mock_manager.scan_and_process_nfo = AsyncMock()
|
||||
mock_manager.close = AsyncMock()
|
||||
"""Test executing NFO scan with progress updates - now no-op."""
|
||||
mock_progress = AsyncMock()
|
||||
|
||||
with patch('src.core.services.series_manager_service.SeriesManagerService') as mock_sms:
|
||||
mock_sms.from_settings.return_value = mock_manager
|
||||
|
||||
await _execute_nfo_scan(progress_service=mock_progress)
|
||||
|
||||
mock_manager.scan_and_process_nfo.assert_called_once()
|
||||
mock_manager.close.assert_called_once()
|
||||
assert mock_progress.update_progress.call_count == 2
|
||||
mock_progress.complete_progress.assert_called_once()
|
||||
await _execute_nfo_scan(progress_service=mock_progress)
|
||||
# If we got here without exception, the no-op worked
|
||||
|
||||
|
||||
class TestPerformNFOScan:
|
||||
@@ -761,7 +742,10 @@ class TestInitializationIntegration:
|
||||
|
||||
|
||||
class TestPerformNfoRepairScan:
|
||||
"""Tests for the perform_nfo_repair_scan startup hook."""
|
||||
"""Tests for the perform_nfo_repair_scan startup hook.
|
||||
|
||||
Note: NFO service removed, so these tests verify no-op behavior.
|
||||
"""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_skips_without_tmdb_api_key(self, tmp_path):
|
||||
@@ -790,100 +774,20 @@ class TestPerformNfoRepairScan:
|
||||
await perform_nfo_repair_scan()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_queues_deficient_series_as_asyncio_task(self, tmp_path):
|
||||
"""Series with incomplete NFO should be scheduled via asyncio.create_task."""
|
||||
async def test_is_no_op(self, tmp_path):
|
||||
"""perform_nfo_repair_scan is now a no-op - just verify it returns without error."""
|
||||
mock_settings = MagicMock()
|
||||
mock_settings.tmdb_api_key = "test-key"
|
||||
mock_settings.anime_directory = str(tmp_path)
|
||||
|
||||
series_dir = tmp_path / "MyAnime"
|
||||
series_dir.mkdir()
|
||||
nfo_file = series_dir / "tvshow.nfo"
|
||||
nfo_file.write_text("<tvshow><title>MyAnime</title></tvshow>")
|
||||
|
||||
mock_settings = MagicMock()
|
||||
mock_settings.tmdb_api_key = "test-key"
|
||||
mock_settings.anime_directory = str(tmp_path)
|
||||
|
||||
mock_repair_service = AsyncMock()
|
||||
mock_repair_service.repair_series = AsyncMock(return_value=True)
|
||||
|
||||
with patch(
|
||||
"src.server.services.scheduler.folder_scan_service._settings", mock_settings
|
||||
), patch(
|
||||
"src.core.services.nfo_repair_service.nfo_needs_repair",
|
||||
return_value=True,
|
||||
), patch(
|
||||
"src.core.services.nfo_factory.NFOServiceFactory"
|
||||
) as mock_factory_cls, patch(
|
||||
"src.core.services.nfo_repair_service.NfoRepairService",
|
||||
return_value=mock_repair_service,
|
||||
), patch(
|
||||
"asyncio.create_task"
|
||||
) as mock_create_task, patch(
|
||||
"asyncio.gather", new_callable=AsyncMock
|
||||
) as mock_gather:
|
||||
mock_factory_cls.return_value.create.return_value = MagicMock()
|
||||
):
|
||||
await perform_nfo_repair_scan(background_loader=AsyncMock())
|
||||
|
||||
mock_create_task.assert_called_once()
|
||||
mock_gather.assert_called_once()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_skips_complete_series(self, tmp_path):
|
||||
"""Series with complete NFO should not be scheduled for repair."""
|
||||
series_dir = tmp_path / "CompleteAnime"
|
||||
series_dir.mkdir()
|
||||
nfo_file = series_dir / "tvshow.nfo"
|
||||
nfo_file.write_text("<tvshow><title>CompleteAnime</title></tvshow>")
|
||||
|
||||
mock_settings = MagicMock()
|
||||
mock_settings.tmdb_api_key = "test-key"
|
||||
mock_settings.anime_directory = str(tmp_path)
|
||||
|
||||
with patch(
|
||||
"src.server.services.scheduler.folder_scan_service._settings", mock_settings
|
||||
), patch(
|
||||
"src.core.services.nfo_repair_service.nfo_needs_repair",
|
||||
return_value=False,
|
||||
), patch(
|
||||
"src.core.services.nfo_factory.NFOServiceFactory"
|
||||
) as mock_factory_cls, patch(
|
||||
"asyncio.create_task"
|
||||
) as mock_create_task:
|
||||
mock_factory_cls.return_value.create.return_value = MagicMock()
|
||||
await perform_nfo_repair_scan(background_loader=AsyncMock())
|
||||
|
||||
mock_create_task.assert_not_called()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_repairs_via_asyncio_task_without_background_loader(self, tmp_path):
|
||||
"""When no background_loader provided, repair is still scheduled via asyncio.create_task."""
|
||||
series_dir = tmp_path / "NeedsRepair"
|
||||
series_dir.mkdir()
|
||||
nfo_file = series_dir / "tvshow.nfo"
|
||||
nfo_file.write_text("<tvshow><title>NeedsRepair</title></tvshow>")
|
||||
|
||||
mock_settings = MagicMock()
|
||||
mock_settings.tmdb_api_key = "test-key"
|
||||
mock_settings.anime_directory = str(tmp_path)
|
||||
|
||||
mock_repair_service = AsyncMock()
|
||||
mock_repair_service.repair_series = AsyncMock(return_value=True)
|
||||
|
||||
with patch(
|
||||
"src.server.services.scheduler.folder_scan_service._settings", mock_settings
|
||||
), patch(
|
||||
"src.core.services.nfo_repair_service.nfo_needs_repair",
|
||||
return_value=True,
|
||||
), patch(
|
||||
"src.core.services.nfo_factory.NFOServiceFactory"
|
||||
) as mock_factory_cls, patch(
|
||||
"src.core.services.nfo_repair_service.NfoRepairService",
|
||||
return_value=mock_repair_service,
|
||||
), patch(
|
||||
"asyncio.create_task"
|
||||
) as mock_create_task, patch(
|
||||
"asyncio.gather", new_callable=AsyncMock
|
||||
) as mock_gather:
|
||||
mock_factory_cls.return_value.create.return_value = MagicMock()
|
||||
await perform_nfo_repair_scan(background_loader=None)
|
||||
|
||||
mock_create_task.assert_called_once()
|
||||
mock_gather.assert_called_once()
|
||||
# If we got here, the no-op worked correctly
|
||||
|
||||
Reference in New Issue
Block a user