from unittest import mock import pytest from anydi import Container from dirty_equals import IsPartialDataclass import dmp.google.models as models from dmp.adapters.google import GoogleClientError, User from dmp.adapters.google.models import AccessToken from dmp.config import Settings from dmp.google.dtos import GoogleUserConnectionAdAccount, GoogleUserConnectionResponse from dmp.google.enums import GoogleUserConnectionStatus from dmp.google.handlers.get_user_connection import ( GetGoogleUserConnectionHandler, GetGoogleUserConnectionRequest, ) from dmp.google.models import GoogleAdAccount, GoogleUserConnection from dmp.google.repositories import GoogleUserConnectionRepository from dmp.google.services import GoogleAdAccountService from tests.unit.faker import FakerTyped from tests.unit.types import BuildModel, CreateModel class TestGetGoogleUserConnectionHandler: @pytest.mark.db def test_get_user_connection_lost_ad_account( self, handler: GetGoogleUserConnectionHandler, google_client_mock: mock.MagicMock, ad_account_service_mock: mock.MagicMock, user_connection_repository: GoogleUserConnectionRepository, build_model: BuildModel, create_model: CreateModel, settings: Settings, identity_id: str, ) -> None: user = build_model(User) access_token = build_model( AccessToken, scope=" ".join(settings.google_user_required_scopes) ) ad_account = build_model(GoogleAdAccount) user_connection = create_model( GoogleUserConnection, is_valid=True, user_id=user.id, user_name=user.name, connection_ad_accounts=[ models.GoogleUserConnectionAdAccount(ad_account=ad_account), ], identity_id=identity_id, ) google_client_mock.get_user.return_value = user google_client_mock.get_access_token.return_value = access_token google_client_mock.get_access_token.return_value = access_token ad_account_service_mock.get_ad_accounts_for_user_connection.return_value = [] user_connection_response = handler.handle( GetGoogleUserConnectionRequest( identity_id=user_connection.identity_id, user_id=user_connection.user_id, ), ) assert user_connection.is_valid assert user_connection_response.user assert user_connection_response.user.id == user_connection.user_id assert user_connection_response.user.name == user_connection.user_name assert ( user_connection_response.user.granted_scopes == settings.google_user_required_scopes ) assert user_connection_response.status == GoogleUserConnectionStatus.CONNECTED assert user_connection_response.ad_accounts == [] assert user_connection_response.ad_accounts_count == 0 db_user_connection = user_connection_repository.get_by_identity_id_and_user_id( identity_id=identity_id, user_id=user.id ) assert db_user_connection assert db_user_connection.connection_ad_accounts == [] @pytest.mark.db def test_get_user_connection_new_ad_account( self, container: Container, handler: GetGoogleUserConnectionHandler, google_client_mock: mock.MagicMock, ad_account_service_mock: mock.MagicMock, user_connection_repository: GoogleUserConnectionRepository, build_model: BuildModel, create_model: CreateModel, settings: Settings, identity_id: str, ) -> None: user = build_model(User) access_token = build_model( AccessToken, scope=" ".join(settings.google_user_required_scopes) ) ad_account = build_model(GoogleAdAccount) user_connection = create_model( GoogleUserConnection, is_valid=True, user_id=user.id, user_name=user.name, connection_ad_accounts=[ models.GoogleUserConnectionAdAccount( ad_account=build_model(GoogleAdAccount) ), ], identity_id=identity_id, ) google_client_mock.get_user.return_value = user google_client_mock.get_access_token.return_value = access_token ad_account_service_mock.get_ad_accounts_for_user_connection.return_value = [ ad_account ] with container.override(GoogleAdAccountService, ad_account_service_mock): user_connection_response = handler.handle( GetGoogleUserConnectionRequest( identity_id=user_connection.identity_id, user_id=user_connection.user_id, ), ) assert user_connection.is_valid assert user_connection_response.user assert user_connection_response.user.id == user_connection.user_id assert user_connection_response.user.name == user_connection.user_name assert ( user_connection_response.user.granted_scopes == settings.google_user_required_scopes ) assert user_connection_response.status == GoogleUserConnectionStatus.CONNECTED assert user_connection_response.ad_accounts == [ GoogleUserConnectionAdAccount( id=ad_account.id, external_id=ad_account.external_id, name=ad_account.name or ad_account.external_id, ) ] assert user_connection_response.ad_accounts_count == 1 db_user_connection = user_connection_repository.get_by_identity_id_and_user_id( identity_id=identity_id, user_id=user.id ) assert db_user_connection assert db_user_connection.connection_ad_accounts == [ IsPartialDataclass(ad_account_id=ad_account.id) ] @pytest.mark.db def test_get_user_connection_scopes_are_missing( self, handler: GetGoogleUserConnectionHandler, google_client_mock: mock.MagicMock, build_model: BuildModel, create_model: CreateModel, fake: FakerTyped, ) -> None: user = build_model(User) access_token = build_model(AccessToken, scope=fake.pystr()) user_connection = create_model( GoogleUserConnection, is_valid=True, user_id=user.id, user_name=user.name, ) google_client_mock.get_user.return_value = user google_client_mock.get_access_token.return_value = access_token user_connection_response = handler.handle( GetGoogleUserConnectionRequest( identity_id=user_connection.identity_id, user_id=user_connection.user_id, ), ) assert user_connection_response.user is None assert ( user_connection_response.status == GoogleUserConnectionStatus.SCOPES_MISSING ) def test_get_user_connection_no_connection_found( self, handler: GetGoogleUserConnectionHandler, identity_id: str, fake: FakerTyped, settings: Settings, ) -> None: user_connection_response = handler.handle( GetGoogleUserConnectionRequest( identity_id=identity_id, user_id=fake.pystr() ) ) assert user_connection_response == GoogleUserConnectionResponse( user=None, status=GoogleUserConnectionStatus.NOT_CONNECTED, ad_accounts=[], required_scopes=settings.google_user_required_scopes, ) @pytest.mark.db def test_get_user_connection_invalid( self, handler: GetGoogleUserConnectionHandler, create_model: CreateModel ) -> None: user_connection = create_model(GoogleUserConnection, is_valid=False) user_connection_response = handler.handle( GetGoogleUserConnectionRequest( identity_id=user_connection.identity_id, user_id=user_connection.user_id, ), ) assert user_connection_response.status == GoogleUserConnectionStatus.INVALID assert user_connection_response.ad_accounts == [] @pytest.mark.db def test_get_user_connection_token_invalid( self, handler: GetGoogleUserConnectionHandler, google_client_mock: mock.MagicMock, create_model: CreateModel, settings: Settings, ) -> None: user_connection = create_model(GoogleUserConnection, is_valid=True) google_client_mock.get_user.side_effect = GoogleClientError user_connection_response = handler.handle( GetGoogleUserConnectionRequest( identity_id=user_connection.identity_id, user_id=user_connection.user_id, ), ) assert not user_connection.is_valid assert user_connection_response == GoogleUserConnectionResponse( user=None, status=GoogleUserConnectionStatus.INVALID, required_scopes=settings.google_user_required_scopes, ad_accounts=[], )