test: fix NFO workflow and background loader tests

- Add missing TMDB async mock methods (_ensure_session, close)
  to all TMDB mocks in test_nfo_workflow.py
- Refactor test_anime_add_nfo_isolation.py to mock get_nfo_factory()
  instead of asserting on series_app.nfo_service directly
- Patch get_nfo_factory in test_background_loader_service.py
  to align with factory-based NFOService creation

Fixes test failures caused by NFOService refactoring that introduced
explicit TMDB session lifecycle and NFO factory pattern.
This commit is contained in:
2026-05-13 12:41:22 +02:00
parent 9c0f7ce08d
commit ceac22fc34
3 changed files with 143 additions and 96 deletions

View File

@@ -91,6 +91,13 @@ def _setup_loader_mocks(loader_service):
loader_service._broadcast_status = AsyncMock()
def _mock_nfo_factory(mock_nfo_service):
"""Create a mock NFO factory that returns the given mock service."""
mock_factory = MagicMock()
mock_factory.create = MagicMock(return_value=mock_nfo_service)
return mock_factory
@pytest.mark.asyncio
async def test_add_anime_loads_nfo_only_for_new_anime(
temp_anime_dir,
@@ -112,6 +119,12 @@ async def test_add_anime_loads_nfo_only_for_new_anime(
)
_setup_loader_mocks(loader_service)
# Set up mock NFO service via factory
mock_nfo_service = AsyncMock()
mock_nfo_service.create_tvshow_nfo = AsyncMock(return_value="/anime/New Anime (2024)/tvshow.nfo")
mock_factory = _mock_nfo_factory(mock_nfo_service)
with patch("src.server.services.background_loader_service.get_nfo_factory", return_value=mock_factory):
await loader_service.start()
try:
@@ -132,9 +145,9 @@ async def test_add_anime_loads_nfo_only_for_new_anime(
await asyncio.sleep(1.0)
assert mock_series_app.nfo_service.create_tvshow_nfo.call_count == 1
assert mock_nfo_service.create_tvshow_nfo.call_count == 1
call_args = mock_series_app.nfo_service.create_tvshow_nfo.call_args
call_args = mock_nfo_service.create_tvshow_nfo.call_args
assert call_args is not None
kwargs = call_args.kwargs
@@ -145,7 +158,7 @@ async def test_add_anime_loads_nfo_only_for_new_anime(
assert kwargs["download_logo"] is True
assert kwargs["download_fanart"] is True
all_calls = mock_series_app.nfo_service.create_tvshow_nfo.call_args_list
all_calls = mock_nfo_service.create_tvshow_nfo.call_args_list
for call_obj in all_calls:
call_kwargs = call_obj.kwargs
assert call_kwargs["serie_name"] != "Existing Anime 1"
@@ -216,6 +229,12 @@ async def test_multiple_anime_added_each_loads_independently(
)
_setup_loader_mocks(loader_service)
# Set up mock NFO service via factory
mock_nfo_service = AsyncMock()
mock_nfo_service.create_tvshow_nfo = AsyncMock(return_value="/anime/tvshow.nfo")
mock_factory = _mock_nfo_factory(mock_nfo_service)
with patch("src.server.services.background_loader_service.get_nfo_factory", return_value=mock_factory):
await loader_service.start()
try:
@@ -238,9 +257,9 @@ async def test_multiple_anime_added_each_loads_independently(
await asyncio.sleep(2.0)
assert mock_series_app.nfo_service.create_tvshow_nfo.call_count == 3
assert mock_nfo_service.create_tvshow_nfo.call_count == 3
all_calls = mock_series_app.nfo_service.create_tvshow_nfo.call_args_list
all_calls = mock_nfo_service.create_tvshow_nfo.call_args_list
called_names = [call_obj.kwargs["serie_name"] for call_obj in all_calls]
called_folders = [call_obj.kwargs["serie_folder"] for call_obj in all_calls]
@@ -275,6 +294,12 @@ async def test_nfo_service_receives_correct_parameters(
)
_setup_loader_mocks(loader_service)
# Set up mock NFO service via factory
mock_nfo_service = AsyncMock()
mock_nfo_service.create_tvshow_nfo = AsyncMock(return_value="/anime/Test Anime Series (2024)/tvshow.nfo")
mock_factory = _mock_nfo_factory(mock_nfo_service)
with patch("src.server.services.background_loader_service.get_nfo_factory", return_value=mock_factory):
await loader_service.start()
try:
@@ -295,9 +320,9 @@ async def test_nfo_service_receives_correct_parameters(
await asyncio.sleep(1.0)
assert mock_series_app.nfo_service.create_tvshow_nfo.call_count == 1
assert mock_nfo_service.create_tvshow_nfo.call_count == 1
call_kwargs = mock_series_app.nfo_service.create_tvshow_nfo.call_args.kwargs
call_kwargs = mock_nfo_service.create_tvshow_nfo.call_args.kwargs
assert call_kwargs["serie_name"] == test_name
assert call_kwargs["serie_folder"] == test_folder

View File

@@ -96,6 +96,8 @@ class TestCompleteNFOWorkflow:
mock_tmdb = Mock()
mock_tmdb.__aenter__ = AsyncMock(return_value=mock_tmdb)
mock_tmdb.__aexit__ = AsyncMock(return_value=None)
mock_tmdb._ensure_session = AsyncMock()
mock_tmdb.close = AsyncMock()
mock_tmdb.search_tv_show = AsyncMock(return_value={"results": [mock_tmdb_show]})
mock_tmdb.get_tv_show = AsyncMock(return_value=mock_tmdb_show)
mock_tmdb.get_tv_show_details = AsyncMock(return_value=mock_tmdb_show)
@@ -158,6 +160,8 @@ class TestCompleteNFOWorkflow:
mock_tmdb = Mock()
mock_tmdb.__aenter__ = AsyncMock(return_value=mock_tmdb)
mock_tmdb.__aexit__ = AsyncMock(return_value=None)
mock_tmdb._ensure_session = AsyncMock()
mock_tmdb.close = AsyncMock()
mock_tmdb.search_tv_show = AsyncMock(
return_value={"results": [{
"id": 999,
@@ -208,6 +212,8 @@ class TestCompleteNFOWorkflow:
mock_tmdb = Mock()
mock_tmdb.__aenter__ = AsyncMock(return_value=mock_tmdb)
mock_tmdb.__aexit__ = AsyncMock(return_value=None)
mock_tmdb._ensure_session = AsyncMock()
mock_tmdb.close = AsyncMock()
mock_tmdb.search_tv_show = AsyncMock(
side_effect=TMDBAPIError("API error")
)
@@ -253,6 +259,8 @@ class TestCompleteNFOWorkflow:
mock_tmdb = Mock()
mock_tmdb.__aenter__ = AsyncMock(return_value=mock_tmdb)
mock_tmdb.__aexit__ = AsyncMock(return_value=None)
mock_tmdb._ensure_session = AsyncMock()
mock_tmdb.close = AsyncMock()
mock_tmdb.search_tv_show = AsyncMock(
return_value={"results": [{
"id": 999,
@@ -307,16 +315,22 @@ class TestCompleteNFOWorkflow:
mock_tmdb = Mock()
mock_tmdb.__aenter__ = AsyncMock(return_value=mock_tmdb)
mock_tmdb.__aexit__ = AsyncMock(return_value=None)
mock_tmdb._ensure_session = AsyncMock()
mock_tmdb.close = AsyncMock()
mock_tmdb.search_tv_show = AsyncMock(
side_effect=[
{"results": [{"id": 1, "name": "Anime 1", "first_air_date": "2020-01-01"}]},
{"results": [{"id": 2, "name": "Anime 2", "first_air_date": "2021-01-01"}]},
{"results": [{"id": 1, "name": "Anime 1", "first_air_date": "2020-01-01"}]},
{"results": [{"id": 2, "name": "Anime 2", "first_air_date": "2021-01-01"}]},
]
)
mock_tmdb.get_tv_show_details = AsyncMock(
side_effect=[
{"id": 1, "name": "Anime 1", "first_air_date": "2020-01-01"},
{"id": 2, "name": "Anime 2", "first_air_date": "2021-01-01"},
{"id": 1, "name": "Anime 1", "first_air_date": "2020-01-01"},
{"id": 2, "name": "Anime 2", "first_air_date": "2021-01-01"},
]
)
mock_tmdb.get_tv_show_content_ratings = AsyncMock(return_value={"results": []})
@@ -366,6 +380,8 @@ class TestNFOWorkflowWithDownloads:
mock_tmdb = Mock()
mock_tmdb.__aenter__ = AsyncMock(return_value=mock_tmdb)
mock_tmdb.__aexit__ = AsyncMock(return_value=None)
mock_tmdb._ensure_session = AsyncMock()
mock_tmdb.close = AsyncMock()
mock_tmdb.search_tv_show = AsyncMock(
return_value={"results": [{
"id": 999,

View File

@@ -528,7 +528,13 @@ class TestLoadNfoAndImages:
year=2020
)
with patch("src.server.database.service.AnimeSeriesService") as mock_service_class:
mock_nfo_service = AsyncMock()
mock_nfo_service.create_tvshow_nfo = AsyncMock(return_value="/anime/test_folder/tvshow.nfo")
mock_factory = MagicMock()
mock_factory.create = MagicMock(return_value=mock_nfo_service)
with patch("src.server.database.service.AnimeSeriesService") as mock_service_class, \
patch("src.server.services.background_loader_service.get_nfo_factory", return_value=mock_factory):
mock_service_class.get_by_key = AsyncMock(return_value=mock_series)
result = await background_loader_service._load_nfo_and_images(task, mock_db)