from collections import defaultdict from http import HTTPStatus import pytest from server.legacy.core.constants import DELPHI_GLOBAL_MARKET, GLOBAL_MARKET_CODE, SPOTIFY from server.legacy.delphi.deserializers import StreamsGroupBy, StreamsInclude from tests.legacy.delphi.fixtures.responses import combine_vendor_data, get_streams pytest_plugins = ["tests.legacy.delphi.fixtures.responses"] @pytest.mark.parametrize( "params,expected_result", ( ( {"isrc": "USSM19902991", "market": "us", "vendor": "apple", "last_date": "2020-10-09"}, { "1055200360": 791, "360391": 4, "pl.5411245c134d43c3b4ceb5c81b038c2a": 905, "pl.af4d982795c6472ea48579eb147cd726": 5745, }, ), ( {"isrc": "USSM19902991", "market": "us", "vendor": "spotify"}, {"37i9dQZF1DX1spT6G94GFC": 1914, "7LblksdAMAj7O1HMyIyozB": 6, "7ib1G8uW767k0gw0nD5PG4": 18}, ), ( {"isrc": "USSM19902991", "vendor": "spotify", "last_date": "2020-10-08"}, {"37i9dQZF1DX1spT6G94GFC": 7233, "7LblksdAMAj7O1HMyIyozB": 186, "7ib1G8uW767k0gw0nD5PG4": 145}, ), ( {"isrc": "USSM19902991", "vendor": "apple"}, { "1055200360": 1415, "360391": 15, "pl.5411245c134d43c3b4ceb5c81b038c2a": 1245, "pl.af4d982795c6472ea48579eb147cd726": 15385, }, ), ), ) async def test_track_playlist_summary( params, expected_result, client, auth_header, mocked_streams, mocked_latest_dates ): response = await client.get("/api/consumer_analytics/playlists-summary", params=params, headers=auth_header) assert response.status == HTTPStatus.OK resp_data = await response.json() assert resp_data == expected_result @pytest.mark.parametrize( "isrc_list,vendor,all_markets,expected_result", [ ( ["USSM19902991", "USSM19902990"], "apple", "false", { "items": [ { "containerId": "1055200360", "globalDaysStreamed": 2, "globalStreams": 2450, "isrc": "USSM19902991", "localDaysStreamed": 2, "localStreams": 1576, }, { "containerId": "360391", "globalDaysStreamed": 2, "globalStreams": 34, "isrc": "USSM19902991", "localDaysStreamed": 2, "localStreams": 9, }, { "containerId": "pl.5411245c134d43c3b4ceb5c81b038c2a", "globalDaysStreamed": 2, "globalStreams": 2158, "isrc": "USSM19902991", "localDaysStreamed": 2, "localStreams": 1772, }, { "containerId": "pl.af4d982795c6472ea48579eb147cd726", "globalDaysStreamed": 2, "globalStreams": 22355, "isrc": "USSM19902991", "localDaysStreamed": 2, "localStreams": 10574, }, { "containerId": "1055200360", "globalDaysStreamed": 2, "globalStreams": 2022, "isrc": "USSM19902990", "localDaysStreamed": 2, "localStreams": 1506, }, { "containerId": "360391", "globalDaysStreamed": 2, "globalStreams": 4, "isrc": "USSM19902990", "localDaysStreamed": 1, "localStreams": 1, }, { "containerId": "pl.af4d982795c6472ea48579eb147cd726", "globalDaysStreamed": 2, "globalStreams": 1868, "isrc": "USSM19902990", "localDaysStreamed": 0, "localStreams": 0, }, ] }, ), ( ["USSM19902991", "USSM19902990"], "apple", None, { "items": [ { "containerId": "1055200360", "globalDaysStreamed": 2, "globalStreams": 2450, "isrc": "USSM19902991", "localDaysStreamed": 2, "localStreams": 1576, "markets": [ ["at", 2, 1], ["au", 92, 2], ["be", 6, 2], ["br", 4, 1], ["ca", 90, 2], ["ch", 17, 2], ["cl", 7, 2], ["cn", 4, 2], ["co", 4, 1], ["cr", 2, 2], ["de", 54, 2], ["dk", 4, 2], ["ec", 3, 2], ["es", 16, 2], ["fi", 3, 2], ["fr", 71, 2], ["gb", 395, 2], ["gt", 1, 1], ["hk", 3, 1], ["hn", 1, 1], ["id", 1, 1], ["ie", 8, 2], ["jp", 11, 2], ["lu", 5, 2], ["mx", 24, 2], ["nl", 16, 2], ["nz", 1, 1], ["pe", 1, 1], ["ru", 7, 2], ["se", 3, 2], ["sg", 2, 1], ["sv", 1, 1], ["tr", 5, 2], ["tw", 4, 2], ["us", 1576, 2], ["za", 6, 2], ], }, { "containerId": "360391", "globalDaysStreamed": 2, "globalStreams": 34, "isrc": "USSM19902991", "localDaysStreamed": 2, "localStreams": 9, "markets": [ ["au", 1, 1], ["ca", 3, 2], ["ch", 1, 1], ["co", 1, 1], ["de", 1, 1], ["fr", 5, 2], ["gb", 3, 2], ["it", 1, 1], ["jp", 1, 1], ["mx", 4, 2], ["ru", 1, 1], ["sg", 1, 1], ["us", 9, 2], ["za", 2, 2], ], }, { "containerId": "pl.5411245c134d43c3b4ceb5c81b038c2a", "globalDaysStreamed": 2, "globalStreams": 2158, "isrc": "USSM19902991", "localDaysStreamed": 2, "localStreams": 1772, "markets": [ ["ae", 1, 1], ["ar", 1, 1], ["at", 2, 1], ["au", 29, 2], ["bb", 1, 1], ["be", 2, 1], ["br", 3, 2], ["bw", 1, 1], ["ca", 25, 2], ["cl", 2, 1], ["cn", 8, 2], ["co", 3, 1], ["cr", 1, 1], ["cz", 1, 1], ["de", 27, 2], ["eg", 1, 1], ["es", 3, 2], ["fr", 11, 2], ["gb", 74, 2], ["il", 3, 2], ["in", 2, 1], ["it", 3, 2], ["jm", 1, 1], ["jp", 110, 2], ["ke", 12, 2], ["kr", 5, 2], ["md", 1, 1], ["mx", 1, 1], ["my", 1, 1], ["ng", 8, 2], ["nl", 2, 2], ["nz", 3, 2], ["pe", 2, 1], ["pg", 1, 1], ["ph", 3, 2], ["pl", 1, 1], ["ru", 7, 2], ["si", 3, 2], ["th", 1, 1], ["tw", 1, 1], ["tz", 1, 1], ["ug", 2, 2], ["us", 1772, 2], ["vn", 1, 1], ["za", 15, 2], ], }, { "containerId": "pl.af4d982795c6472ea48579eb147cd726", "globalDaysStreamed": 2, "globalStreams": 22355, "isrc": "USSM19902991", "localDaysStreamed": 2, "localStreams": 10574, "markets": [ ["ae", 50, 2], ["am", 1, 1], ["ao", 1, 1], ["ar", 2, 1], ["at", 81, 2], ["au", 698, 2], ["az", 4, 2], ["ba", 1, 1], ["bb", 2, 1], ["be", 79, 2], ["bg", 8, 2], ["bj", 1, 1], ["bo", 1, 1], ["bs", 3, 2], ["bw", 2, 2], ["by", 6, 2], ["bz", 2, 2], ["ca", 1676, 2], ["cg", 1, 1], ["ch", 507, 2], ["cl", 12, 2], ["cm", 1, 1], ["cn", 87, 2], ["co", 7, 2], ["cr", 2, 1], ["cy", 2, 2], ["cz", 100, 2], ["de", 756, 2], ["dk", 101, 2], ["ec", 3, 2], ["ee", 7, 2], ["eg", 4, 2], ["es", 219, 2], ["fi", 11, 2], ["fj", 3, 2], ["fr", 597, 2], ["gb", 2873, 2], ["ge", 1, 1], ["gh", 6, 2], ["gr", 16, 2], ["gt", 2, 2], ["hk", 46, 2], ["hn", 2, 2], ["hr", 9, 2], ["hu", 60, 2], ["id", 50, 2], ["ie", 91, 2], ["il", 90, 2], ["in", 162, 2], ["is", 1, 1], ["it", 250, 2], ["jm", 3, 2], ["jp", 844, 2], ["ke", 8, 2], ["kh", 1, 1], ["kr", 60, 2], ["kw", 4, 1], ["ky", 3, 2], ["kz", 17, 2], ["lb", 2, 1], ["lk", 19, 2], ["lt", 7, 2], ["lu", 10, 2], ["lv", 8, 2], ["ma", 2, 1], ["md", 5, 1], ["mn", 4, 1], ["mo", 1, 1], ["mt", 5, 2], ["mu", 4, 1], ["mw", 1, 1], ["mx", 34, 2], ["my", 27, 2], ["na", 4, 2], ["ng", 18, 2], ["nl", 73, 2], ["no", 47, 2], ["nz", 115, 2], ["om", 3, 2], ["pe", 3, 2], ["ph", 94, 2], ["pl", 106, 2], ["pt", 61, 2], ["py", 1, 1], ["qa", 7, 2], ["ro", 35, 2], ["rs", 5, 2], ["ru", 493, 2], ["sa", 14, 2], ["se", 31, 2], ["sg", 26, 2], ["si", 24, 2], ["sk", 41, 2], ["sv", 1, 1], ["th", 55, 2], ["tn", 1, 1], ["tr", 56, 2], ["tt", 10, 2], ["tw", 79, 2], ["tz", 4, 2], ["ua", 125, 2], ["ug", 2, 1], ["us", 10574, 2], ["vn", 20, 2], ["za", 459, 2], ["zm", 2, 2], ], }, { "containerId": "1055200360", "globalDaysStreamed": 2, "globalStreams": 2022, "isrc": "USSM19902990", "localDaysStreamed": 2, "localStreams": 1506, "markets": [ ["ar", 1, 1], ["at", 3, 1], ["au", 61, 2], ["be", 3, 1], ["br", 2, 2], ["ca", 99, 2], ["ch", 20, 2], ["cl", 3, 2], ["cn", 2, 1], ["co", 3, 2], ["de", 51, 2], ["dk", 7, 2], ["ec", 1, 1], ["es", 16, 2], ["fi", 1, 1], ["fr", 15, 2], ["gb", 146, 2], ["hk", 2, 2], ["ie", 4, 2], ["jp", 15, 2], ["kr", 2, 1], ["lk", 1, 1], ["lu", 2, 2], ["mx", 22, 2], ["nl", 7, 2], ["no", 1, 1], ["nz", 4, 2], ["ph", 1, 1], ["ru", 8, 2], ["se", 1, 1], ["tr", 1, 1], ["tw", 4, 2], ["us", 1506, 2], ["za", 7, 2], ], }, { "containerId": "360391", "globalDaysStreamed": 2, "globalStreams": 4, "isrc": "USSM19902990", "localDaysStreamed": 1, "localStreams": 1, "markets": [["jp", 2, 2], ["ru", 1, 1], ["us", 1, 1]], }, { "containerId": "pl.af4d982795c6472ea48579eb147cd726", "globalDaysStreamed": 2, "globalStreams": 1868, "isrc": "USSM19902990", "localDaysStreamed": 0, "localStreams": 0, "markets": [ ["ae", 10, 2], ["ao", 1, 1], ["at", 11, 2], ["bg", 2, 1], ["bw", 2, 2], ["cg", 1, 1], ["ch", 108, 2], ["cn", 8, 2], ["cz", 21, 2], ["de", 190, 2], ["dk", 30, 2], ["ee", 1, 1], ["es", 34, 2], ["fi", 3, 2], ["fj", 2, 2], ["fr", 121, 2], ["gb", 820, 2], ["gh", 2, 1], ["gr", 4, 2], ["hk", 10, 2], ["hr", 1, 1], ["hu", 14, 2], ["id", 8, 2], ["ie", 24, 2], ["il", 20, 2], ["in", 28, 2], ["it", 53, 2], ["ke", 1, 1], ["ky", 2, 1], ["kz", 2, 2], ["lb", 1, 1], ["lk", 2, 2], ["lv", 1, 1], ["md", 1, 1], ["mo", 1, 1], ["mt", 3, 2], ["my", 10, 2], ["na", 1, 1], ["ng", 6, 2], ["no", 13, 2], ["ph", 13, 2], ["pl", 21, 2], ["pt", 10, 2], ["qa", 2, 1], ["ro", 6, 2], ["rs", 4, 2], ["ru", 67, 2], ["sa", 3, 2], ["sg", 7, 2], ["si", 2, 1], ["sk", 7, 2], ["th", 6, 2], ["tr", 6, 2], ["tt", 5, 1], ["tw", 8, 2], ["ua", 17, 2], ["za", 109, 2], ["zm", 2, 2], ], }, ] }, ), ( ["USSM19902991", "USSM19902990"], "spotify", None, { "items": [ { "daysStreamed": 2, "globalStreams": 13246, "isrc": "USSM19902991", "localStreams": 3493, "playlistId": "37i9dQZF1DX1spT6G94GFC", }, { "daysStreamed": 2, "globalStreams": 387, "isrc": "USSM19902991", "localStreams": 9, "playlistId": "7LblksdAMAj7O1HMyIyozB", }, { "daysStreamed": 2, "globalStreams": 301, "isrc": "USSM19902991", "localStreams": 34, "playlistId": "7ib1G8uW767k0gw0nD5PG4", }, { "daysStreamed": 2, "globalStreams": 174, "isrc": "USSM19902990", "localStreams": 10, "playlistId": "7LblksdAMAj7O1HMyIyozB", }, ] }, ), ], ) async def test_track_playlist_summary_v1( isrc_list, vendor, all_markets, expected_result, client, auth_header, mocked_streams ): def sort_results(list_field: str, *args): for item in args: item[list_field].sort(key=lambda x: (x["isrc"], x["playlistId" if vendor == SPOTIFY else "containerId"])) params = { "isrc": ",".join(isrc_list), "start_date": "2020-10-01", "end_date": "2020-10-10", "vendor": vendor, "market": "us", } if all_markets: params["all_markets"] = all_markets response = await client.get("/api/consumer_analytics/v1/playlists-summary", params=params, headers=auth_header) assert response.status == HTTPStatus.OK resp_data = await response.json() sort_results("items", resp_data, expected_result) assert resp_data == expected_result @pytest.mark.parametrize( "params,expected_result", ( ( { "isrc": "USSM19902991,USSM19902990", "market": "au", "vendor": "apple", "start_date": "2020-10-01", "end_date": "2020-10-09", }, {"streams": {"USSM19902990": 13261, "USSM19902991": 23148}}, ), ( { "isrc": "USSM19902991,USSM19902990", "vendor": "spotify", "start_date": "2020-10-01", "end_date": "2020-10-08", }, {"streams": {"USSM19902990": 1444148, "USSM19902991": 2655532}}, ), ( {"isrc": "USSM19902990", "vendor": "apple", "start_date": "2020-09-30", "end_date": "2020-10-05"}, {"streams": {"USSM19902990": 235618}}, ), ( { "isrc": "USSM19902991,USSM19902990", "vendor": "apple", "start_date": "2020-10-01", "end_date": "2020-10-08", }, {"streams": {"USSM19902990": 412332, "USSM19902991": 677512}}, ), ( { "isrc": "USSM19902991", "vendor": "spotify", "market": "au", "start_date": "2020-10-07", "end_date": "2020-10-09", }, {"streams": {"USSM19902991": 34579}}, ), ), ) async def test_tracks_streams_view(params, expected_result, client, auth_header, mocked_streams): response = await client.get("/api/consumer_analytics/tracks-streams", params=params, headers=auth_header) assert response.status == HTTPStatus.OK resp_data = await response.json() assert resp_data == expected_result async def test_track_per_country_v1_view_combine(client, auth_header, mocked_streams): isrc_list = ["USSM19902991", "USSM19902990"] start_date = "2020-10-01" end_date = "2020-10-08" vendor = SPOTIFY params = { "isrc": ",".join(isrc_list), "start_date": start_date, "end_date": end_date, "vendor": vendor, "streams_only": "false", "combine_isrc": "true", } response = await client.get("/api/consumer_analytics/v1/track-per-country", params=params, headers=auth_header) assert response.status == HTTPStatus.OK resp_data = await response.json() data = await get_streams( start_date=start_date, end_date=end_date, isrc_list=isrc_list, dsp_list=[vendor], include=StreamsInclude.ALL, group_by=[StreamsGroupBy.DATE], ) data = combine_vendor_data(data, isrc_list) source_fields = ( "album", "artist", "chart", "collection", "daily_mix", "discover_weekly", "other", "others_playlist", "play_queue", "radio", "release_radar", "search", "unknown", ) expected_data = defaultdict(list) for item in data: streams_info = item.get(f"{vendor}_streams_info", {}) sources = streams_info.get("source", {}) market = item["country_code"] expected_data[GLOBAL_MARKET_CODE if market == DELPHI_GLOBAL_MARKET else market].append( { "date": item["date"], "streams": item["streams"], "listeners": streams_info.get("listeners", 0), "shuffle_play": streams_info.get("shuffle_play", 0), **{f"source{''.join(x.capitalize() for x in k.split('_'))}": sources.get(k, 0) for k in source_fields}, } ) expected_data = [ { "countryCode": GLOBAL_MARKET_CODE if market == DELPHI_GLOBAL_MARKET else market, "data": sorted(date_items, key=lambda x: x["date"]), } for market, date_items in sorted(expected_data.items()) ] assert resp_data == expected_data @pytest.mark.parametrize( "params,expected_result", ( ({}, {"date": "2020-10-15"}), ({"vendors": "spotify"}, {"date": "2020-10-15"}), ({"vendors": "apple"}, {"date": "2020-10-16"}), ({"vendors": "apple,amazon"}, {"apple": "2020-10-16", "amazon": "2020-10-14"}), ( {"vendors": "all"}, { "spotify": "2020-10-15", "apple": "2020-10-16", "amazon": "2020-10-14", "youtube": "2021-01-31", "tiktok": "2020-10-17", }, ), ), ) async def test_streams_latest_date_view(params, expected_result, client, auth_header, mocked_latest_dates): response = await client.get("/api/consumer_analytics/streams-latest-date", params=params, headers=auth_header) assert response.status == HTTPStatus.OK resp_data = await response.json() assert resp_data == expected_result