"""Integration tests for streams number consistency across endpoints.""" import pandas as pd import pytest from sound_recordings import config from tests.integration.request import request_get_cache class TestStreamsConsistency(object): """Test streaming numbers consistent across streams endpoints.""" @pytest.fixture def top_sound_recordings_response(self, request_headers): """Return top-sound-recordings response.""" return request_get_cache( config.TOP_SOUND_RECORDINGS_URL, headers=request_headers ) @pytest.fixture def top_sound_recording_isrc(self, top_sound_recordings_response): """Return the isrc for the top track.""" return top_sound_recordings_response.json().get("items")[0].get("isrc") @pytest.fixture def streams_response(self, request_headers, top_sound_recording_isrc): """Return streams response for a top-sound-recording.""" return request_get_cache( config.STREAMS_URL.replace("", top_sound_recording_isrc), headers=request_headers, ) @pytest.fixture def sos_response(self, request_headers, top_sound_recording_isrc): """Return source of streams response for a top-sound-recording.""" return request_get_cache( config.SOURCE_OF_STREAMS_URL.replace("", top_sound_recording_isrc), headers=request_headers, ) @pytest.fixture def store_filter(self): """Return common store filter.""" return "?store_ids=286" @pytest.fixture def country_filter(self): """Return common country filter.""" return "&country_code=DE" @pytest.fixture def date_filter(self): """Return common date filter.""" return "&start_date=HIGHWATERMARK&days=365" @pytest.fixture def sos_response_filtered( self, request_headers, store_filter, country_filter, date_filter, top_sound_recording_isrc, ): """Return source of streams response for a top-sound-recording.""" return request_get_cache( config.SOURCE_OF_STREAMS_URL.replace("", top_sound_recording_isrc) + store_filter + country_filter + date_filter, headers=request_headers, ) @pytest.fixture def streams_breakdown_response(self, request_headers, top_sound_recording_isrc): """Return streams breakdown response for a top-sound-recording.""" return request_get_cache( config.STREAMS_BREAKDOWN_URL.replace("", top_sound_recording_isrc), headers=request_headers, ) @pytest.fixture def streams_breakdown_response_filtered( self, request_headers, store_filter, country_filter, date_filter, top_sound_recording_isrc, ): """Return streams breakdown response for a top-sound-recording.""" return request_get_cache( config.STREAMS_BREAKDOWN_URL.replace("", top_sound_recording_isrc) + store_filter + date_filter + country_filter, headers=request_headers, ) @pytest.fixture def streams_response_filtered_by_country( self, request_headers, top_sound_recording_isrc ): """Return sound recording response for a top-sound-recording.""" return request_get_cache( config.STREAMS_URL.replace("", top_sound_recording_isrc) + "?country_code=US", headers=request_headers, ) @pytest.fixture def streams_response_filtered( self, request_headers, store_filter, country_filter, date_filter, top_sound_recording_isrc, ): """Return sound recording response for a top-sound-recording.""" return request_get_cache( config.STREAMS_URL.replace("", top_sound_recording_isrc) + store_filter + country_filter + date_filter, headers=request_headers, ) @pytest.mark.parametrize( "track_with_products", [ { "isrc": "USJMZ1800055", "product_ids": ["2320107"], "headers": { "Grass-Account-Id": "6971", # Frenchkiss "Grass-Account-Type": "vendor", "Orchard-User-Id": "alw:48071", }, }, { "isrc": "USJMZ1800048", "product_ids": ["2353825", "2320107"], "headers": { "Grass-Account-Id": "6971", # Frenchkiss "Grass-Account-Type": "vendor", "Orchard-User-Id": "alw:48071", }, }, ], ) @pytest.mark.skip(reason="need to remove or use analytics for product url") def test_streams_sum_up_across_products_for_a_track(self, track_with_products): """Check streams of a track sum up accross its products. If track belonging to only 1 product number of streams on track screen = number of streams on product screen. If track belonging to more than 1 product: number of streams on track screen = sum of the numbers of streams for this track on all of its products screen. """ isrc = track_with_products["isrc"] headers = track_with_products["headers"] track_all_time_streams = ( request_get_cache( config.STREAMS_URL.replace("", isrc), headers=headers ) .json() .get("aggregate") .get("all_time") ) track_streams_on_products_all_time = 0 for product_id in track_with_products["product_ids"]: product_payload = request_get_cache( config.PRODUCT_URL.replace("", product_id), headers=headers ).json() for track in product_payload["tracks"]: if track["isrc"] == isrc: track_streams_on_products_all_time += track["streams"]["aggregate"][ "all_time" ] assert track_all_time_streams == track_streams_on_products_all_time @pytest.mark.parametrize( "track_with_products", [ { "isrc": "USJMZ1800074", "product_id": "2439152", "headers": { "Grass-Account-Id": "6971", # Frenchkiss "Grass-Account-Type": "vendor", "Orchard-User-Id": "alw:48071", }, }, ], ) @pytest.mark.skip(reason="need to remove or use analytics for product url") def test_growth_percentage_is_consistent(self, track_with_products): """Check if growth percentage is consistent. For a track appearing on a single product we test that growth percentage of a track is equal to growth percentage of a product. """ isrc = track_with_products["isrc"] product_id = track_with_products["product_id"] headers = track_with_products["headers"] track_growth_pct = ( request_get_cache( config.STREAMS_URL.replace("", isrc), headers=headers ) .json() .get("aggregate") .get("growth_percentage") ) product_payload = request_get_cache( config.PRODUCT_URL.replace("", product_id), headers=headers ).json() product_growth_pct = product_payload["streams"]["aggregate"][ "growth_percentage" ] assert product_growth_pct == track_growth_pct @pytest.mark.skip(reason="Underlying dbt issue - needs to be investigated") def test_top_streams_equals_sound_recording_streams( self, top_sound_recordings_response, streams_response ): """Confirm consistent results between top tracks and track streams.""" top_sound_recordings = top_sound_recordings_response.json().get("items") top_sound_recordings_streams = top_sound_recordings[0].get("streams") sound_recording_streams_body = streams_response.json() df = pd.json_normalize(sound_recording_streams_body.get("aggregate"), "items") df["date"] = pd.to_datetime(df["date"]) sound_recording_streams_total = df[ df.date > df.date.max() - pd.to_timedelta("7day") ].streams.sum() assert top_sound_recordings_streams == sound_recording_streams_total def test_sound_recording_streams_equals_source_of_streams( self, sos_response, streams_response ): """Confirm consistent results between sound recording streams & sos.""" sos_payload = sos_response.json() stream_types = ["collection", "passive", "active"] source_of_streams_total = sum( [sos_payload.get(key).get("total") for key in stream_types] ) store_list = [item["name"] for item in sos_payload.get("sources")] ts_stores = streams_response.json().get("stores") df = pd.json_normalize(ts_stores, "items", "name") df["date"] = pd.to_datetime(df["date"]) comparable_stores_streams_total = df[ (df.date > df.date.max() - pd.to_timedelta("7day")) & df.name.isin(store_list) ].streams.sum() assert comparable_stores_streams_total == source_of_streams_total def test_filtered_streams_equals_filtered_source_of_streams( self, streams_breakdown_response_filtered, streams_response_filtered ): """Confirm consistent results between sound recording streams & sos.""" sos_payload = streams_breakdown_response_filtered.json() stream_types = ["ad_supported", "mid_tier", "subscription"] streams_breakdown_total = sum( [ sos_payload["streams_by_subscription"].get(key).get("total") for key in stream_types ] ) ts_aggregate = streams_response_filtered.json().get("aggregate") df = pd.json_normalize(ts_aggregate, "items") df["date"] = pd.to_datetime(df["date"]) streams_total = df.streams.sum() assert streams_total == streams_breakdown_total def test_source_of_streams_equals_streams_breakdown( self, sos_response, streams_breakdown_response ): """Confirm consistent results between sound recording streams & sos.""" sos_payload = sos_response.json() streams_breakdown_payload = streams_breakdown_response.json() stream_types = ["collection", "passive", "active"] source_of_streams_total = sum( [sos_payload.get(key).get("total") for key in stream_types] ) streams_breakdown_total = sum( [ streams_breakdown_payload["source_of_streams"].get(key).get("total") for key in stream_types ] ) assert streams_breakdown_total == source_of_streams_total def test_filtered_source_of_streams_equals_filtered_streams_breakdown( self, sos_response_filtered, streams_breakdown_response_filtered ): """Confirm consistent results between sound recording streams & sos.""" sos_payload = sos_response_filtered.json() streams_breakdown_payload = streams_breakdown_response_filtered.json() stream_types = ["collection", "passive", "active"] source_of_streams_total = sum( [sos_payload.get(key).get("total") for key in stream_types] ) streams_breakdown_total = sum( [ streams_breakdown_payload["source_of_streams"].get(key).get("total") for key in stream_types ] ) assert streams_breakdown_total == source_of_streams_total def test_sound_recording_streams_filtered_by_country_consistent( self, streams_response_filtered_by_country ): """Confirm consistent results between sound recording streams & sos.""" stores = streams_response_filtered_by_country.json().get("stores") aggregate = streams_response_filtered_by_country.json().get("aggregate") df_stores = pd.json_normalize(stores, "items", "name") df_stores["date"] = pd.to_datetime(df_stores["date"]) df_aggregate = pd.json_normalize(aggregate, "items") df_aggregate["date"] = pd.to_datetime(df_stores["date"]) stores_streams_total = df_stores[ (df_stores.date > df_stores.date.max() - pd.to_timedelta("7day")) ].streams.sum() streams_total = df_aggregate[ (df_aggregate.date > df_aggregate.date.max() - pd.to_timedelta("7day")) ].streams.sum() stores_saves_total = df_stores[ (df_stores.date > df_stores.date.max() - pd.to_timedelta("7day")) ].saves.sum() saves_total = df_aggregate[ (df_aggregate.date > df_aggregate.date.max() - pd.to_timedelta("7day")) ].saves.sum() assert stores_streams_total == streams_total assert stores_saves_total == saves_total