CI / lint (push) Canceled after 0s
CI / typecheck (push) Canceled after 0s
CI / unit-tests (push) Canceled after 0s
CI / integration-tests (push) Canceled after 0s
CI / container-build (push) Canceled after 0s
CI / dependency-audit (push) Canceled after 0s
TMDb's release_dates/content_ratings blocks were already fetched via append_to_response but discarded at normalization -- every downstream layer (ingestion write, repository read, schema, service) was unbuilt. Adds the full pipeline: NormalizedReleaseDate + get_or_create_certification, a shared polymorphic sync/read (movie and series both use it), and MovieDetailOut/SeriesDetailOut certification + release_dates fields. Series content_ratings has no date of its own, so each rating is anchored to the show's first_air_date with release_type="tv". Co-Authored-By: Claude Sonnet 5 <[email protected]>
135 lines
5.0 KiB
Python
135 lines
5.0 KiB
Python
"""Integration tests for release-dates/certifications (section 17,
|
|
additive): TMDb's release_dates/content_ratings blocks were already being
|
|
fetched via append_to_response, but dropped at the normalizer step -- every
|
|
downstream layer (ingestion write, repository read, schema, service) was
|
|
unbuilt. Mirrors test_movie_ingestion.py/test_series_ingestion.py's fake
|
|
provider pattern to exercise the full write -> read path against
|
|
PostgreSQL."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
import pytest
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.core.ids import aurora_id
|
|
from app.models.language_country import Certification
|
|
from app.models.movie import ReleaseDate
|
|
from app.providers.base import MetadataProvider
|
|
from app.services import movie_service, tv_service
|
|
from app.services.ingestion.movie_ingestion import ingest_movie
|
|
from app.services.ingestion.series_ingestion import ingest_series
|
|
from tests.unit.test_normalizer import FAKE_MOVIE, FAKE_SERIES
|
|
|
|
|
|
class FakeTMDbProvider(MetadataProvider):
|
|
slug = "tmdb"
|
|
name = "The Movie Database (TMDb)"
|
|
|
|
def __init__(self, movie_payload: dict[str, Any] | None = None, series_payload: dict[str, Any] | None = None) -> None:
|
|
self._movie_payload = movie_payload
|
|
self._series_payload = series_payload
|
|
|
|
async def get_movie(self, external_id: str) -> dict[str, Any]:
|
|
assert self._movie_payload is not None
|
|
return self._movie_payload
|
|
|
|
async def get_series(self, external_id: str) -> dict[str, Any]:
|
|
assert self._series_payload is not None
|
|
return self._series_payload
|
|
|
|
async def get_season(self, series_external_id: str, season_number: int) -> dict[str, Any]:
|
|
raise NotImplementedError
|
|
|
|
async def get_person(self, external_id: str) -> dict[str, Any]:
|
|
raise NotImplementedError
|
|
|
|
async def get_collection(self, external_id: str) -> dict[str, Any]:
|
|
raise NotImplementedError
|
|
|
|
async def search_movie(self, query: str) -> list[dict[str, Any]]:
|
|
raise NotImplementedError
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_ingest_movie_stores_release_dates_and_certifications(db_session: AsyncSession):
|
|
movie_id = await ingest_movie(db_session, FakeTMDbProvider(movie_payload=FAKE_MOVIE), "603")
|
|
await db_session.commit()
|
|
|
|
rows = (
|
|
(await db_session.execute(select(ReleaseDate).where(ReleaseDate.entity_id == movie_id)))
|
|
.scalars()
|
|
.all()
|
|
)
|
|
assert len(rows) == 4
|
|
|
|
us_theatrical = next(r for r in rows if r.country_code == "US" and r.release_type == "theatrical")
|
|
cert = await db_session.get(Certification, us_theatrical.certification_id)
|
|
assert cert.system == "MPA"
|
|
assert cert.rating == "R"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_ingest_movie_reingestion_replaces_release_dates(db_session: AsyncSession):
|
|
"""Wholesale replace on re-sync, same as credits/videos -- re-running
|
|
ingestion must not accumulate duplicate release-date rows."""
|
|
|
|
provider = FakeTMDbProvider(movie_payload=FAKE_MOVIE)
|
|
movie_id = await ingest_movie(db_session, provider, "603")
|
|
await db_session.commit()
|
|
|
|
movie_id_again = await ingest_movie(db_session, provider, "603")
|
|
await db_session.commit()
|
|
assert movie_id == movie_id_again
|
|
|
|
rows = (
|
|
(await db_session.execute(select(ReleaseDate).where(ReleaseDate.entity_id == movie_id)))
|
|
.scalars()
|
|
.all()
|
|
)
|
|
assert len(rows) == 4
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_movie_detail_surfaces_certification_and_release_dates(db_session: AsyncSession):
|
|
movie_id = await ingest_movie(db_session, FakeTMDbProvider(movie_payload=FAKE_MOVIE), "603")
|
|
await db_session.commit()
|
|
|
|
detail = await movie_service.get_movie_detail(db_session, aurora_id("movie", str(movie_id)))
|
|
|
|
assert detail.certification == "R" # US MPA rating, the default badge
|
|
assert len(detail.release_dates) == 4
|
|
us_theatrical = next(
|
|
rd for rd in detail.release_dates if rd.country_code == "US" and rd.release_type == "theatrical"
|
|
)
|
|
assert us_theatrical.certification.system == "MPA"
|
|
assert us_theatrical.certification.rating == "R"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_ingest_series_anchors_content_ratings_to_first_air_date(db_session: AsyncSession):
|
|
series_id = await ingest_series(db_session, FakeTMDbProvider(series_payload=FAKE_SERIES), "1396")
|
|
await db_session.commit()
|
|
|
|
rows = (
|
|
(await db_session.execute(select(ReleaseDate).where(ReleaseDate.entity_id == series_id)))
|
|
.scalars()
|
|
.all()
|
|
)
|
|
assert len(rows) == 2
|
|
assert all(r.release_type == "tv" for r in rows)
|
|
assert all(str(r.release_date) == "2008-01-20" for r in rows)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_series_detail_surfaces_certification(db_session: AsyncSession):
|
|
series_id = await ingest_series(db_session, FakeTMDbProvider(series_payload=FAKE_SERIES), "1396")
|
|
await db_session.commit()
|
|
|
|
detail = await tv_service.get_series_detail(db_session, aurora_id("series", str(series_id)))
|
|
|
|
assert detail.certification == "TV-MA"
|
|
assert len(detail.release_dates) == 2
|