Complete Task 8: Database Support for NFO Status

- Added 5 NFO tracking fields to AnimeSeries model
- Fields: has_nfo, nfo_created_at, nfo_updated_at, tmdb_id, tvdb_id
- Added 3 service methods to AnimeService for NFO operations
- Methods: update_nfo_status, get_series_without_nfo, get_nfo_statistics
- SQLAlchemy auto-migration (no manual migration needed)
- Backward compatible with existing data
- 15 new tests added (19/19 passing)
- Tests: database models, service methods, integration queries
This commit is contained in:
2026-01-16 18:50:04 +01:00
parent 56b4975d10
commit d642234814
9 changed files with 1014 additions and 50 deletions

View File

@@ -0,0 +1,224 @@
"""Integration tests for NFO database operations.
Tests NFO status tracking across database models and services.
"""
from datetime import datetime, timezone
import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from src.server.database.base import Base
from src.server.database.models import AnimeSeries
@pytest.fixture
def db_engine():
"""Create in-memory SQLite database for testing."""
engine = create_engine("sqlite:///:memory:", echo=False)
Base.metadata.create_all(engine)
return engine
@pytest.fixture
def db_session(db_engine):
"""Create database session for testing."""
SessionLocal = sessionmaker(bind=db_engine)
session = SessionLocal()
yield session
session.close()
class TestNFODatabaseIntegration:
"""Integration tests for NFO database operations."""
def test_create_series_with_nfo_tracking(self, db_session):
"""Test creating series with NFO tracking fields."""
now = datetime.now(timezone.utc)
series = AnimeSeries(
key="test-series-nfo",
name="Test Series",
site="https://example.com",
folder="/anime/test",
has_nfo=True,
nfo_created_at=now,
tmdb_id=12345,
tvdb_id=67890
)
db_session.add(series)
db_session.commit()
# Retrieve and verify
retrieved = db_session.query(AnimeSeries).filter_by(
key="test-series-nfo"
).first()
assert retrieved is not None
assert retrieved.has_nfo is True
assert retrieved.tmdb_id == 12345
assert retrieved.tvdb_id == 67890
assert retrieved.nfo_created_at is not None
def test_query_series_without_nfo(self, db_session):
"""Test querying series without NFO files."""
# Create series with and without NFO
series_with = AnimeSeries(
key="with-nfo",
name="Series With NFO",
site="https://example.com",
folder="/anime/with",
has_nfo=True,
)
series_without_1 = AnimeSeries(
key="without-nfo-1",
name="Series Without NFO 1",
site="https://example.com",
folder="/anime/without1",
has_nfo=False,
)
series_without_2 = AnimeSeries(
key="without-nfo-2",
name="Series Without NFO 2",
site="https://example.com",
folder="/anime/without2",
has_nfo=False,
)
db_session.add_all([series_with, series_without_1, series_without_2])
db_session.commit()
# Query series without NFO
without_nfo = db_session.query(AnimeSeries).filter(
AnimeSeries.has_nfo == False # noqa: E712
).all()
assert len(without_nfo) == 2
assert all(s.has_nfo is False for s in without_nfo)
keys = [s.key for s in without_nfo]
assert "without-nfo-1" in keys
assert "without-nfo-2" in keys
def test_query_series_by_tmdb_id(self, db_session):
"""Test querying series by TMDB ID."""
series1 = AnimeSeries(
key="series-1",
name="Series 1",
site="https://example.com",
folder="/anime/1",
tmdb_id=111,
)
series2 = AnimeSeries(
key="series-2",
name="Series 2",
site="https://example.com",
folder="/anime/2",
tmdb_id=222,
)
series3 = AnimeSeries(
key="series-3",
name="Series 3",
site="https://example.com",
folder="/anime/3",
)
db_session.add_all([series1, series2, series3])
db_session.commit()
# Query specific TMDB ID
result = db_session.query(AnimeSeries).filter_by(
tmdb_id=111
).first()
assert result.key == "series-1"
# Query series with any TMDB ID
with_tmdb = db_session.query(AnimeSeries).filter(
AnimeSeries.tmdb_id.isnot(None)
).all()
assert len(with_tmdb) == 2
def test_update_nfo_status(self, db_session):
"""Test updating NFO status after creation."""
series = AnimeSeries(
key="update-test",
name="Update Test",
site="https://example.com",
folder="/anime/update",
has_nfo=False,
)
db_session.add(series)
db_session.commit()
# Update NFO status
now = datetime.now(timezone.utc)
series.has_nfo = True
series.nfo_created_at = now
series.nfo_updated_at = now
series.tmdb_id = 99999
db_session.commit()
# Refresh and verify
db_session.refresh(series)
assert series.has_nfo is True
assert series.nfo_created_at is not None
assert series.nfo_updated_at is not None
assert series.tmdb_id == 99999
def test_backward_compatibility(self, db_session):
"""Test backward compatibility with existing series."""
# Create series without NFO fields (like existing data)
series = AnimeSeries(
key="old-series",
name="Old Series",
site="https://example.com",
folder="/anime/old",
)
db_session.add(series)
db_session.commit()
# Verify default values
db_session.refresh(series)
assert series.has_nfo is False
assert series.nfo_created_at is None
assert series.nfo_updated_at is None
assert series.tmdb_id is None
assert series.tvdb_id is None
def test_nfo_statistics_queries(self, db_session):
"""Test queries for NFO statistics."""
# Create mixed data
for i in range(10):
has_nfo = i < 7 # 7 with NFO, 3 without
tmdb = i * 100 if i < 8 else None # 8 with TMDB
tvdb = i * 1000 if i < 5 else None # 5 with TVDB
series = AnimeSeries(
key=f"series-{i}",
name=f"Series {i}",
site="https://example.com",
folder=f"/anime/{i}",
has_nfo=has_nfo,
tmdb_id=tmdb,
tvdb_id=tvdb,
)
db_session.add(series)
db_session.commit()
# Count statistics
total = db_session.query(AnimeSeries).count()
with_nfo = db_session.query(AnimeSeries).filter(
AnimeSeries.has_nfo == True # noqa: E712
).count()
with_tmdb = db_session.query(AnimeSeries).filter(
AnimeSeries.tmdb_id.isnot(None)
).count()
with_tvdb = db_session.query(AnimeSeries).filter(
AnimeSeries.tvdb_id.isnot(None)
).count()
assert total == 10
assert with_nfo == 7
assert with_tmdb == 8
assert with_tvdb == 5