from unittest import mock import pytest from dmp.adapters.tiktok.models import ( AccessToken, AdAccount, BusinessCenterInfo, User, ) from dmp.config import Settings from dmp.tiktok.exceptions import TikTokUserConnectionScopesError from dmp.tiktok.handlers import ConnectTikTokUserHandler, ConnectTikTokUserRequest from dmp.tiktok.models import TikTokUserConnection from dmp.tiktok.repositories import ( TikTokAdAccountRepository, TikTokUserConnectionRepository, ) from tests.unit.faker import FakerTyped from tests.unit.types import BuildModel, CreateModel class TestConnectTikTokUserHandler: @pytest.fixture(autouse=True) def mock_campaigns_count(self, tiktok_client_mock: mock.MagicMock) -> None: tiktok_client_mock.get_ad_account_campaigns_count.return_value = 5 @pytest.mark.db def test_connect_user_with_insufficient_scopes_token( self, handler: ConnectTikTokUserHandler, tiktok_client_mock: mock.MagicMock, identity_id: str, fake: FakerTyped, build_model: BuildModel, ) -> None: tmp_token = fake.plain_token() tiktok_client_mock.get_oauth_access_token.return_value = build_model( AccessToken ) with pytest.raises(TikTokUserConnectionScopesError): handler.handle( ConnectTikTokUserRequest( identity_id=identity_id, access_token=tmp_token, ) ) @pytest.mark.db def test_connect_user_with_empty_ad_accounts_data( self, handler: ConnectTikTokUserHandler, user_connection_repository: TikTokUserConnectionRepository, tiktok_client_mock: mock.MagicMock, identity_id: str, fake: FakerTyped, build_model: BuildModel, settings: Settings, ) -> None: tmp_token = fake.plain_token() tiktok_client_mock.get_oauth_access_token.return_value = build_model( AccessToken, scope=settings.tiktok_user_required_scopes ) user = build_model(User) tiktok_client_mock.get_user.return_value = user tiktok_client_mock.get_ad_accounts_details.return_value = [] user_connection_response = handler.handle( ConnectTikTokUserRequest( identity_id=identity_id, access_token=tmp_token, ) ) assert user_connection_response assert user_connection_response.status == "CONNECTED" assert user_connection_response.ad_accounts_count == 0 user_connection = user_connection_repository.first() assert user_connection assert user_connection.user_id == user.core_user_id assert user_connection.identity_id == identity_id @pytest.mark.db def test_connect_user_with_ad_accounts( self, handler: ConnectTikTokUserHandler, user_connection_repository: TikTokUserConnectionRepository, ad_account_repository: TikTokAdAccountRepository, tiktok_client_mock: mock.MagicMock, identity_id: str, fake: FakerTyped, build_model: BuildModel, settings: Settings, ) -> None: tmp_token = fake.plain_token() tiktok_client_mock.get_oauth_access_token.return_value = build_model( AccessToken, scope=settings.tiktok_user_required_scopes ) user = build_model(User) ad_account_1 = build_model(AdAccount) ad_account_2 = build_model(AdAccount) tiktok_client_mock.get_user.return_value = user tiktok_client_mock.get_ad_accounts_details.return_value = [ ad_account_1, ad_account_2, ] tiktok_client_mock.get_business_center_details.return_value = None user_connection_response = handler.handle( ConnectTikTokUserRequest( identity_id=identity_id, access_token=tmp_token, ) ) assert user_connection_response assert user_connection_response.status == "CONNECTED" assert user_connection_response.ad_accounts_count == 2 user_connection = user_connection_repository.first() assert user_connection assert user_connection.user_id == user.core_user_id assert user_connection.identity_id == identity_id assert user_connection.ad_accounts_count == 2 ad_accounts = ad_account_repository.find_by_external_ids( external_ids=[ad_account_1.advertiser_id, ad_account_2.advertiser_id] ) assert ad_accounts assert ad_accounts[0].campaigns_count == 5 assert ad_accounts[0].business_center_name assert ad_accounts[1].campaigns_count == 5 assert ad_accounts[1].business_center_name @pytest.mark.db def test_connect_user_with_existed_connection_and_new_user_id( self, handler: ConnectTikTokUserHandler, user_connection_repository: TikTokUserConnectionRepository, ad_account_repository: TikTokAdAccountRepository, tiktok_client_mock: mock.MagicMock, identity_id: str, fake: FakerTyped, build_model: BuildModel, create_model: CreateModel, settings: Settings, ) -> None: create_model( TikTokUserConnection, identity_id=identity_id, ) tmp_token = fake.plain_token() tiktok_client_mock.get_oauth_access_token.return_value = build_model( AccessToken, scope=settings.tiktok_user_required_scopes ) user = build_model(User) ad_account_1 = build_model(AdAccount) ad_account_2 = build_model(AdAccount) tiktok_client_mock.get_user.return_value = user tiktok_client_mock.get_ad_accounts_details.return_value = [ ad_account_1, ad_account_2, ] business_center = build_model(BusinessCenterInfo) tiktok_client_mock.get_business_center_details.return_value = business_center user_connection_response = handler.handle( ConnectTikTokUserRequest( identity_id=identity_id, access_token=tmp_token, ) ) assert user_connection_response assert user_connection_response.status == "CONNECTED" assert user_connection_response.ad_accounts_count == 2 user_connections = user_connection_repository.get_by_identity_id( identity_id=identity_id ) assert user_connections assert len(user_connections) == 2 user_connection = user_connection_repository.get_by_identity_id_and_user_id( identity_id=identity_id, user_id=user.core_user_id ) assert user_connection assert user_connection.user_id == user.core_user_id assert user_connection.identity_id == identity_id assert user_connection.ad_accounts_count == 2 ad_accounts = ad_account_repository.find_by_external_ids( external_ids=[ad_account_1.advertiser_id, ad_account_2.advertiser_id] ) assert ad_accounts assert ad_accounts[0].campaigns_count == 5 assert ad_accounts[0].business_center_name == business_center.name assert ad_accounts[1].campaigns_count == 5 assert ad_accounts[1].business_center_name == business_center.name @pytest.mark.db def test_reconnect_invalid_connection( self, handler: ConnectTikTokUserHandler, user_connection_repository: TikTokUserConnectionRepository, tiktok_client_mock: mock.MagicMock, identity_id: str, fake: FakerTyped, create_model: CreateModel, build_model: BuildModel, settings: Settings, ) -> None: tmp_token = fake.plain_token() tiktok_client_mock.get_oauth_access_token.return_value = build_model( AccessToken, scope=settings.tiktok_user_required_scopes ) user = build_model(User) create_model( TikTokUserConnection, identity_id=identity_id, user_id=user.core_user_id, is_valid=False, ) tiktok_client_mock.get_user.return_value = user tiktok_client_mock.get_ad_accounts_details.return_value = [] user_connection_response = handler.handle( ConnectTikTokUserRequest( identity_id=identity_id, access_token=tmp_token, ) ) assert user_connection_response assert user_connection_response.status == "CONNECTED" assert user_connection_response.ad_accounts_count == 0 user_connection = user_connection_repository.first() assert user_connection assert user_connection.is_valid assert user_connection.user_id == user.core_user_id assert user_connection.identity_id == identity_id