"""Transfer-ownership tests for /placements/total_vs_playlist_streams_by_store. DAILY grain, two CTEs (``playlist_streams_timeseries`` + ``streams_timeseries``). Both CTEs run through the v2 ``permissions_filter`` macro, so the visibility law applies to both the playlist-streams metric and the total-streams metric. Only the ``isrc=`` selector is precisely probable here. The endpoint also accepts ``global_participant_id=``, but that routes the query through ``V_STREAMS_BY_PARTICIPANT_*_DAILY`` (a catalogue-wide view per participant) and the response then mixes streams from every product the participant appears on. The visibility matrix is per-product, so the GP selector can't isolate product 5244974's transfer — for a former-owner profile, the participant's other still-owned products surface in the response. That selector is exercised in production by other paths; it isn't tested here. The ISRC selector test exercises both CTEs (each carries the v2 macro independently) and asserts visibility on: - ``data.all_stores_aggregation.total_streams`` and ``total_playlist_streams`` — the aggregate scalars - ``data.stores[].total_streams`` and ``total_playlist_streams`` — the per-store breakdowns must show no leak in any store """ from __future__ import annotations import pytest import requests from tests.integration.config import QA_BASE_URL from tests.integration.transfer_ownership.conftest import ( ISRC, PROBES, TRANSFER_PROFILES, WINDOW_PROBES, assert_visibility, profile_key_for, ) def _url(selector: str, probe: str) -> str: """Build the total_vs_playlist URL for a selector / probe pair.""" return ( f"{QA_BASE_URL}/placements/total_vs_playlist_streams_by_store?" f"{selector}&{PROBES[probe]}" ) def _payload(url: str, headers: dict) -> dict: """GET the endpoint and return the inner ``data`` body.""" response = requests.get(url, headers=headers) assert ( response.status_code == 200 ), f"GET {url} -> {response.status_code}: {response.text}" return response.json()["data"] def _assert_total_vs_playlist_visibility(payload: dict, profile_key: str, probe: str): """Assert visibility on every total-streams / playlist-streams figure the endpoint exposes — the all-stores aggregate scalars *and* every per-store entry. Both CTEs go through the v2 filter, so both metrics must respect the visibility matrix; no per-store row may leak streams past a former owner's cutoff.""" # all_stores_aggregation scalars agg = payload.get("all_stores_aggregation") or {} for metric in ("total_streams", "total_playlist_streams"): assert_visibility( agg, profile_key=profile_key, probe=probe, items_key=None, metric_key=metric, ) # per-store scalars — every store row must also respect the matrix for store in payload.get("stores") or []: for metric in ("total_streams", "total_playlist_streams"): assert_visibility( store, profile_key=profile_key, probe=probe, items_key=None, metric_key=metric, ) class TestTotalVsPlaylistByISRC: """ISRC selector — direct predicate on both CTEs.""" SELECTOR = f"isrc={ISRC}" @pytest.mark.parametrize("hdrs", TRANSFER_PROFILES) @pytest.mark.parametrize("probe", WINDOW_PROBES) def test_visibility(self, hdrs, probe): payload = _payload(_url(self.SELECTOR, probe), hdrs) _assert_total_vs_playlist_visibility(payload, profile_key_for(hdrs), probe)