from unittest.mock import MagicMock import pytest import requests_mock from apollo_notifications.constants import APPLE_CATEGORY_ID, SONY_CATEGORY_ID from apollo_notifications.push_client import PushClient from tests.helpers import * from apollo_main_db.push_notifications.models import PushMessage, PushMessageReduced from client import SpotifyPlaylistClient from config import config from index import _job, process_starred_playlists_entries_by_market, process_top_playlists_entries_by_market from logger import logger def mock_user_data_requests(requests_mocker): mocked_feed = requests_mocker.register_uri( "POST", "https://test/api/service/messages/feed/", json={"status": "OK"} ) mocked_push = requests_mocker.register_uri( "POST", "https://test/api/service/messages/push/", json={"status": "OK"} ) return mocked_feed, mocked_push def test_get_added_tracks_for_existing_playlist(db_session): """Here we have 2 TOP playlists for today, get_added_tracks should return only new tracks for each playlist, which is added today and wasn't yesterday """ market = "us" today, yesterday = get_formatted_today_yesterday() create_basic_structures( playlists_n=3, tracks_n=3, users_n=1, category_id_to_playlists_map={SONY_CATEGORY_ID: [1], SPOTIFY_CATEGORY_ID: [2], APPLE_CATEGORY_ID: [3]}, previous_top_playlists=range(1, 4), playlist_to_last_and_previous_tracks_map={1: ([1, 2], [2]), 2: ([1, 3], [1]), 3: ([1], None)}, starred_tracks=range(1, 4), market=market, ) notifications_client = SpotifyPlaylistClient(config) top_playlist_ids_for_today = notifications_client.get_top_playlists_by_date_query(market, today) top_playlist_ids_for_yesterday = notifications_client.get_top_playlists_by_date_query(market, yesterday) added_tracks = notifications_client.get_added_tracks_query( today, yesterday, top_playlist_ids_for_today, top_playlist_ids_for_yesterday ).all() result = [ ( i.playlist_id, i.track_id, ) for i in added_tracks ] assert ("playlist_id_1", "track_id_1") in result assert ("playlist_id_2", "track_id_3") in result assert ("playlist_id_3", "track_id_1") not in result def test_added_tracks_for_new_playlist(db_session): """Here we have 1 NEW TOP playlist for today, get_added_tracks should return tracks only for new playlist, even though tracks were in that playlist yesterday. """ market = "us" today, yesterday = get_formatted_today_yesterday() create_basic_structures( playlists_n=2, tracks_n=3, users_n=1, category_id_to_playlists_map={SONY_CATEGORY_ID: [1], SPOTIFY_CATEGORY_ID: [2]}, last_top_playlists=[1], previous_top_playlists=[2], playlist_to_last_and_previous_tracks_map={1: ([1, 2], [2]), 2: ([3], None)}, starred_tracks=range(1, 4), market=market, ) notifications_client = SpotifyPlaylistClient(config) top_playlist_ids_for_today = notifications_client.get_top_playlists_by_date_query(market, today) top_playlist_ids_for_yesterday = notifications_client.get_top_playlists_by_date_query(market, yesterday) added_tracks = notifications_client.get_added_tracks_query( today, yesterday, top_playlist_ids_for_today, top_playlist_ids_for_yesterday ).all() result = [ ( i.playlist_id, i.track_id, ) for i in added_tracks ] assert ("playlist_id_1", "track_id_1") in result assert ("playlist_id_1", "track_id_2") in result assert ("playlist_id_2", "track_id_3") not in result @pytest.mark.parametrize("market", ("us", None)) @requests_mock.Mocker(kw="requests_mocker") def test_process_starred_playlists_entries_by_market(db_session, mocked_sqs, market, **kwargs): mock_user_data_requests(**kwargs) today, yesterday = get_formatted_today_yesterday() create_basic_structures( playlists_n=4, tracks_n=4, users_n=2, playlist_to_last_and_previous_tracks_map={ 1: ([1, 2], None), 2: ([3, 4], None), 3: ([1, 4], None), 4: ([1, 2, 3, 4], None), }, starred_tracks=range(1, 5), market=market, ) # create existing messages existing_messages = { str( get_track_in_playlist_push_key( today, playlist_id(3), user_id(2), config.STARRED_PLAYLIST_ADDITION_TOPIC, market, config.VENDOR, track_isrc(1), ) ) } # run it push_client = PushClient(logger=logger, sqs_client=mocked_sqs, config=config, db_session=db_session) notifications_client = SpotifyPlaylistClient(config) process_starred_playlists_entries_by_market( count=1, market=market, today=today, yesterday=yesterday, include_playlist_id_list=[playlist_id(1), playlist_id(2), playlist_id(3)], user_id_list=[user_id(1), user_id(2)], include_playlist_to_users_map={ playlist_id(1): {user_id(1)}, playlist_id(2): {user_id(1)}, playlist_id(3): {user_id(2)}, playlist_id(4): {user_id(1), user_id(2)}, }, existing_messages=existing_messages, notifications_client=notifications_client, push_client=push_client, ) # test it expected_push_list = [ create_push_message_data( playlist_idx=playlist_track_user[0], track_idx=playlist_track_user[1], user_idx=playlist_track_user[2], topic=config.STARRED_PLAYLIST_ADDITION_TOPIC, country_code=market, title=config.STARRED_PLAYLIST_ADDITION_TITLE, date=today, add_playlist_image=True, ) for playlist_track_user in [ (1, 1, 1), (1, 2, 1), (2, 3, 1), (2, 4, 1), (3, 4, 2), ] ] expected_push_id_to_data_map = {p.pop("id"): p for p in expected_push_list} push_messages = db_session.query(PushMessage).all() push_messages_reduced = db_session.query(PushMessageReduced).all() verify_push_messages(expected_push_id_to_data_map, push_messages) verify_push_messages(expected_push_id_to_data_map, push_messages_reduced) @requests_mock.Mocker(kw="requests_mocker") def test_process_top_playlists_entries_by_market(db_session, mocked_sqs, **kwargs): mock_user_data_requests(**kwargs) market = "us" today, yesterday = get_formatted_today_yesterday() create_basic_structures( playlists_n=4, tracks_n=4, users_n=2, playlist_to_last_and_previous_tracks_map={ 1: ([1, 2], None), 2: ([3, 4], None), 3: ([1, 4], None), 4: ([1, 2, 3, 4], None), }, last_top_playlists=range(1, 5), blacklisted_playlists=[4], starred_tracks=range(1, 5), market=market, ) # create existing messages existing_messages = { str( get_track_in_playlist_push_key( today, playlist_id(3), user_id(2), config.TOPIC, market, config.VENDOR, track_isrc(1) ) ) } # run it push_client = PushClient(logger=logger, sqs_client=mocked_sqs, config=config, db_session=db_session) notifications_client = SpotifyPlaylistClient(config) process_top_playlists_entries_by_market( count=1, market=market, today=today, yesterday=yesterday, excluded_playlist_id_list=[playlist_id(4)], user_id_list=[user_id(1), user_id(2)], exclude_playlist_to_users_map={playlist_id(1): {user_id(2)}, playlist_id(2): {user_id(1)}}, existing_messages=existing_messages, notifications_client=notifications_client, push_client=push_client, ) # test it expected_push_list = [ create_push_message_data( playlist_idx=playlist_track_user[0], track_idx=playlist_track_user[1], user_idx=playlist_track_user[2], topic=config.TOPIC, country_code=market, title=config.TITLE, date=today, ) for playlist_track_user in [ (1, 1, 1), (1, 2, 1), (2, 3, 2), (2, 4, 2), (3, 1, 1), (3, 4, 1), (3, 4, 2), ] ] expected_push_id_to_data_map = {p.pop("id"): p for p in expected_push_list} push_messages = db_session.query(PushMessage).all() push_messages_reduced = db_session.query(PushMessageReduced).all() verify_push_messages(expected_push_id_to_data_map, push_messages) verify_push_messages(expected_push_id_to_data_map, push_messages_reduced) @requests_mock.Mocker(kw="requests_mocker") def test_job(db_session, mocked_sqs, **kwargs): mock_user_data_requests(**kwargs) market_us, market_gb, market_null = "us", "gb", None today, yesterday = get_formatted_today_yesterday() today_date = datetime.datetime.fromisoformat(today).date() # mock user_data client user_data_mock = MagicMock() user_data_mock.parse_v1_mobile_settings.return_value = ( {market_us: {user_id(1), user_id(2)}, market_gb: {user_id(3)}}, {user_id(1): account_id(1), user_id(2): account_id(2), user_id(3): account_id(3)}, ) user_data_mock.parse_starred_playlists.return_value = ( { playlist_id(1): {user_id(1), user_id(2)}, playlist_id(2): {user_id(2), user_id(3)}, playlist_id(4): {user_id(1), user_id(2), user_id(3)}, playlist_id(5): {user_id(1)}, }, {playlist_id(1), playlist_id(2), playlist_id(4), playlist_id(5)}, ) # create db data for us market create_basic_structures( playlists_n=5, tracks_n=4, users_n=3, playlist_to_last_and_previous_tracks_map={ 1: ([1, 2], [1]), 2: ([3, 4], None), 3: ([1, 4], [3, 4]), 4: ([1, 2, 3, 4], None), 5: ([1, 2], None), }, last_top_playlists=(2, 3, 4), previous_top_playlists=(1, 3), blacklisted_playlists=(4,), starred_tracks=range(1, 5), market_to_playlists_map={market_us: range(1, 5), market_null: (5,)}, ) # create existing push messages existing = [ factories.PushMessageReducedFactory.create( id=get_track_in_playlist_push_key( today, playlist_id(3), user_id(2), config.TOPIC, market_us, config.VENDOR, track_isrc(1) ), inner_id=1000, topic=TopicEnum.PLAYLIST_ADDITIONS, vendor=VendorEnum.SPOTIFY, date=today_date, ), factories.PushMessageReducedFactory.create( id=get_track_in_playlist_push_key( today, playlist_id(2), user_id(2), config.STARRED_PLAYLIST_ADDITION_TOPIC, market_us, config.VENDOR, track_isrc(3), ), inner_id=1001, topic=TopicEnum.STARRED_PLAYLIST_ADDITIONS, vendor=VendorEnum.SPOTIFY, date=today_date, ), factories.PushMessageReducedFactory.create( id=get_track_in_playlist_push_key( today, playlist_id(2), user_id(3), config.TOPIC, market_us, config.VENDOR, track_isrc(3) ), inner_id=1002, topic=TopicEnum.STARRED_PLAYLIST_ADDITIONS, vendor=VendorEnum.SPOTIFY, date=today_date, ), factories.PushMessageReducedFactory.create( id=get_track_in_playlist_push_key( today, playlist_id(5), user_id(1), config.STARRED_PLAYLIST_ADDITION_TOPIC, market_null, config.VENDOR, track_isrc(2), ), inner_id=1003, topic=TopicEnum.STARRED_PLAYLIST_ADDITIONS, vendor=VendorEnum.SPOTIFY, date=today_date, ), ] db_session.commit() # run it push_client = PushClient(logger=logger, sqs_client=mocked_sqs, config=config, db_session=db_session) notifications_client = SpotifyPlaylistClient(config) _job( notifications_client=notifications_client, push_client=push_client, user_data_client=user_data_mock, blacklist_cache=lambda f: f, ) # test it expected_top_playlists_push_list = [ create_push_message_data( playlist_idx=playlist_track_user[0], track_idx=playlist_track_user[1], user_idx=playlist_track_user[2], topic=config.TOPIC, country_code=market_us, title=config.TITLE, date=today, ) for playlist_track_user in [ (2, 3, 1), (2, 4, 1), (3, 1, 1), ] ] expected_us_starred_playlists_push_list = [ create_push_message_data( playlist_idx=playlist_track_user[0], track_idx=playlist_track_user[1], user_idx=playlist_track_user[2], topic=config.STARRED_PLAYLIST_ADDITION_TOPIC, country_code=market_us, title=config.STARRED_PLAYLIST_ADDITION_TITLE, date=today, add_playlist_image=True, ) for playlist_track_user in [ (1, 2, 1), (1, 2, 2), (2, 4, 2), (2, 4, 3), ] ] expected_null_starred_playlists_push_list = [ create_push_message_data( playlist_idx=playlist_track_user[0], track_idx=playlist_track_user[1], user_idx=playlist_track_user[2], topic=config.STARRED_PLAYLIST_ADDITION_TOPIC, country_code=market_null, title=config.STARRED_PLAYLIST_ADDITION_TITLE, date=today, add_playlist_image=True, ) for playlist_track_user in [ (5, 1, 1), ] ] expected_push_list = ( expected_top_playlists_push_list + expected_us_starred_playlists_push_list + expected_null_starred_playlists_push_list ) expected_push_id_to_data_map = {p.pop("id"): p for p in expected_push_list} push_messages = db_session.query(PushMessage).all() created_push_messages_reduced = ( db_session.query(PushMessageReduced) .filter(PushMessageReduced.inner_id.notin_([p.inner_id for p in existing])) .all() ) verify_push_messages(expected_push_id_to_data_map, push_messages) verify_push_messages(expected_push_id_to_data_map, created_push_messages_reduced)