from unittest import mock import pytest from dmp.ad_accounts.enums import AdAccountPlatform from dmp.ad_accounts.models import AdAccountDbt from dmp.ad_reporting.enums import AdReportingPlatform from dmp.adapters.fivetran.enums import ( AdsAccountsSyncMode, ConnectionSetupState, ConnectionSyncState, ) from dmp.adapters.fivetran.models import AdsConnection from dmp.app_connections.enums import AppConnectionStatus from dmp.google.models import ( GoogleAdAccount, GoogleAdReportingConnection, GoogleUserConnection, GoogleUserConnectionAdAccount, ) from dmp.google.services import GoogleAdReportingConnectionService from tests.unit.faker import FakerTyped from tests.unit.types import BuildModel, CreateModel, CreateReportingModel class TestGoogleAdReportingConnectionService: @pytest.mark.db def test_refresh_connection_with_new_ad_account_for_existed_connection( self, service: GoogleAdReportingConnectionService, fivetran_client_mock: mock.MagicMock, create_model: CreateModel, create_reporting_model: CreateReportingModel, build_model: BuildModel, fake: FakerTyped, ) -> None: ad_account_1 = create_model(GoogleAdAccount) ad_account_2 = create_model(GoogleAdAccount) new_ad_account_external_id = fake.pystr() ad_reporting_connection = create_model( GoogleAdReportingConnection, ad_accounts=[ad_account_1, ad_account_2] ) fivetran_connection = build_model( AdsConnection, config={ "sync_mode": AdsAccountsSyncMode.SPECIFIC_ACCOUNTS, "accounts": [ ad_account_1.external_id, ad_account_2.external_id, new_ad_account_external_id, ], }, status={ "setup_state": ConnectionSetupState.CONNECTED, "sync_state": ConnectionSyncState.SYNCING, "is_historical_sync": False, }, ) create_reporting_model( AdAccountDbt, id=ad_account_1.external_id, platform=AdReportingPlatform.GOOGLE, ) create_reporting_model( AdAccountDbt, id=ad_account_2.external_id, platform=AdReportingPlatform.GOOGLE, ) create_reporting_model( AdAccountDbt, id=new_ad_account_external_id, platform=AdReportingPlatform.GOOGLE, ) fivetran_client_mock.get_ads_connection.return_value = fivetran_connection refreshed_ad_reporting_connection = service.refresh_connection( ad_reporting_connection ) assert refreshed_ad_reporting_connection assert refreshed_ad_reporting_connection.ad_accounts_count == 3 @pytest.mark.db def test_refresh_connection_with_deleted_ad_account_for_existed_connection( self, service: GoogleAdReportingConnectionService, fivetran_client_mock: mock.MagicMock, create_model: CreateModel, create_reporting_model: CreateReportingModel, build_model: BuildModel, ) -> None: ad_account_1 = create_model(GoogleAdAccount) ad_account_2 = create_model(GoogleAdAccount) ad_reporting_connection = create_model( GoogleAdReportingConnection, ad_accounts=[ad_account_1, ad_account_2] ) fivetran_connection = build_model( AdsConnection, config={ "sync_mode": AdsAccountsSyncMode.SPECIFIC_ACCOUNTS, "accounts": [ ad_account_1.external_id, ], }, status={ "setup_state": ConnectionSetupState.CONNECTED, "sync_state": ConnectionSyncState.SYNCING, "is_historical_sync": False, }, ) create_reporting_model( AdAccountDbt, id=ad_account_1.external_id, platform=AdReportingPlatform.GOOGLE, ) fivetran_client_mock.get_ads_connection.return_value = fivetran_connection refreshed_ad_reporting_connection = service.refresh_connection( ad_reporting_connection ) assert refreshed_ad_reporting_connection assert refreshed_ad_reporting_connection.ad_accounts_count == 1 @pytest.mark.db def test_refresh_connection_before_sync_details_for_specific_accounts( self, service: GoogleAdReportingConnectionService, fivetran_client_mock: mock.MagicMock, create_model: CreateModel, create_reporting_model: CreateReportingModel, build_model: BuildModel, fake: FakerTyped, ) -> None: ad_reporting_connection = create_model(GoogleAdReportingConnection) external_id_1 = fake.pystr() external_id_2 = fake.pystr() fivetran_connection = build_model( AdsConnection, config={ "sync_mode": AdsAccountsSyncMode.SPECIFIC_ACCOUNTS, "accounts": [external_id_1, external_id_2], }, status={ "setup_state": ConnectionSetupState.CONNECTED, "sync_state": ConnectionSyncState.SYNCING, "is_historical_sync": False, }, ) create_reporting_model( AdAccountDbt, id=external_id_1, platform=AdReportingPlatform.GOOGLE ) create_reporting_model( AdAccountDbt, id=external_id_2, platform=AdReportingPlatform.GOOGLE ) fivetran_client_mock.get_ads_connection.return_value = fivetran_connection refreshed_ad_reporting_connection = service.refresh_connection( ad_reporting_connection ) assert refreshed_ad_reporting_connection assert refreshed_ad_reporting_connection.ad_accounts_count == 2 @pytest.mark.db def test_refresh_connection_for_incomplete_connection_not_create_ad_accounts( self, service: GoogleAdReportingConnectionService, fivetran_client_mock: mock.MagicMock, create_model: CreateModel, build_model: BuildModel, fake: FakerTyped, ) -> None: ad_reporting_connection = create_model(GoogleAdReportingConnection) external_id_1 = fake.pystr() external_id_2 = fake.pystr() fivetran_connection = build_model( AdsConnection, config={ "sync_mode": AdsAccountsSyncMode.SPECIFIC_ACCOUNTS, "accounts": [external_id_1, external_id_2], }, status={ "setup_state": ConnectionSetupState.INCOMPLETE, "sync_state": ConnectionSyncState.RESCHEDULED, "is_historical_sync": False, }, ) fivetran_client_mock.get_ads_connection.return_value = fivetran_connection refreshed_ad_reporting_connection = service.refresh_connection( ad_reporting_connection ) assert refreshed_ad_reporting_connection assert refreshed_ad_reporting_connection.ad_accounts_count == 0 @pytest.mark.db def test_refresh_connection_for_connection_with_only_dbt_ad_accounts( self, service: GoogleAdReportingConnectionService, fivetran_client_mock: mock.MagicMock, create_model: CreateModel, create_reporting_model: CreateReportingModel, build_model: BuildModel, ) -> None: ad_reporting_connection = create_model(GoogleAdReportingConnection) dbt_ad_account = create_reporting_model( AdAccountDbt, source_schema=ad_reporting_connection.fivetran_schema, platform=AdAccountPlatform.GOOGLE, ) fivetran_connection = build_model( AdsConnection, config={ "sync_mode": AdsAccountsSyncMode.SPECIFIC_ACCOUNTS, "accounts": [], }, status={ "setup_state": ConnectionSetupState.CONNECTED, "sync_state": ConnectionSyncState.RESCHEDULED, "is_historical_sync": False, }, schema=ad_reporting_connection.fivetran_schema, ) fivetran_client_mock.get_ads_connection.return_value = fivetran_connection refreshed_ad_reporting_connection = service.refresh_connection( ad_reporting_connection ) assert refreshed_ad_reporting_connection assert refreshed_ad_reporting_connection.ad_accounts_count == 1 assert ( refreshed_ad_reporting_connection.ad_accounts[0].external_id == dbt_ad_account.id ) @pytest.mark.db def test_refresh_connection_for_connection_for_sync_all_empty_dbt( self, service: GoogleAdReportingConnectionService, fivetran_client_mock: mock.MagicMock, create_model: CreateModel, build_model: BuildModel, ) -> None: ad_account = create_model(GoogleAdAccount) user_connection = create_model( GoogleUserConnection, connection_ad_accounts=[ GoogleUserConnectionAdAccount(ad_account=ad_account), ], ) ad_reporting_connection = create_model( GoogleAdReportingConnection, user_id=user_connection.user_id, identity_id=user_connection.identity_id, status=AppConnectionStatus.SYNCING_INITIAL, ad_accounts=[], ) fivetran_connection = build_model( AdsConnection, config={ "sync_mode": AdsAccountsSyncMode.ALL_ACCOUNTS, }, status={ "setup_state": ConnectionSetupState.CONNECTED, "sync_state": ConnectionSyncState.SYNCING, "is_historical_sync": True, }, schema=ad_reporting_connection.fivetran_schema, ) fivetran_client_mock.get_ads_connection.return_value = fivetran_connection refreshed_ad_reporting_connection = service.refresh_connection( ad_reporting_connection ) assert refreshed_ad_reporting_connection assert refreshed_ad_reporting_connection.ad_accounts_count == 1 assert refreshed_ad_reporting_connection.ad_accounts[0].id == ad_account.id @pytest.mark.db def test_refresh_connection_for_connection_for_sync_manager_accounts_empty_dbt( self, service: GoogleAdReportingConnectionService, fivetran_client_mock: mock.MagicMock, create_model: CreateModel, build_model: BuildModel, ) -> None: ad_account = create_model(GoogleAdAccount) user_connection = create_model( GoogleUserConnection, connection_ad_accounts=[ GoogleUserConnectionAdAccount(ad_account=ad_account), ], ) ad_reporting_connection = create_model( GoogleAdReportingConnection, user_id=user_connection.user_id, identity_id=user_connection.identity_id, status=AppConnectionStatus.SYNCING_INITIAL, ad_accounts=[], ) fivetran_connection = build_model( AdsConnection, config={ "sync_mode": AdsAccountsSyncMode.MANAGER_ACCOUNTS, }, status={ "setup_state": ConnectionSetupState.CONNECTED, "sync_state": ConnectionSyncState.SYNCING, "is_historical_sync": True, }, schema=ad_reporting_connection.fivetran_schema, ) fivetran_client_mock.get_ads_connection.return_value = fivetran_connection refreshed_ad_reporting_connection = service.refresh_connection( ad_reporting_connection ) assert refreshed_ad_reporting_connection assert refreshed_ad_reporting_connection.ad_accounts_count == 1 assert refreshed_ad_reporting_connection.ad_accounts[0].id == ad_account.id