from unittest.mock import MagicMock import pytest import requests_mock from apollo_notifications.constants import SONY_CATEGORY_ID, SPOTIFY_CATEGORY_ID from apollo_notifications.push_client.client import PushClient from tests.helpers import * from apollo_main_db.push_notifications.models import PushMessage, PushMessageReduced from client import ApplePlaylistClient 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 get_formatted_today_yesterday(): today = datetime.date.today() yesterday = today - datetime.timedelta(days=1) return today.strftime("%Y-%m-%d"), yesterday.strftime("%Y-%m-%d") def test_get_added_tracks(db_session, mocked_sqs, redis_client): """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=4, tracks_n=3, users_n=1, market_to_tracks={market: list(range(1, 4))}, category_id_to_playlists_map={SONY_CATEGORY_ID: [1], SPOTIFY_CATEGORY_ID: [3, 4], APPLE_CATEGORY_ID: [2]}, previous_top_playlists={market: (1, 3, 4)}, playlist_to_last_and_previous_tracks_map={ 1: ({market: [1, 2, 3]}, {market: [3]}), 2: ({market: [1, 3]}, {market: [1]}), 3: ({market: [1]}, {market: [1]}), 4: ({market: [1]}, None), }, starred_tracks=range(1, 4), ) notifications_client = ApplePlaylistClient(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, market, [user_id(1)] ).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(4), track_id(1)) in result # we do not filter by category_id at this step assert (playlist_id(2), track_id(3)) not in result assert (playlist_id(3), track_id(1)) not in result @pytest.mark.parametrize( "market,result", ( ("us", [(1, 1, 1)]), ("global", [(1, 1, 1)]), ("ca", [(4, 5, 1)]), ("gb", []), ), ) @requests_mock.Mocker(kw="requests_mocker") def test_process_top_playlists_entries_by_market(db_session, mocked_sqs, redis_client, market, result, **kwargs): mock_user_data_requests(**kwargs) today, yesterday = get_formatted_today_yesterday() us_market, ca_market, gb_market, global_market = "us", "ca", "gb", "global" create_basic_structures( playlists_n=4, tracks_n=6, users_n=1, market_to_tracks={us_market: (1, 2, 3), ca_market: (4, 5, 6)}, previous_top_playlists={global_market: (1, 2, 3), us_market: (1, 2, 3), ca_market: (4,)}, playlist_to_last_and_previous_tracks_map={ 1: ({us_market: (1, 2, 3), gb_market: (1, 2, 3)}, None), 2: ({us_market: (1, 2, 3), gb_market: (1, 2, 3)}, None), 3: ({us_market: (1, 2, 3), gb_market: (1, 2, 3)}, None), 4: ({us_market: (4, 5, 6), ca_market: (4, 5, 6)}, None), }, blacklisted_playlists=(3,), starred_tracks=(1, 4, 5), ) # create existing messages existing_messages = { str( get_track_in_playlist_push_key( today, playlist_id(4), user_id(1), config.TOPIC, ca_market, config.VENDOR, track_isrc(4) ) ) } push_client = PushClient(logger=logger, sqs_client=mocked_sqs, config=config, db_session=db_session) notifications_client = ApplePlaylistClient(config) process_top_playlists_entries_by_market( count=1, market=market, today=today, yesterday=yesterday, excluded_playlist_id_list=[playlist_id(3)], 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 result ] 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) @pytest.mark.parametrize( "market,result", ( ("us", [(1, 1, 1)]), ("ca", [(4, 5, 1)]), ("gb", []), ), ) @requests_mock.Mocker(kw="requests_mocker") def test_process_starred_playlists_entries_by_market(db_session, mocked_sqs, redis_client, market, result, **kwargs): mock_user_data_requests(**kwargs) today, yesterday = get_formatted_today_yesterday() us_market, ca_market, gb_market = "us", "ca", "gb" create_basic_structures( playlists_n=4, tracks_n=6, users_n=1, market_to_tracks={us_market: (1, 2, 3), ca_market: (4, 5, 6)}, playlist_to_last_and_previous_tracks_map={ 1: ({us_market: (1, 2, 3), gb_market: (1, 2, 3)}, None), 2: ({us_market: (1, 2, 3), gb_market: (1, 2, 3)}, None), 3: ({us_market: (1, 2, 3), gb_market: (1, 2, 3)}, None), 4: ({us_market: (4, 5, 6), ca_market: (4, 5, 6)}, None), }, blacklisted_playlists=(3,), starred_tracks=(1, 2, 4, 5), ) market_to_starred_playlists_to_users_map = { us_market: { playlist_id(1): {user_id(1), user_id(2)}, }, gb_market: {playlist_id(1): {user_id(1), user_id(2)}, playlist_id(4): {user_id(1)}}, ca_market: {playlist_id(2): {user_id(1), user_id(2)}, playlist_id(4): {user_id(1)}}, } # create existing messages existing_messages = { str( get_track_in_playlist_push_key( today, playlist_id(4), user_id(1), config.STARRED_PLAYLIST_ADDITION_TOPIC, ca_market, config.VENDOR, track_isrc(4), ) ), str( get_track_in_playlist_push_key( today, playlist_id(1), user_id(1), config.TOPIC, us_market, config.VENDOR, track_isrc(2) ) ), } # run it push_client = PushClient(logger=logger, sqs_client=mocked_sqs, config=config, db_session=db_session) notifications_client = ApplePlaylistClient(config) process_starred_playlists_entries_by_market( count=1, market=market, today=today, yesterday=yesterday, include_playlist_id_list=market_to_starred_playlists_to_users_map[market].keys(), user_id_list=[user_id(1), user_id(2)], include_playlist_to_users_map=market_to_starred_playlists_to_users_map[market], 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 result ] 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) today, yesterday = get_formatted_today_yesterday() today_date = datetime.datetime.fromisoformat(today).date() us_market, ca_market, gb_market, global_market = "us", "ca", "gb", "global" # mock user_data client user_data_mock = MagicMock() user_data_mock.parse_v1_mobile_settings.return_value = ( { us_market: {user_id(1), user_id(3)}, gb_market: {user_id(1), user_id(2), user_id(3)}, global_market: {user_id(2)}, ca_market: {user_id(1)}, }, {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 = ( { us_market: { playlist_id(1): {user_id(1)}, playlist_id(3): {user_id(1)}, playlist_id(4): {user_id(1), user_id(3)}, }, gb_market: {playlist_id(2): {user_id(1), user_id(2)}}, ca_market: {playlist_id(4): {user_id(1), user_id(3)}}, }, {playlist_id(1), playlist_id(2), playlist_id(3), playlist_id(4)}, ) create_basic_structures( playlists_n=4, tracks_n=6, users_n=3, market_to_tracks={us_market: (1, 2, 3), ca_market: (4, 5, 6)}, previous_top_playlists={us_market: (1, 2, 3), global_market: (1, 2, 3)}, playlist_to_last_and_previous_tracks_map={ 1: ({us_market: (1, 2, 3), gb_market: (1, 2, 3)}, {us_market: (2,)}), 2: ({us_market: (1, 2, 3), gb_market: (1, 2, 3)}, None), 3: ({us_market: (1, 2, 3), gb_market: (1, 2, 3)}, None), 4: ({us_market: (4, 5, 6), ca_market: (4, 5, 6)}, None), }, blacklisted_playlists=(3,), starred_tracks=(1, 2, 4, 5), ) # create existing push messages existing = [ factories.PushMessageReducedFactory.create( id=get_track_in_playlist_push_key( today, playlist_id(4), user_id(1), config.STARRED_PLAYLIST_ADDITION_TOPIC, ca_market, config.VENDOR, track_isrc(4), ), inner_id=1000, topic=TopicEnum.STARRED_PLAYLIST_ADDITIONS, vendor=VendorEnum.APPLE, date=today_date, ), factories.PushMessageReducedFactory.create( id=get_track_in_playlist_push_key( today, playlist_id(4), user_id(3), config.TOPIC, ca_market, config.VENDOR, track_isrc(4) ), inner_id=1001, topic=TopicEnum.PLAYLIST_ADDITIONS, vendor=VendorEnum.APPLE, date=today_date, ), factories.PushMessageReducedFactory.create( id=get_track_in_playlist_push_key( today, playlist_id(2), user_id(1), config.TOPIC, us_market, config.VENDOR, track_isrc(2) ), inner_id=1002, topic=TopicEnum.PLAYLIST_ADDITIONS, vendor=VendorEnum.APPLE, 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 = ApplePlaylistClient(config) _job( notifications_client=notifications_client, push_client=push_client, user_data_client=user_data_mock, blacklist_cache=lambda f: f, ) # test it expected_us_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=us_market, title=config.TITLE, date=today, ) for playlist_track_user in [(1, 1, 3), (2, 1, 1), (2, 1, 3), (2, 2, 3)] ] expected_global_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=global_market, title=config.TITLE, date=today, ) for playlist_track_user in [ (1, 1, 2), (2, 1, 2), (2, 2, 2), ] ] 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=us_market, title=config.STARRED_PLAYLIST_ADDITION_TITLE, date=today, add_playlist_image=True, ) for playlist_track_user in [ (1, 1, 1), ] ] expected_ca_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=ca_market, title=config.STARRED_PLAYLIST_ADDITION_TITLE, date=today, add_playlist_image=True, ) for playlist_track_user in [(4, 5, 1), (4, 5, 3)] ] expected_push_list = ( expected_us_top_playlists_push_list + expected_global_top_playlists_push_list + expected_us_starred_playlists_push_list + expected_ca_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)