feat(core): Add database support to SeriesApp (Task 7)

- Added db_session parameter to SeriesApp.__init__()
- Added db_session property and set_db_session() method
- Added init_from_db_async() for async database initialization
- Pass db_session to SerieList and SerieScanner during construction
- Added get_series_app_with_db() dependency for FastAPI endpoints
- All 815 unit tests and 55 API tests pass
This commit is contained in:
2025-12-01 19:42:04 +01:00
parent 246782292f
commit cb014cf547
6 changed files with 291 additions and 330 deletions

View File

@@ -385,3 +385,177 @@ class TestSeriesAppGetters:
pass
class TestSeriesAppDatabaseInit:
"""Test SeriesApp database initialization."""
@patch('src.core.SeriesApp.Loaders')
@patch('src.core.SeriesApp.SerieScanner')
@patch('src.core.SeriesApp.SerieList')
def test_init_without_db_session(
self, mock_serie_list, mock_scanner, mock_loaders
):
"""Test SeriesApp initializes without database session."""
test_dir = "/test/anime"
# Create app without db_session
app = SeriesApp(test_dir)
# Verify db_session is None
assert app._db_session is None
assert app.db_session is None
# Verify SerieList was called with db_session=None
mock_serie_list.assert_called_once()
call_kwargs = mock_serie_list.call_args[1]
assert call_kwargs.get("db_session") is None
# Verify SerieScanner was called with db_session=None
call_kwargs = mock_scanner.call_args[1]
assert call_kwargs.get("db_session") is None
@patch('src.core.SeriesApp.Loaders')
@patch('src.core.SeriesApp.SerieScanner')
@patch('src.core.SeriesApp.SerieList')
def test_init_with_db_session(
self, mock_serie_list, mock_scanner, mock_loaders
):
"""Test SeriesApp initializes with database session."""
test_dir = "/test/anime"
mock_db = Mock()
# Create app with db_session
app = SeriesApp(test_dir, db_session=mock_db)
# Verify db_session is set
assert app._db_session is mock_db
assert app.db_session is mock_db
# Verify SerieList was called with db_session
call_kwargs = mock_serie_list.call_args[1]
assert call_kwargs.get("db_session") is mock_db
# Verify SerieScanner was called with db_session
call_kwargs = mock_scanner.call_args[1]
assert call_kwargs.get("db_session") is mock_db
class TestSeriesAppDatabaseSession:
"""Test SeriesApp database session management."""
@patch('src.core.SeriesApp.Loaders')
@patch('src.core.SeriesApp.SerieScanner')
@patch('src.core.SeriesApp.SerieList')
def test_set_db_session_updates_all_components(
self, mock_serie_list, mock_scanner, mock_loaders
):
"""Test set_db_session updates app, list, and scanner."""
test_dir = "/test/anime"
mock_list = Mock()
mock_list.GetMissingEpisode.return_value = []
mock_scan = Mock()
mock_serie_list.return_value = mock_list
mock_scanner.return_value = mock_scan
# Create app without db_session
app = SeriesApp(test_dir)
assert app.db_session is None
# Create mock database session
mock_db = Mock()
# Set database session
app.set_db_session(mock_db)
# Verify all components are updated
assert app._db_session is mock_db
assert app.db_session is mock_db
assert mock_list._db_session is mock_db
assert mock_scan._db_session is mock_db
@patch('src.core.SeriesApp.Loaders')
@patch('src.core.SeriesApp.SerieScanner')
@patch('src.core.SeriesApp.SerieList')
def test_set_db_session_to_none(
self, mock_serie_list, mock_scanner, mock_loaders
):
"""Test setting db_session to None."""
test_dir = "/test/anime"
mock_list = Mock()
mock_list.GetMissingEpisode.return_value = []
mock_scan = Mock()
mock_serie_list.return_value = mock_list
mock_scanner.return_value = mock_scan
mock_db = Mock()
# Create app with db_session
app = SeriesApp(test_dir, db_session=mock_db)
# Set database session to None
app.set_db_session(None)
# Verify all components are updated
assert app._db_session is None
assert app.db_session is None
assert mock_list._db_session is None
assert mock_scan._db_session is None
class TestSeriesAppAsyncDbInit:
"""Test SeriesApp async database initialization."""
@pytest.mark.asyncio
@patch('src.core.SeriesApp.Loaders')
@patch('src.core.SeriesApp.SerieScanner')
@patch('src.core.SeriesApp.SerieList')
async def test_init_from_db_async_loads_from_database(
self, mock_serie_list, mock_scanner, mock_loaders
):
"""Test init_from_db_async loads series from database."""
import warnings
test_dir = "/test/anime"
mock_list = Mock()
mock_list.load_series_from_db = AsyncMock()
mock_list.GetMissingEpisode.return_value = [{"name": "Test"}]
mock_serie_list.return_value = mock_list
mock_db = Mock()
# Create app with db_session
app = SeriesApp(test_dir, db_session=mock_db)
# Initialize from database
await app.init_from_db_async()
# Verify load_series_from_db was called
mock_list.load_series_from_db.assert_called_once_with(mock_db)
# Verify series_list is populated
assert len(app.series_list) == 1
@pytest.mark.asyncio
@patch('src.core.SeriesApp.Loaders')
@patch('src.core.SeriesApp.SerieScanner')
@patch('src.core.SeriesApp.SerieList')
async def test_init_from_db_async_without_session_warns(
self, mock_serie_list, mock_scanner, mock_loaders
):
"""Test init_from_db_async warns without db_session."""
import warnings
test_dir = "/test/anime"
mock_list = Mock()
mock_list.GetMissingEpisode.return_value = []
mock_serie_list.return_value = mock_list
# Create app without db_session
app = SeriesApp(test_dir)
# Initialize from database should warn
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
await app.init_from_db_async()
# Check warning was raised
assert len(w) == 1
assert "without db_session" in str(w[0].message)