import pytest from datetime import date, datetime, timedelta from flask import url_for from http import HTTPStatus from src.constants import core, http_status from src.constants.core import UNIX_EPOCH_START_DATE, MusicServices from tests.legacy.apollo_api.factories import ApolloMarketFactory, BuzzUserFactory from tests.legacy.apple_music import factories pytest_plugins = ["tests.legacy.dsp_api.fixtures.dsp_responses"] @pytest.mark.parametrize("market", ("us", "au", "global")) def test_track_playlists_added_date_view(mocker, db_session, user_id, client, patch_auth_user, market): patch_auth_user(user_id) isrc = "QZES71982312" if market != "global": song = factories.AppleMusicSongFactory.create(isrc=isrc, storefront=market) else: song = factories.AppleMusicSongFactory.create(isrc=isrc, storefront="gb") playlist_ids = ["id.1", "id.2", "id.3"] factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=playlist_ids[0], storefront="au", song_id=song.id, date=UNIX_EPOCH_START_DATE ) for _id in playlist_ids: factories.ApplePlaylistTracklistHistoryFactory.create(playlist_id=_id, storefront="us", song_id=song.id) factories.ApplePlaylistTracklistHistoryFactory.create(playlist_id=_id, storefront="us", song_id=song.id) url = url_for( "apple_music_blueprint.track-playlists-added-dates", song_id=song.id, market=market, playlist_ids=playlist_ids ) response = client.get(url) assert response.status_code == http_status.HTTP_200_OK data = response.json assert len(data) == 3 if market == "us": for obj in data: assert obj["id"] in playlist_ids assert obj["added_date"] is not None elif market == "au": for obj in data: _id = obj["id"] assert _id in playlist_ids assert obj["added_date"] is None else: for obj in data: assert obj["id"] in playlist_ids assert obj["added_date"] is None @pytest.mark.parametrize( "playlist_ids,response_dict,include", ( ( ["1aaa"], { "items": [ { "market": {"id": 1, "code": "us", "full_name": "the United States", "name": "United States"}, "id": "1aaa", } ] }, None, ), ( ["2aaa", "3aaa"], { "items": [ {"market": {"id": 5, "code": "pl", "full_name": "Poland", "name": "Poland"}, "id": "2aaa"}, { "market": {"id": 1, "code": "us", "full_name": "the United States", "name": "United States"}, "id": "3aaa", }, ] }, None, ), ( ["3aaa"], { "items": [ { "id": "3aaa", "market": {"id": 1, "code": "us", "full_name": "the United States", "name": "United States"}, "top_markets": [ {"id": 1, "code": "us", "full_name": "the United States", "name": "United States"}, {"id": 2, "code": "au", "full_name": "Australia", "name": "Australia"}, ], "other_markets": [ {"id": 5, "code": "pl", "full_name": "Poland", "name": "Poland"}, {"id": 4, "code": "ua", "full_name": "Ukraine", "name": "Ukraine"}, ], } ] }, "top_markets,other_markets", ), ( ["3aaa"], { "items": [ { "id": "3aaa", "market": {"id": 1, "code": "us", "full_name": "the United States", "name": "United States"}, "other_markets": [ {"id": 5, "code": "pl", "full_name": "Poland", "name": "Poland"}, {"id": 4, "code": "ua", "full_name": "Ukraine", "name": "Ukraine"}, ], } ] }, "other_markets", ), ), ) def test_playlists_markets_view(db_session, user_id, client, patch_auth_user, playlist_ids, response_dict, include): patch_auth_user(user_id) ApolloMarketFactory.create(id=1, code="us", name="United States", full_name="the United States", is_primary=True) ApolloMarketFactory.create(id=2, code="au", name="Australia", full_name="Australia", is_primary=True) ApolloMarketFactory.create(id=3, code="br", name="Brazil", full_name="Brazil", is_primary=False) ApolloMarketFactory.create(id=4, code="ua", name="Ukraine", full_name="Ukraine", is_primary=True) ApolloMarketFactory.create(id=5, code="pl", name="Poland", full_name="Poland", is_primary=True) factories.ApplePlaylistStorefrontDataFactory.create(playlist_id="1aaa", storefront="us") factories.ApplePlaylistStorefrontDataFactory.create(playlist_id="2aaa", storefront="pl") factories.ApplePlaylistStorefrontDataFactory.create(playlist_id="2aaa", storefront="br") factories.ApplePlaylistStorefrontDataFactory.create(playlist_id="3aaa", storefront="au") factories.ApplePlaylistStorefrontDataFactory.create(playlist_id="3aaa", storefront="us") factories.ApplePlaylistStorefrontDataFactory.create(playlist_id="3aaa", storefront="pl") factories.ApplePlaylistStorefrontDataFactory.create(playlist_id="3aaa", storefront="ua") url = url_for("v1_apple_music_blueprint.playlists-markets-v1", id=",".join(playlist_ids), include=include) response = client.get(url) assert response.status_code == http_status.HTTP_200_OK assert response.json == response_dict def generate_playlist_data(): BuzzUserFactory.create(user_name="11", music_service=MusicServices.APPLEMUSIC, display_name="dn1") BuzzUserFactory.create(user_name="22", music_service=MusicServices.APPLEMUSIC, display_name="dn2") BuzzUserFactory.create(user_name="33", music_service=MusicServices.APPLEMUSIC, display_name="dn3") factories.ApplePlaylistFactory.create(id="1aaa", curator_id=11, latest_update=date(2021, 1, 1)) factories.ApplePlaylistFactory.create(id="2aaa", curator_id=22, latest_update=date(2021, 1, 2)) factories.ApplePlaylistFactory.create(id="3aaa", curator_id=33, latest_update=date(2021, 1, 3)) factories.ApplePlaylistStorefrontDataFactory.create(playlist_id="1aaa", storefront="us", name="pl1", artwork="img1") factories.ApplePlaylistStorefrontDataFactory.create(playlist_id="2aaa", storefront="us", name="pl2", artwork="img2") factories.ApplePlaylistStorefrontDataFactory.create(playlist_id="2aaa", storefront="au", name="pl2", artwork="img2") factories.ApplePlaylistStorefrontDataFactory.create(playlist_id="3aaa", storefront="us", name="pl3", artwork="img3") factories.ApplePlaylistStorefrontDataFactory.create(playlist_id="3aaa", storefront="de", name="pl3", artwork="img3") @pytest.mark.parametrize( "playlist_ids,response_dict,market", ( ( ["1aaa", "2aaa"], { "items": [ { "name": "pl1", "id": "1aaa", "image_url": "img1", "country_code": "us", "curator_name": "dn1", "curator_id": "11", "updated_date": "2021-01-01", }, { "name": "pl2", "id": "2aaa", "image_url": "img2", "country_code": "us", "curator_name": "dn2", "curator_id": "22", "updated_date": "2021-01-02", }, ] }, "us", ), (["2aaa"], {"items": []}, "ca"), ( ["2aaa", "3aaa"], { "items": [ { "name": "pl2", "id": "2aaa", "image_url": "img2", "country_code": "au", "curator_name": "dn2", "curator_id": "22", "updated_date": "2021-01-02", } ] }, "au", ), ( ["3aaa"], { "items": [ { "name": "pl3", "id": "3aaa", "image_url": "img3", "country_code": "de", "curator_name": "dn3", "curator_id": "33", "updated_date": "2021-01-03", } ] }, "de", ), ), ) def test_playlists_data_in_market_view( db_session, user_id, client, patch_auth_user, playlist_ids, response_dict, market ): patch_auth_user(user_id) generate_playlist_data() url = url_for("v1_apple_music_blueprint.playlists-data-v1", id=",".join(playlist_ids), market=market) response = client.get(url) assert response.status_code == http_status.HTTP_200_OK assert response.json == response_dict @pytest.mark.parametrize( "body,status,expected_result", ( ({}, HTTPStatus.BAD_REQUEST, None), ({"items": []}, HTTPStatus.BAD_REQUEST, None), ({"items": [{}]}, HTTPStatus.BAD_REQUEST, None), ({"items": [{"id": "1aab", "country_code": "us"}]}, HTTPStatus.OK, {"items": []}), ( {"items": [{"id": "1aaa", "country_code": "us"}]}, HTTPStatus.OK, { "items": [ { "country_code": "us", "curator_id": "11", "curator_name": "dn1", "id": "1aaa", "image_url": "img1", "name": "pl1", "updated_date": "2021-01-01", }, ], }, ), ( { "items": [ {"id": "1aaa", "country_code": "us"}, {"id": "3aaa", "country_code": "de"}, {"id": "4aaa", "country_code": "ca"}, ], }, HTTPStatus.OK, { "items": [ { "country_code": "us", "curator_id": "11", "curator_name": "dn1", "id": "1aaa", "image_url": "img1", "name": "pl1", "updated_date": "2021-01-01", }, { "country_code": "de", "curator_id": "33", "curator_name": "dn3", "id": "3aaa", "image_url": "img3", "name": "pl3", "updated_date": "2021-01-03", }, ], }, ), ), ) def test_playlists_bulk_view(body, status, expected_result, user_id, client, patch_auth_user, db_session): patch_auth_user(user_id) if status == HTTPStatus.OK: generate_playlist_data() response = client.post(url_for("v1_apple_music_blueprint.playlists-bulk-v1"), json=body) assert response.status_code == status if status == HTTPStatus.OK: assert response.json == expected_result def test_playlist_tracklist_view_v1(db_session, user_id, client, patch_auth_user): patch_auth_user(user_id) today, now = date.today(), datetime.now() position_change_date_1 = now - timedelta(days=2) added_date_1 = today - timedelta(days=10) added_date_2 = today - timedelta(days=100) pl_1 = factories.ApplePlaylistFactory.create(id="pl.a1", latest_update=today) pl_2 = factories.ApplePlaylistFactory.create(id="pl.a2", latest_update=today) song_1 = factories.AppleMusicSongFactory.create(id=1, name="song1", storefront="us", isrc="isrc1") song_2 = factories.AppleMusicSongFactory.create(id=2, name="song2", storefront="us", isrc="isrc2") song_3 = factories.AppleMusicSongFactory.create(id=3, name="song3", storefront="us", isrc="isrc3") song_4 = factories.AppleMusicSongFactory.create(id=4, name="song4", storefront="us", isrc="isrc4") factories.ApplePlaylistTrackListFactory.create( storefront="us", position=0, previous_position=0, playlist_id=pl_1.id, song_id=song_1.id, latest_position_change=position_change_date_1, added_datetime=added_date_2, added_earliest_datetime=added_date_2, ) factories.ApplePlaylistTrackListFactory.create( storefront="us", position=1, previous_position=1, playlist_id=pl_1.id, song_id=song_2.id, latest_position_change=today, added_datetime=today, added_earliest_datetime=today, ) factories.ApplePlaylistTrackListFactory.create( storefront="us", position=2, previous_position=5, playlist_id=pl_1.id, song_id=song_3.id, latest_position_change=position_change_date_1, added_datetime=added_date_2, added_earliest_datetime=added_date_2, ) factories.ApplePlaylistTrackListFactory.create( storefront="us", position=3, previous_position=2, playlist_id=pl_1.id, song_id=song_4.id, latest_position_change=position_change_date_1, added_datetime=added_date_1, added_earliest_datetime=added_date_1, ) factories.ApplePlaylistTrackListFactory.create( storefront="us", position=3, previous_position=4, playlist_id=pl_2.id, song_id=song_1.id, latest_position_change=position_change_date_1, added_datetime=added_date_1, added_earliest_datetime=added_date_1, ) factories.ApplePlaylistTrackListFactory.create( storefront="us", position=2, previous_position=5, playlist_id=pl_2.id, song_id=song_2.id, latest_position_change=position_change_date_1, added_datetime=added_date_2, added_earliest_datetime=added_date_2, ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_1.id, storefront="us", song_id=song_1.id, date=today, ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_1.id, storefront="us", song_id=song_1.id, date=position_change_date_1, ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_1.id, storefront="us", song_id=song_4.id, date=today ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_2.id, storefront="us", song_id=song_2.id, date=today ) expected_output = { 1: {"added_date": (today - timedelta(days=2)).isoformat(), "trend": 0, "is_new": False}, 2: {"added_date": today.isoformat(), "trend": None, "is_new": True}, 3: {"added_date": added_date_2.isoformat(), "trend": -3, "is_new": False}, 4: {"added_date": today.isoformat(), "trend": 1, "is_new": False}, } url = url_for("v1_apple_music_blueprint.track-playlist-tracklist-v1", market="us", playlist_id="pl.a1") response = client.get(url) assert response.status_code == http_status.HTTP_200_OK data = response.json assert data["count"] == 4 for item in data.get("items", []): track_id = item["track_id"] assert item["added_date"] == expected_output[track_id]["added_date"] assert item["trend"] == expected_output[track_id]["trend"] assert item["is_new"] == expected_output[track_id]["is_new"] @pytest.mark.parametrize("playlist_id,limit,count", (("pl.a1", 1, 4), ("pl.a2", None, 2), ("pl.a3", 10, 0))) def test_playlist_tracklist_allocated_graph_view_v1( db_session, user_id, client, patch_auth_user, playlist_id, limit, count ): patch_auth_user(user_id) today = date.today() release_date_1 = today - timedelta(days=10) release_date_2 = today - timedelta(days=100) release_date_3 = today - timedelta(days=1) release_date_4 = today - timedelta(days=1000) release_date_5 = today - timedelta(days=2) release_date_6 = today - timedelta(days=20) pl_1 = factories.ApplePlaylistFactory.create(id="pl.a1") pl_2 = factories.ApplePlaylistFactory.create(id="pl.a2") album_1 = factories.AppleMusicAlbumFactory.create(id=1, name="album1", storefront="us", release_date=release_date_1) album_2 = factories.AppleMusicAlbumFactory.create(id=2, name="album2", storefront="us", release_date=release_date_2) song_1 = factories.AppleMusicSongFactory.create( id=1, name="song1", storefront="us", isrc="isrc1", album_id=1, release_date=release_date_3 ) song_2 = factories.AppleMusicSongFactory.create( id=2, name="song2", storefront="us", isrc="isrc2", album_id=1, release_date=release_date_4 ) song_3 = factories.AppleMusicSongFactory.create( id=3, name="song3", storefront="us", isrc="isrc3", album_id=2, release_date=release_date_5 ) song_4 = factories.AppleMusicSongFactory.create( id=4, name="song4", storefront="us", isrc="isrc4", album_id=2, release_date=release_date_6 ) songs = [song_1, song_2, song_3, song_4] albums = [album_1, album_1, album_2, album_2] playlist_to_songs_ids = {"pl.a1": set(range(1, 5)), "pl.a2": {1, 2}, "pl.a3": []} factories.ApplePlaylistTrackListFactory.create(storefront="us", position=0, playlist_id=pl_1.id, song_id=song_1.id) factories.ApplePlaylistTrackListFactory.create(storefront="us", position=1, playlist_id=pl_1.id, song_id=song_2.id) factories.ApplePlaylistTrackListFactory.create(storefront="us", position=2, playlist_id=pl_1.id, song_id=song_3.id) factories.ApplePlaylistTrackListFactory.create(storefront="us", position=3, playlist_id=pl_1.id, song_id=song_4.id) factories.ApplePlaylistTrackListFactory.create(storefront="us", position=3, playlist_id=pl_2.id, song_id=song_1.id) factories.ApplePlaylistTrackListFactory.create(storefront="us", position=2, playlist_id=pl_2.id, song_id=song_2.id) url = url_for( "v1_apple_music_blueprint.track-playlist-tracklist-allocated-graph-v1", market="us", playlist_id=playlist_id ) response = client.get(url) assert response.status_code == http_status.HTTP_200_OK data = response.json assert data["count"] == count for item in data.get("items", []): track_id = item["track_id"] assert track_id in playlist_to_songs_ids[playlist_id] indx = int(track_id) - 1 db_song = songs[indx] db_album = albums[indx] assert item["album_release_date"] == db_album.release_date.isoformat().split("T")[0] assert item["release_date"] == db_song.release_date.isoformat().split("T")[0] assert item["isrc"] == db_song.isrc @pytest.mark.parametrize( "isrc,playlist_type", (("isrc1", "current"), ("isrc2", "current"), ("isrc3", "current"), ("isrc4", "current"), ("isrc5", "past")), ) def test_playlist_tracklist_track_view_v1(db_session, user_id, client, patch_auth_user, isrc, playlist_type): patch_auth_user(user_id) today, now = date.today(), datetime.now() position_change_date_1 = now - timedelta(days=2) position_change_date_2 = now - timedelta(days=20) added_date_1 = today - timedelta(days=10) added_date_2 = today - timedelta(days=100) earliest_added_date_1 = today - timedelta(days=20) earliest_added_date_2 = today - timedelta(days=60) removed_date = today - timedelta(days=10) pl_1 = factories.ApplePlaylistFactory.create(id="pl.a1") song_1 = factories.AppleMusicSongFactory.create(id=1, name="song1", storefront="us", isrc="isrc1") song_2 = factories.AppleMusicSongFactory.create(id=2, name="song2", storefront="us", isrc="isrc2") song_3 = factories.AppleMusicSongFactory.create(id=3, name="song3", storefront="us", isrc="isrc3") song_4 = factories.AppleMusicSongFactory.create(id=4, name="song4", storefront="us", isrc="isrc4") song_5 = factories.AppleMusicSongFactory.create(id=5, name="song5", storefront="us", isrc="isrc5") factories.ApplePlaylistTrackListFactory.create( storefront="us", position=0, previous_position=0, playlist_id=pl_1.id, song_id=song_1.id, latest_position_change=position_change_date_1, added_datetime=added_date_2, added_earliest_datetime=added_date_2, ) factories.ApplePlaylistTrackListFactory.create( storefront="us", position=1, previous_position=3, playlist_id=pl_1.id, song_id=song_2.id, latest_position_change=position_change_date_2, added_datetime=today, added_earliest_datetime=today, ) factories.ApplePlaylistTrackListFactory.create( storefront="us", position=2, previous_position=5, playlist_id=pl_1.id, song_id=song_3.id, latest_position_change=position_change_date_1, added_datetime=added_date_2, added_earliest_datetime=added_date_2, ) factories.ApplePlaylistTrackListFactory.create( storefront="us", position=3, previous_position=2, playlist_id=pl_1.id, song_id=song_4.id, latest_position_change=position_change_date_1, added_datetime=added_date_1, added_earliest_datetime=added_date_1, ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_1.id, storefront="us", song_id=song_1.id, date=earliest_added_date_1 ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_1.id, storefront="us", song_id=song_4.id, date=earliest_added_date_2 ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_1.id, storefront="us", song_id=song_5.id, date=earliest_added_date_2 ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_1.id, storefront="us", song_id=song_5.id, date=removed_date ) url = url_for( "v1_apple_music_blueprint.track-in-playlist-v1", market="us", playlist_id="pl.a1", isrc=isrc, playlist_type=playlist_type, ) response = client.get(url) assert response.status_code == http_status.HTTP_200_OK data = response.json expected_output = { "isrc1": {"added_date": earliest_added_date_1.isoformat(), "trend": 0, "is_new": False, "current_position": 1}, "isrc2": {"added_date": today.isoformat(), "trend": None, "is_new": True, "current_position": 2}, "isrc3": {"added_date": added_date_2.isoformat(), "trend": -3, "is_new": False, "current_position": 3}, "isrc4": {"added_date": earliest_added_date_2.isoformat(), "trend": 1, "is_new": False, "current_position": 4}, "isrc5": { "added_date": earliest_added_date_2.isoformat(), "trend": None, "is_new": None, "current_position": None, "removed_date": removed_date.isoformat(), }, } assert data["added_date"] == expected_output[isrc]["added_date"] assert data.get("trend") == expected_output[isrc]["trend"] assert data.get("is_new") is expected_output[isrc]["is_new"] assert data["current_position"] == expected_output[isrc]["current_position"] assert data["removed_date"] == expected_output[isrc].get("removed_date") @pytest.mark.parametrize( "isrc,recent_adds_only,order_by,search,response_dict", ( ( "isrc11111111", True, ["current_position"], None, { "count": 2, "items": [ { "added_date": (date.today() - timedelta(days=2)).isoformat(), "country_code": "us", "current_position": 3, "id": "pl.1", "image_url": "pl_artwork_1", "is_new": False, "isrc": "isrc11111111", "name": "pl one", "position_change_date": (datetime.now() - timedelta(days=7)).date().isoformat(), "track_id": 1, "trend": -8, "updated_date": "2021-01-10", }, { "added_date": (date.today() - timedelta(days=6)).isoformat(), "country_code": "us", "current_position": 5, "id": "pl.4", "image_url": "pl_artwork_4", "is_new": False, "isrc": "isrc11111111", "name": "pl four one", "position_change_date": (datetime.now() - timedelta(days=7)).date().isoformat(), "track_id": 1, "trend": -2, "updated_date": "2021-01-12", }, ], "next": None, "previous": None, }, ), ( "isrc22222222", False, ["-current_position"], None, { "count": 3, "items": [ { "added_date": (date.today() - timedelta(days=40)).isoformat(), "country_code": "us", "current_position": 10, "id": "pl.1", "image_url": "pl_artwork_1", "is_new": False, "isrc": "isrc22222222", "name": "pl one", "position_change_date": None, "track_id": 2, "trend": 0, "updated_date": "2021-01-10", }, { "added_date": (date.today() - timedelta(days=2)).isoformat(), "country_code": "us", "current_position": 3, "id": "pl.2", "image_url": "pl_artwork_2", "is_new": False, "isrc": "isrc22222222", "name": "pl two one", "position_change_date": (datetime.now() - timedelta(days=7)).date().isoformat(), "track_id": 2, "trend": 0, "updated_date": "2021-02-10", }, { "added_date": (date.today() - timedelta(days=6)).isoformat(), "country_code": "us", "current_position": 2, "id": "pl.4", "image_url": "pl_artwork_4", "is_new": False, "isrc": "isrc22222222", "name": "pl four one", "position_change_date": (datetime.now() - timedelta(days=7)).date().isoformat(), "track_id": 2, "trend": -9, "updated_date": "2021-01-12", }, ], "next": None, "previous": None, }, ), ( "isrc11111111", False, None, "one", { "count": 2, "items": [ { "added_date": (date.today() - timedelta(days=6)).isoformat(), "country_code": "us", "current_position": 5, "id": "pl.4", "image_url": "pl_artwork_4", "is_new": False, "isrc": "isrc11111111", "name": "pl four one", "position_change_date": (datetime.now() - timedelta(days=7)).date().isoformat(), "track_id": 1, "trend": -2, "updated_date": "2021-01-12", }, { "added_date": (date.today() - timedelta(days=2)).isoformat(), "country_code": "us", "current_position": 3, "id": "pl.1", "image_url": "pl_artwork_1", "is_new": False, "isrc": "isrc11111111", "name": "pl one", "position_change_date": (datetime.now() - timedelta(days=7)).date().isoformat(), "track_id": 1, "trend": -8, "updated_date": "2021-01-10", }, ], "next": None, "previous": None, }, ), ( "isrc22222222", True, ["-added_date"], "one", { "count": 2, "items": [ { "added_date": (date.today() - timedelta(days=2)).isoformat(), "country_code": "us", "current_position": 3, "id": "pl.2", "image_url": "pl_artwork_2", "is_new": False, "isrc": "isrc22222222", "name": "pl two one", "position_change_date": (datetime.now() - timedelta(days=7)).date().isoformat(), "track_id": 2, "trend": 0, "updated_date": "2021-02-10", }, { "added_date": (date.today() - timedelta(days=6)).isoformat(), "country_code": "us", "current_position": 2, "id": "pl.4", "image_url": "pl_artwork_4", "is_new": False, "isrc": "isrc22222222", "name": "pl four one", "position_change_date": (datetime.now() - timedelta(days=7)).date().isoformat(), "track_id": 2, "trend": -9, "updated_date": "2021-01-12", }, ], "next": None, "previous": None, }, ), ( "isrc11111111", True, None, None, { "count": 2, "items": [ { "added_date": (date.today() - timedelta(days=6)).isoformat(), "country_code": "us", "current_position": 5, "id": "pl.4", "image_url": "pl_artwork_4", "is_new": False, "isrc": "isrc11111111", "name": "pl four one", "position_change_date": (datetime.now() - timedelta(days=7)).date().isoformat(), "track_id": 1, "trend": -2, "updated_date": "2021-01-12", }, { "added_date": (date.today() - timedelta(days=2)).isoformat(), "country_code": "us", "current_position": 3, "id": "pl.1", "image_url": "pl_artwork_1", "is_new": False, "isrc": "isrc11111111", "name": "pl one", "position_change_date": (datetime.now() - timedelta(days=7)).date().isoformat(), "track_id": 1, "trend": -8, "updated_date": "2021-01-10", }, ], "next": None, "previous": None, }, ), ), ) def test_track_playlists_view_v1( db_session, user_id, client, patch_auth_user, isrc, recent_adds_only, order_by, search, response_dict ): patch_auth_user(user_id) today, now = date.today(), datetime.now() change_date_1 = now - timedelta(days=7) change_date_2 = now - timedelta(days=18) added_date_1 = today - timedelta(days=2) added_date_3 = today - timedelta(days=6) added_date_4 = today - timedelta(days=100) added_date_5 = today - timedelta(days=40) pl_1 = factories.ApplePlaylistFactory.create( id="pl.1", name="pl one", latest_update=date(2021, 1, 10), artwork="pl_artwork_1" ) pl_2 = factories.ApplePlaylistFactory.create( id="pl.2", name="pl two one", latest_update=date(2021, 2, 10), artwork="pl_artwork_2" ) pl_3 = factories.ApplePlaylistFactory.create( id="pl.3", name="pl three two", latest_update=date(2021, 1, 10), artwork="pl_artwork_3" ) pl_4 = factories.ApplePlaylistFactory.create( id="pl.4", name="pl four one", latest_update=date(2021, 1, 12), artwork="pl_artwork_4" ) song_1 = factories.AppleMusicSongFactory.create( id=1, name="song1", storefront="us", isrc="isrc11111111", artwork_url="artwork1" ) song_2 = factories.AppleMusicSongFactory.create( id=2, name="song4", storefront="us", isrc="isrc22222222", artwork_url="artwork2" ) factories.ApplePlaylistTrackListFactory.create( position=2, previous_position=10, playlist_id=pl_1.id, song_id=song_1.id, storefront="us", latest_position_change=change_date_1, added_datetime=added_date_1, added_earliest_datetime=added_date_1, ) factories.ApplePlaylistTrackListFactory.create( position=10, previous_position=10, playlist_id=pl_3.id, song_id=song_1.id, storefront="us", latest_position_change=change_date_2, added_datetime=added_date_4, added_earliest_datetime=added_date_4, ) factories.ApplePlaylistTrackListFactory.create( position=4, previous_position=6, playlist_id=pl_4.id, song_id=song_1.id, storefront="us", latest_position_change=change_date_1, added_datetime=added_date_3, added_earliest_datetime=added_date_3, ) factories.ApplePlaylistTrackListFactory.create( position=9, previous_position=9, playlist_id=pl_1.id, song_id=song_2.id, storefront="us", latest_position_change=change_date_2, added_datetime=added_date_5, added_earliest_datetime=added_date_5, ) factories.ApplePlaylistTrackListFactory.create( position=2, previous_position=2, playlist_id=pl_2.id, song_id=song_2.id, storefront="us", latest_position_change=change_date_1, added_datetime=added_date_1, added_earliest_datetime=added_date_1, ) factories.ApplePlaylistTrackListFactory.create( position=1, previous_position=10, playlist_id=pl_4.id, song_id=song_2.id, storefront="us", latest_position_change=change_date_1, added_datetime=added_date_3, added_earliest_datetime=added_date_3, ) url = url_for( "v1_apple_music_blueprint.track-playlists-v1", market="us", isrc=isrc, recent_adds_only=recent_adds_only, order_by=order_by, search=search, ) response = client.get(url) assert response.status_code == http_status.HTTP_200_OK data = response.json assert data["count"] == response_dict["count"] assert data["items"] == response_dict["items"] @pytest.mark.parametrize( "isrc,recent_removals_only,markets,search,exclude_current_playlists,include,response_dict", ( ( "isrc11111111", False, None, None, False, [], { "count": 5, "items": [ { "removed_date": (date.today() - timedelta(days=1)).isoformat(), "country_code": "us", "id": "1ws2d", "image_url": "pl_artwork_1", "name": "pl one", "personalized": False, "track_id": 1, "updated_date": (date.today() - timedelta(days=6)).isoformat(), "added_date": (date.today() - timedelta(days=20)).isoformat(), }, { "removed_date": (date.today() - timedelta(days=3)).isoformat(), "country_code": "us", "id": "3asd3", "image_url": "pl_artwork_3", "name": "pl three", "personalized": False, "track_id": 1, "updated_date": (date.today() - timedelta(days=3)).isoformat(), "added_date": (date.today() - timedelta(days=12)).isoformat(), }, { "removed_date": (date.today() - timedelta(days=5)).isoformat(), "country_code": "au", "id": "1ws2d", "image_url": "pl_artwork_1", "name": "pl one", "personalized": False, "track_id": 3, "updated_date": (date.today() - timedelta(days=6)).isoformat(), "added_date": (date.today() - timedelta(days=20)).isoformat(), }, { "removed_date": (date.today() - timedelta(days=6)).isoformat(), "country_code": "us", "id": "2asf3", "image_url": "pl_artwork_2", "name": "pl two", "personalized": False, "track_id": 1, "updated_date": (date.today() - timedelta(days=5)).isoformat(), "added_date": (date.today() - timedelta(days=20)).isoformat(), }, { "removed_date": (date.today() - timedelta(days=12)).isoformat(), "country_code": "us", "id": "4asd4", "image_url": "pl_artwork_4", "name": "pl four", "personalized": False, "track_id": 1, "updated_date": (date.today() - timedelta(days=1)).isoformat(), "added_date": (date.today() - timedelta(days=20)).isoformat(), }, ], "next": None, "previous": None, }, ), ( "isrc11111111", True, None, None, True, [], { "count": 3, "items": [ { "removed_date": (date.today() - timedelta(days=1)).isoformat(), "country_code": "us", "id": "1ws2d", "image_url": "pl_artwork_1", "name": "pl one", "personalized": False, "track_id": 1, "updated_date": (date.today() - timedelta(days=6)).isoformat(), "added_date": (date.today() - timedelta(days=20)).isoformat(), }, { "removed_date": (date.today() - timedelta(days=3)).isoformat(), "country_code": "us", "id": "3asd3", "image_url": "pl_artwork_3", "name": "pl three", "personalized": False, "track_id": 1, "updated_date": (date.today() - timedelta(days=3)).isoformat(), "added_date": (date.today() - timedelta(days=12)).isoformat(), }, { "removed_date": (date.today() - timedelta(days=6)).isoformat(), "country_code": "us", "id": "2asf3", "image_url": "pl_artwork_2", "name": "pl two", "personalized": False, "track_id": 1, "updated_date": (date.today() - timedelta(days=5)).isoformat(), "added_date": (date.today() - timedelta(days=20)).isoformat(), }, ], "next": None, "previous": None, }, ), ( "isrc11111111", True, None, "three", True, [], { "count": 1, "items": [ { "removed_date": (date.today() - timedelta(days=3)).isoformat(), "country_code": "us", "id": "3asd3", "image_url": "pl_artwork_3", "name": "pl three", "personalized": False, "track_id": 1, "updated_date": (date.today() - timedelta(days=3)).isoformat(), "added_date": (date.today() - timedelta(days=12)).isoformat(), } ], "next": None, "previous": None, }, ), ( "isrc22222222", True, ["lv"], None, True, [], { "count": 1, "items": [ { "removed_date": (date.today() - timedelta(days=3)).isoformat(), "country_code": "lv", "id": "3asd3", "image_url": "pl_artwork_3", "name": "pl three", "personalized": False, "track_id": 2, "updated_date": (date.today() - timedelta(days=3)).isoformat(), "added_date": (date.today() - timedelta(days=12)).isoformat(), } ], "next": None, "previous": None, }, ), ( "isrc22222222", True, ["lv"], None, True, ["owner"], { "count": 1, "items": [ { "removed_date": (date.today() - timedelta(days=3)).isoformat(), "country_code": "lv", "id": "3asd3", "image_url": "pl_artwork_3", "name": "pl three", "category_id": 11, "track_id": 2, "updated_date": (date.today() - timedelta(days=3)).isoformat(), "category_name": "Apple Curators", "personalized": False, "added_date": (date.today() - timedelta(days=12)).isoformat(), } ], "next": None, "previous": None, }, ), ( "isrc11111111", False, None, None, True, [], { "count": 4, "items": [ { "removed_date": (date.today() - timedelta(days=1)).isoformat(), "country_code": "us", "id": "1ws2d", "image_url": "pl_artwork_1", "name": "pl one", "personalized": False, "track_id": 1, "updated_date": (date.today() - timedelta(days=6)).isoformat(), "added_date": (date.today() - timedelta(days=20)).isoformat(), }, { "removed_date": (date.today() - timedelta(days=3)).isoformat(), "country_code": "us", "id": "3asd3", "image_url": "pl_artwork_3", "name": "pl three", "personalized": False, "track_id": 1, "updated_date": (date.today() - timedelta(days=3)).isoformat(), "added_date": (date.today() - timedelta(days=12)).isoformat(), }, { "removed_date": (date.today() - timedelta(days=6)).isoformat(), "country_code": "us", "id": "2asf3", "image_url": "pl_artwork_2", "name": "pl two", "personalized": False, "track_id": 1, "updated_date": (date.today() - timedelta(days=5)).isoformat(), "added_date": (date.today() - timedelta(days=20)).isoformat(), }, { "removed_date": (date.today() - timedelta(days=12)).isoformat(), "country_code": "us", "id": "4asd4", "image_url": "pl_artwork_4", "name": "pl four", "personalized": False, "track_id": 1, "updated_date": (date.today() - timedelta(days=1)).isoformat(), "added_date": (date.today() - timedelta(days=20)).isoformat(), }, ], "next": None, "previous": None, }, ), ( "isrc11111111", False, ["gb"], None, True, [], { "count": 0, "items": [], "next": None, "previous": None, }, ), ( "isrc22222222", True, ["lv"], None, True, ["categories"], { "count": 1, "items": [ { "removed_date": (date.today() - timedelta(days=3)).isoformat(), "country_code": "lv", "id": "3asd3", "image_url": "pl_artwork_3", "name": "pl three", "category_id": 11, "track_id": 2, "updated_date": (date.today() - timedelta(days=3)).isoformat(), "category_name": "Apple Curators", "personalized": False, "added_date": (date.today() - timedelta(days=12)).isoformat(), } ], "next": None, "previous": None, "categories": [{"category_id": 11, "category_name": "Apple Curators"}], }, ), ), ) def test_previous_track_playlists_view_v1( db_session, user_id, client, patch_auth_user, isrc, recent_removals_only, markets, search, exclude_current_playlists, include, response_dict, ): patch_auth_user(user_id) today = date.today() date_1_day_ago = today - timedelta(days=1) date_3_days_ago = today - timedelta(days=3) date_5_days_ago = today - timedelta(days=5) date_6_days_ago = today - timedelta(days=6) date_12_days_ago = today - timedelta(days=12) date_20_days_ago = today - timedelta(days=20) track_1 = factories.AppleMusicSongFactory( id=1, name="track 1", isrc="isrc11111111", storefront="us", artwork_url="artwork1" ) track_2 = factories.AppleMusicSongFactory( id=2, name="track 2", isrc="isrc22222222", storefront="lv", artwork_url="artwork2" ) track_3 = factories.AppleMusicSongFactory( id=3, name="track 3", isrc="isrc11111111", storefront="au", artwork_url="artwork3" ) pl_1 = factories.ApplePlaylistFactory.create( id="1ws2d", name="pl one", artwork="pl_artwork_1", latest_update=date_6_days_ago ) pl_2 = factories.ApplePlaylistFactory.create( id="2asf3", name="pl two", artwork="pl_artwork_2", latest_update=date_5_days_ago ) pl_3 = factories.ApplePlaylistFactory.create( id="3asd3", name="pl three", artwork="pl_artwork_3", latest_update=date_3_days_ago, curator_id=111 ) pl_4 = factories.ApplePlaylistFactory.create( id="4asd4", name="pl four", artwork="pl_artwork_4", latest_update=date_1_day_ago ) factories.ApplePlaylistTrackListFactory.create( position=2, previous_position=10, playlist_id=pl_1.id, song_id=track_3.id, storefront="au", added_datetime=date_3_days_ago, added_earliest_datetime=date_3_days_ago, ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_1.id, storefront="us", song_id=track_1.id, date=date_1_day_ago.isoformat() ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_1.id, storefront="us", song_id=track_1.id, date=date_20_days_ago.isoformat() ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_2.id, storefront="us", song_id=track_1.id, date=date_6_days_ago.isoformat() ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_2.id, storefront="us", song_id=track_1.id, date=date_20_days_ago.isoformat() ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_3.id, storefront="us", song_id=track_1.id, date=date_3_days_ago.isoformat() ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_3.id, storefront="us", song_id=track_1.id, date=date_12_days_ago.isoformat() ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_4.id, storefront="us", song_id=track_1.id, date=date_12_days_ago.isoformat() ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_4.id, storefront="us", song_id=track_1.id, date=date_20_days_ago.isoformat() ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_1.id, storefront="us", song_id=track_2.id, date=date_1_day_ago.isoformat() ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_1.id, storefront="us", song_id=track_2.id, date=date_20_days_ago.isoformat() ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_2.id, storefront="us", song_id=track_2.id, date=date_6_days_ago.isoformat() ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_2.id, storefront="us", song_id=track_2.id, date=date_20_days_ago.isoformat() ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_3.id, storefront="lv", song_id=track_2.id, date=date_3_days_ago.isoformat() ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_3.id, storefront="lv", song_id=track_2.id, date=date_12_days_ago.isoformat() ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_4.id, storefront="us", song_id=track_2.id, date=date_12_days_ago.isoformat() ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_4.id, storefront="us", song_id=track_2.id, date=date_20_days_ago.isoformat() ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_1.id, storefront="au", song_id=track_3.id, date=date_5_days_ago.isoformat() ) factories.ApplePlaylistTracklistHistoryFactory.create( playlist_id=pl_1.id, storefront="au", song_id=track_3.id, date=date_20_days_ago.isoformat() ) factories.BuzzUserFactory.create( user_name="111", category_id=11, music_service=core.MusicServices.APPLEMUSIC, country_code="lv" ) factories.BuzzCategoryFactory.create(id=11, name="Apple Curators") url = url_for( "v1_apple_music_blueprint.track-previous-playlists-v1", isrc=isrc, recent_removals_only=recent_removals_only, market=markets, search=search, exclude_current_playlists=exclude_current_playlists, include=include, ) response = client.get(url) assert response.status_code == http_status.HTTP_200_OK data = response.json assert data["count"] == response_dict["count"] assert data["items"] == response_dict["items"] assert data.get("categories") == response_dict.get("categories", []) def get_date_iso(days: int or None) -> str or None: if not days: return None return (date.today() - timedelta(days=days)).isoformat() def get_playlist_item( playlist_index: int, track_index: int, added_days: int or None, change_days: int or None, updated_date: str, country_code: str, position: int, trend: int or None, is_new: bool = False, streams_7_days: int or None = None, track_count: int or None = None, user_name: str or None = None, category_id: int or None = None, ) -> dict: names = ("pl one", "pl two one", "pl three two", "pl four one") return { "id": f"pl.{playlist_index}", "name": names[playlist_index - 1], "track_id": track_index, "added_date": get_date_iso(added_days), "country_code": country_code, "current_position": position, "image_url": f"pl_artwork_{playlist_index}", "is_new": is_new, "position_change_date": get_date_iso(change_days), "trend": trend, "updated_date": updated_date, **({"track_count": track_count} if track_count is not None else {}), **({"username": user_name} if user_name is not None else {}), **({"playlist_streams": streams_7_days} if streams_7_days is not None else {}), **( { "category_name": {11: "Apple Curators"}.get(category_id), "category_id": category_id, } if category_id else {} ), } def get_playlist_result(*data, **kwargs) -> dict: return {"count": kwargs.get("count", len(data)), "items": list(data)} @pytest.mark.parametrize( "params,status,expected_result", ( ({}, HTTPStatus.BAD_REQUEST, None), ({"isrc": "isrc1", "order_by": "-playlist_streams"}, HTTPStatus.BAD_REQUEST, None), ( {"isrc": "isrc1", "order_by": "-playlist_streams", "limit": 1, "include": "playlist_streams"}, HTTPStatus.OK, get_playlist_result(get_playlist_item(4, 1, 6, 7, "2021-01-12", "us", 5, -2, streams_7_days=5290), count=3), ), ( {"isrc": "isrc1", "order_by": "playlist_streams", "limit": 1, "include": ["playlist_streams", "username"]}, HTTPStatus.OK, get_playlist_result( get_playlist_item(3, 1, 100, None, "2021-01-10", "us", 11, 0, streams_7_days=0, user_name="user2"), count=3, ), ), ( {"isrc": "isrc1", "recent_adds_only": True, "order_by": ["current_position"]}, HTTPStatus.OK, get_playlist_result( get_playlist_item(1, 1, 2, 7, "2021-01-10", "us", 3, -8), get_playlist_item(4, 1, 6, 7, "2021-01-12", "us", 5, -2), ), ), ( {"isrc": "isrc2", "order_by": ["-current_position"]}, HTTPStatus.OK, get_playlist_result( get_playlist_item(1, 2, 40, None, "2021-01-10", "us", 10, 0), get_playlist_item(2, 2, 2, 7, "2021-02-10", "us", 3, 0), get_playlist_item(4, 2, 6, 7, "2021-01-12", "us", 2, -9), ), ), ( {"isrc": "isrc1", "search": "one", "include": "all", "order_by": "id"}, HTTPStatus.OK, { "categories": [{"category_id": 11, "category_name": "Apple Curators"}], **get_playlist_result( get_playlist_item( 1, 1, 2, 7, "2021-01-10", "us", 3, -8, streams_7_days=4351, track_count=10, user_name="user1", category_id=11, ), get_playlist_item( 4, 1, 6, 7, "2021-01-12", "us", 5, -2, streams_7_days=5290, track_count=10, user_name="user3", category_id=11, ), ), }, ), ( {"isrc": "isrc2", "recent_adds_only": True, "order_by": ["-added_date"], "search": "one"}, HTTPStatus.OK, get_playlist_result( get_playlist_item(2, 2, 2, 7, "2021-02-10", "us", 3, 0), get_playlist_item(4, 2, 6, 7, "2021-01-12", "us", 2, -9), ), ), ( {"isrc": "isrc1", "recent_adds_only": True}, HTTPStatus.OK, get_playlist_result( get_playlist_item(4, 1, 6, 7, "2021-01-12", "us", 5, -2), get_playlist_item(1, 1, 2, 7, "2021-01-10", "us", 3, -8), ), ), ), ) def test_track_playlists_view_v2(params, status, expected_result, user_id, client, patch_auth_user, db_session): patch_auth_user(user_id) today, now = date.today(), datetime.now() change_dates = [now - timedelta(days=i) for i in (7, 18)] added_dates = [today - timedelta(days=i) for i in (2, 6, 100, 40)] curators = [factories.AppleMusicCuratorFactory.create(id=i, name=f"user{i}") for i in range(1, 5)] playlists = [ factories.ApplePlaylistFactory.create( id=f"pl.{i + 1}", name=d[0] if i != 3 else None, latest_update=d[1], artwork=f"pl_artwork_{i + 1}" if i != 3 else None, curator_id=curators[d[2]].id, ) for i, d in enumerate( ( ("pl one", date(2021, 1, 10), 0), ("pl two one", date(2021, 2, 10), 1), ("pl three two", date(2021, 1, 10), 1), ("pl four one", date(2021, 1, 12), 2), ) ) ] [ factories.AppleMusicContainerStreamSummaryFactory.create( container_id=playlists[d[0]].id, country_code="us", streams_7_days=d[1] ) for d in ((0, 4351), (1, 74441), (3, 5290)) ] songs = [ factories.AppleMusicSongFactory.create( id=i, name=f"song{i}", storefront="us", isrc=f"isrc{i}", artwork_url=f"artwork{i}" ) for i in range(1, 3) ] [ factories.ApplePlaylistTrackListFactory.create( position=data[0], previous_position=data[1], playlist_id=playlists[data[2]].id, song_id=songs[data[3]].id, storefront="us", latest_position_change=change_dates[data[4]], added_datetime=added_dates[data[5]], added_earliest_datetime=added_dates[data[5]], ) for data in ( (2, 10, 0, 0, 0, 0), (10, 10, 2, 0, 1, 2), (4, 6, 3, 0, 0, 1), (9, 9, 0, 1, 1, 3), (2, 2, 1, 1, 0, 0), (1, 10, 3, 1, 0, 1), ) ] factories.BuzzCategoryFactory.create(id=11, name="Apple Curators") [ factories.BuzzUserFactory.create( id=i, user_name=str(i), country_code="us", music_service=core.MusicServices.APPLEMUSIC, category_id=11 ) for i in range(1, 5) ] factories.ApplePlaylistStorefrontDataFactory.create( playlist_id="pl.4", storefront="us", name="pl four one", artwork="pl_artwork_4" ) url = url_for("v2_apple_music_blueprint.track-playlists-v2", **params) response = client.get(url) assert response.status_code == status if status == HTTPStatus.OK: data = response.json assert data["count"] == expected_result["count"] assert data["items"] == expected_result["items"] assert data.get("categories") == expected_result.get("categories", [])