From 1cdfbc59acb88de987f854963c7165abbdfe5e24 Mon Sep 17 00:00:00 2001 From: NixReaper Date: Sun, 6 Sep 2026 07:45:39 -0500 Subject: [PATCH] Fix test isolation: trending tests were leaking data into other tests Not a bug in production code -- refresh_trending()'s tests use session_scope() for real, permanent commits (necessary, since refresh_trending manages its own sessions), unlike every other integration test's db_session fixture, which rolls back after each test. FakeTrendingProvider reused FAKE_MOVIE/FAKE_SERIES unmodified except for id/title, so every synthetic trending movie/series carried the same embedded video id and imdb_id -- values meant to be globally unique per real TMDb entity. Those commits were never rolled back, so they permanently occupied uq_video_provider_source/uq_external_id_source in the shared test database for the rest of the run, causing test_watch_providers.py (which runs later alphabetically and ingests the same fixtures unmodified via the normal rolled-back db_session) to collide against leaked data with 14 failures that had nothing to do with watch providers. Found by actually running the full suite against real Postgres -- confirms it was worth doing before this deploys. Co-Authored-By: Claude Sonnet 5 --- tests/integration/test_trending.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/tests/integration/test_trending.py b/tests/integration/test_trending.py index f304d35..c76bfd8 100644 --- a/tests/integration/test_trending.py +++ b/tests/integration/test_trending.py @@ -36,10 +36,32 @@ class FakeTrendingProvider(MetadataProvider): self._series_ids = series_ids async def get_movie(self, external_id: str) -> dict[str, Any]: - return {**FAKE_MOVIE, "id": int(external_id), "title": f"Movie {external_id}"} + # FAKE_MOVIE's embedded video id and imdb_id are fixed identifiers + # meant to be globally unique per real TMDb movie -- reusing them + # unmodified across multiple synthetic movies here would collide + # on uq_video_provider_source / uq_external_id_source. Unlike + # every other test file (db_session rolls back per test), + # refresh_trending's session_scope() commits are never rolled + # back, so that collision would otherwise permanently poison the + # shared test database for every later test in the same run that + # also ingests FAKE_MOVIE unmodified (see test_watch_providers.py). + return { + **FAKE_MOVIE, + "id": int(external_id), + "title": f"Movie {external_id}", + "videos": {"results": []}, + "imdb_id": None, + "external_ids": {}, + } async def get_series(self, external_id: str) -> dict[str, Any]: - return {**FAKE_SERIES, "id": int(external_id), "name": f"Series {external_id}"} + # Same reasoning as get_movie above, for FAKE_SERIES's imdb_id/tvdb_id. + return { + **FAKE_SERIES, + "id": int(external_id), + "name": f"Series {external_id}", + "external_ids": {}, + } async def get_season(self, series_external_id: str, season_number: int) -> dict[str, Any]: raise NotImplementedError