from unittest import mock import pytest from dirty_equals import IsList from freezegun import freeze_time from dmp.adapters.meta.exceptions import FacebookClientError from dmp.adapters.meta.models import DebugToken, User, UserAdAccount from dmp.config import Settings from dmp.meta.dtos import MetaUserConnectionAdAccount, MetaUserConnectionResult from dmp.meta.enums import MetaUserConnectionStatus from dmp.meta.handlers import GetMetaUserConnectionHandler, GetMetaUserConnectionRequest from dmp.meta.models import MetaAdAccount, MetaUserConnection from tests.unit.types import BuildModel, CreateModel class TestGetMetaUserConnectionHandler: @freeze_time("2022-07-20") @pytest.mark.db def test_get_user_connection( self, handler: GetMetaUserConnectionHandler, facebook_client_mock: mock.MagicMock, build_model: BuildModel, create_model: CreateModel, settings: Settings, ) -> None: custom_audience_tos_accepted = True api_user = build_model(User) ad_account = create_model(MetaAdAccount) ad_account.user_custom_audience_tos_accepted = custom_audience_tos_accepted user_connection = create_model( MetaUserConnection, is_valid=True, user_id=api_user.id, user_name=api_user.name, ad_accounts=[ad_account], ) facebook_client_mock.debug_token.return_value = DebugToken( is_valid=True, scopes=settings.meta_user_required_scopes ) facebook_client_mock.get_user.return_value = api_user user_connection_result = handler.handle( GetMetaUserConnectionRequest(identity_id=user_connection.identity_id), ) assert user_connection.is_valid assert user_connection_result.user assert user_connection_result.user.id == user_connection.user_id assert user_connection_result.user.name == user_connection.user_name assert user_connection_result.status == MetaUserConnectionStatus.CONNECTED assert user_connection_result.ad_accounts == [ MetaUserConnectionAdAccount( id=ad_account.id, external_id=ad_account.external_id, name=ad_account.name or ad_account.external_id, business_account_name=ad_account.business_account_name, business_account_picture=ad_account.business_account_picture, custom_audience_tos_accepted=custom_audience_tos_accepted, ) ] @freeze_time("2022-07-20") @pytest.mark.db def test_get_user_connection_refreshed_tos( self, handler: GetMetaUserConnectionHandler, facebook_client_mock: mock.MagicMock, build_model: BuildModel, create_model: CreateModel, settings: Settings, ) -> None: api_user = build_model(User) api_ad_account_1 = build_model( UserAdAccount, tos_accepted={"custom_audience_tos": 1} ) api_ad_account_2 = build_model( UserAdAccount, tos_accepted={"custom_audience_tos": 1} ) ad_account_1 = create_model(MetaAdAccount, external_id=api_ad_account_1.id) ad_account_1.user_custom_audience_tos_accepted = False ad_account_2 = create_model(MetaAdAccount, external_id=api_ad_account_2.id) ad_account_2.user_custom_audience_tos_accepted = False user_connection = create_model( MetaUserConnection, is_valid=True, user_id=api_user.id, user_name=api_user.name, ad_accounts=[ad_account_1, ad_account_2], ) facebook_client_mock.debug_token.return_value = DebugToken( is_valid=True, scopes=settings.meta_user_required_scopes ) facebook_client_mock.get_user.return_value = api_user facebook_client_mock.get_user_ad_accounts.return_value = [ api_ad_account_1, api_ad_account_2, ] user_connection_result = handler.handle( GetMetaUserConnectionRequest(identity_id=user_connection.identity_id), ) assert user_connection.is_valid assert user_connection_result.user assert user_connection_result.user.id == user_connection.user_id assert user_connection_result.user.name == user_connection.user_name assert user_connection_result.status == MetaUserConnectionStatus.CONNECTED assert user_connection_result.ad_accounts == IsList( MetaUserConnectionAdAccount( id=ad_account_1.id, external_id=ad_account_1.external_id, name=ad_account_1.name or ad_account_1.external_id, business_account_name=ad_account_1.business_account_name, business_account_picture=ad_account_1.business_account_picture, custom_audience_tos_accepted=api_ad_account_1.custom_audience_tos_accepted, ), MetaUserConnectionAdAccount( id=ad_account_2.id, external_id=ad_account_2.external_id, name=ad_account_2.name or ad_account_1.external_id, business_account_name=ad_account_2.business_account_name, business_account_picture=ad_account_2.business_account_picture, custom_audience_tos_accepted=api_ad_account_2.custom_audience_tos_accepted, ), check_order=False, ) def test_get_user_connection_no_connection_found( self, handler: GetMetaUserConnectionHandler, identity_id: str, settings: Settings, ) -> None: user_connection_result = handler.handle( GetMetaUserConnectionRequest(identity_id=identity_id) ) assert user_connection_result == MetaUserConnectionResult( user=None, status=MetaUserConnectionStatus.NOT_CONNECTED, required_scopes=settings.meta_user_required_scopes, ad_accounts=[], ) @pytest.mark.db def test_get_user_connection_invalid( self, handler: GetMetaUserConnectionHandler, create_model: CreateModel ) -> None: user_connection = create_model(MetaUserConnection, is_valid=False) user_connection_result = handler.handle( GetMetaUserConnectionRequest(identity_id=user_connection.identity_id), ) assert user_connection_result.status == MetaUserConnectionStatus.INVALID assert user_connection_result.ad_accounts == [] @pytest.mark.db def test_get_user_connection_debug_token_invalid( self, handler: GetMetaUserConnectionHandler, facebook_client_mock: mock.MagicMock, create_model: CreateModel, settings: Settings, ) -> None: user_connection = create_model(MetaUserConnection, is_valid=True) facebook_client_mock.debug_token.return_value = DebugToken( is_valid=False, scopes=settings.meta_user_required_scopes ) user_connection_result = handler.handle( GetMetaUserConnectionRequest(identity_id=user_connection.identity_id), ) assert not user_connection.is_valid assert user_connection_result.user assert user_connection_result.user.id == user_connection.user_id assert user_connection_result.user.name == user_connection.user_name assert user_connection_result.user.picture == user_connection.user_picture assert user_connection_result.user.granted_scopes == [] assert user_connection_result.status == MetaUserConnectionStatus.INVALID assert user_connection_result.ad_accounts == [] @pytest.mark.db def test_get_user_connection_token_valid_user_id_not_valid( self, handler: GetMetaUserConnectionHandler, facebook_client_mock: mock.MagicMock, build_model: BuildModel, create_model: CreateModel, settings: Settings, ) -> None: api_user = build_model(User) user_connection = create_model( MetaUserConnection, is_valid=True, user_id=api_user.id, user_name=api_user.name, ) facebook_client_mock.debug_token.return_value = DebugToken( is_valid=True, scopes=settings.meta_user_required_scopes ) facebook_client_mock.get_user.side_effect = FacebookClientError() user_connection_result = handler.handle( GetMetaUserConnectionRequest(identity_id=user_connection.identity_id), ) assert not user_connection.is_valid assert user_connection_result.status == MetaUserConnectionStatus.INVALID @pytest.mark.db def test_get_user_connection_scope_missing( self, handler: GetMetaUserConnectionHandler, facebook_client_mock: mock.MagicMock, build_model: BuildModel, create_model: CreateModel, settings: Settings, ) -> None: api_user = build_model(User) granted_scopes = list(set(settings.meta_user_required_scopes) - {"email"}) user_connection = create_model( MetaUserConnection, is_valid=True, user_id=api_user.id, user_name=api_user.name, ) facebook_client_mock.debug_token.return_value = DebugToken( is_valid=True, scopes=granted_scopes ) facebook_client_mock.get_user.return_value = api_user user_connection_result = handler.handle( GetMetaUserConnectionRequest(identity_id=user_connection.identity_id), ) assert not user_connection.is_valid assert user_connection_result.user assert user_connection_result.user.id == user_connection.user_id assert user_connection_result.user.name == user_connection.user_name assert user_connection_result.user.picture == api_user.picture.data.url assert user_connection_result.user.granted_scopes == granted_scopes assert user_connection_result.status == MetaUserConnectionStatus.SCOPES_MISSING assert user_connection_result.ad_accounts == []