from unittest import mock import pytest from anydi import Container from faker import Faker from fansifter_common.adapters.graphql_router import GlobalParticipant from fansifter_common.auth.account import Account from fansifter_common.auth.exceptions import PermissionDenied from fansifter_common.auth.identity import Identity from fansifter_common.auth.types import Permission from dmp.adapters.aws.location import Location from dmp.audiences.enums import AudienceTarget from dmp.audiences.exceptions import ( AudienceUniqueNameError, ) from dmp.audiences.filters import ( AudienceFilters, CityFilter, CrmCampaignFilter, EmailCampaignAction, EmailCampaignsFilter, FanSegmentInFilter, Operator, SongwhipCampaignInFilter, SongwhipPresavePageInFilter, ) from dmp.audiences.handlers import CreateAudienceHandler, CreateAudienceRequest from dmp.audiences.models import Audience from dmp.audiences.types import FanDataListId from dmp.crm_campaigns.models import CrmCampaignIdFanDbt from dmp.email_campaigns.models import EmailAnalyticsByCampaignFanDbt from dmp.fandata.enums import FanSegment from dmp.fandata.models import ( AudienceFiltersAdCampaignDbt, AudienceFiltersCustomListAdCampaignDbt, AudienceFiltersEmailCampaignDbt, GlobalAudienceFiltersAdCampaignDbt, GlobalAudienceFiltersEmailCampaignDbt, ) from dmp.locations.models import City from dmp.rosters.enums import FanDataListType from dmp.rosters.exceptions import ( FanDataListIdIsRequiredError, MainRepArtistOnlyAllowedError, ) from dmp.rosters.models import ArtistRosterLocalRep, ArtistRosterMainRep, CustomList from dmp.rosters.services import GlobalFanDataAccessService from dmp.songwhip.models import SongwhipCustomPageFanDbt, SongwhipPresavePageFanDbt from tests.unit.faker import FakerTyped from tests.unit.types import ( CreateModel, CreateReportingModel, CreateReportingModelBatch, ) def email_target_only_access_side_effect( identity_id: str, # noqa /, *, account: Account, # noqa permission: Permission, resource_id: str | None = None, # noqa ) -> None: if permission == Permission("audience", "create_email_target"): return None else: raise PermissionDenied class TestCreateAudienceHandler: @pytest.mark.db def test_create_audience( self, handler: CreateAudienceHandler, identity: Identity, fake: FakerTyped ) -> None: countries = ["EE", "US"] fan_segments = FanSegmentInFilter( operator=Operator.INCLUDE, value=[FanSegment.CASUAL_FANS, FanSegment.SECONDARY_FANS], ) target = AudienceTarget.ADS filters = AudienceFilters.model_construct( countries=countries, fan_segments=fan_segments ) request = CreateAudienceRequest( identity=identity, name=fake.name(), target=target, vendor_id=fake.integer(), subaccount_id=fake.integer(), fandata_list_ids=[ FanDataListId.from_artist_id(fake.uuid4_string()), ], filters=filters, ) audience = handler.handle(request) assert audience.name == request.name assert audience.vendor_id == request.vendor_id assert audience.subaccount_id == request.subaccount_id assert audience.global_participant_id == request.fandata_list_ids[0].id assert len(audience.fandata_lists) == 1 assert audience.fandata_lists[0].list_id == request.fandata_list_ids[0].id assert audience.fandata_lists[0].type == FanDataListType.ARTIST assert audience.target == request.target assert audience.countries == countries assert audience.filters == filters assert audience.fan_count == 0 assert audience.created_by == request.identity.id assert audience.updated_by == request.identity.id @pytest.mark.db def test_create_audience_with_rosters( self, handler: CreateAudienceHandler, identity: Identity, fake: FakerTyped, create_reporting_model: CreateReportingModel, ) -> None: vendor_id = fake.integer() subaccount_id = fake.integer() custom_list = create_reporting_model( CustomList, vendor_id=vendor_id, subaccount_id=subaccount_id ) countries = ["EE", "US"] fan_segments = FanSegmentInFilter( operator=Operator.INCLUDE, value=[FanSegment.CASUAL_FANS, FanSegment.SECONDARY_FANS], ) target = AudienceTarget.ADS filters = AudienceFilters.model_construct( countries=countries, fan_segments=fan_segments ) request = CreateAudienceRequest( identity=identity, name=fake.name(), target=target, vendor_id=vendor_id, subaccount_id=subaccount_id, fandata_list_ids=[ FanDataListId( id=fake.uuid4_string(), type=FanDataListType.ARTIST, ), FanDataListId( id=custom_list.id, type=FanDataListType.CUSTOM_LIST, ), ], filters=filters, ) audience = handler.handle(request) assert audience.global_participant_id assert audience.fandata_list_ids == request.fandata_list_ids @pytest.mark.db def test_create_audience_unique_name( self, handler: CreateAudienceHandler, create_model: CreateModel, identity: Identity, fake: FakerTyped, ) -> None: audience = create_model(Audience) request = CreateAudienceRequest( identity=identity, name=audience.name, target=AudienceTarget.ADS, vendor_id=audience.vendor_id, subaccount_id=audience.subaccount_id, fandata_list_ids=[ FanDataListId.from_artist_id(fake.uuid4_string()), ], filters=AudienceFilters.model_construct(), ) with pytest.raises(AudienceUniqueNameError): handler.handle(request) @pytest.mark.db def test_create_audience_with_events( self, handler: CreateAudienceHandler, graphql_router_client_mock: mock.MagicMock, create_reporting_model_batch: CreateReportingModelBatch, fake: FakerTyped, identity: Identity, ) -> None: size = 5 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() graphql_router_client_mock.get_global_participant_by_gp_id.return_value = ( GlobalParticipant(id=global_participant_id, name=fake.name()) ) create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) audience = handler.handle( CreateAudienceRequest( identity=identity, vendor_id=vendor_id, subaccount_id=subaccount_id, name=fake.name(), fandata_list_ids=[ FanDataListId.from_artist_id(global_participant_id), ], target=AudienceTarget.ADS, filters=AudienceFilters.model_construct(), ) ) assert audience.fan_count == size @pytest.mark.db def test_create_audience_with_songwhip_presave_page_ids_include( self, handler: CreateAudienceHandler, graphql_router_client_mock: mock.MagicMock, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, identity: Identity, ) -> None: size = 5 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() graphql_router_client_mock.get_global_participant_by_gp_id.return_value = ( GlobalParticipant(id=global_participant_id, name=fake.name()) ) audience_filters_dbt = create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) songwhip_presave_page_fan_dbt = create_reporting_model( SongwhipPresavePageFanDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, fan_id=audience_filters_dbt[0].fan_id, ) audience = handler.handle( CreateAudienceRequest( identity=identity, vendor_id=vendor_id, subaccount_id=subaccount_id, name=fake.name(), fandata_list_ids=[ FanDataListId.from_artist_id(global_participant_id), ], target=AudienceTarget.ADS, filters=AudienceFilters.model_construct( songwhipPresavePageIds=SongwhipPresavePageInFilter( value=[songwhip_presave_page_fan_dbt.id], operator=Operator.INCLUDE, ) ), ) ) assert audience.fan_count == 1 @pytest.mark.db def test_create_audience_with_songwhip_presave_page_ids_exclude( self, handler: CreateAudienceHandler, graphql_router_client_mock: mock.MagicMock, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, identity: Identity, ) -> None: size = 5 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() graphql_router_client_mock.get_global_participant_by_gp_id.return_value = ( GlobalParticipant(id=global_participant_id, name=fake.name()) ) audience_filters_dbt = create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) songwhip_presave_page_fan_dbt = create_reporting_model( SongwhipPresavePageFanDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, fan_id=audience_filters_dbt[0].fan_id, ) audience = handler.handle( CreateAudienceRequest( identity=identity, vendor_id=vendor_id, subaccount_id=subaccount_id, name=fake.name(), fandata_list_ids=[ FanDataListId.from_artist_id(global_participant_id), ], target=AudienceTarget.ADS, filters=AudienceFilters.model_construct( songwhipPresavePageIds=SongwhipPresavePageInFilter( value=[songwhip_presave_page_fan_dbt.id], operator=Operator.EXCLUDE, ) ), ) ) assert audience.fan_count == 4 @pytest.mark.db def test_create_audience_with_songwhip_campaign_ids_include_presave( self, handler: CreateAudienceHandler, graphql_router_client_mock: mock.MagicMock, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, identity: Identity, ) -> None: size = 5 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() graphql_router_client_mock.get_global_participant_by_gp_id.return_value = ( GlobalParticipant(id=global_participant_id, name=fake.name()) ) audience_filters_dbt = create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) songwhip_presave_page_fan_dbt = create_reporting_model( SongwhipPresavePageFanDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, fan_id=audience_filters_dbt[0].fan_id, ) audience = handler.handle( CreateAudienceRequest( identity=identity, vendor_id=vendor_id, subaccount_id=subaccount_id, name=fake.name(), fandata_list_ids=[ FanDataListId.from_artist_id(global_participant_id), ], target=AudienceTarget.ADS, filters=AudienceFilters.model_construct( songwhipCampaignIds=SongwhipCampaignInFilter( value=[songwhip_presave_page_fan_dbt.id], operator=Operator.INCLUDE, ) ), ) ) assert audience.fan_count == 1 @pytest.mark.db def test_create_audience_with_songwhip_campaign_ids_include_custom_page( self, handler: CreateAudienceHandler, graphql_router_client_mock: mock.MagicMock, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, identity: Identity, ) -> None: size = 5 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() graphql_router_client_mock.get_global_participant_by_gp_id.return_value = ( GlobalParticipant(id=global_participant_id, name=fake.name()) ) audience_filters_dbt = create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) songwhip_custom_page_fan_dbt = create_reporting_model( SongwhipCustomPageFanDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, fan_id=audience_filters_dbt[0].fan_id, ) audience = handler.handle( CreateAudienceRequest( identity=identity, vendor_id=vendor_id, subaccount_id=subaccount_id, name=fake.name(), fandata_list_ids=[ FanDataListId.from_artist_id(global_participant_id), ], target=AudienceTarget.ADS, filters=AudienceFilters.model_construct( songwhipCampaignIds=SongwhipCampaignInFilter( value=[songwhip_custom_page_fan_dbt.id], operator=Operator.INCLUDE, ) ), ) ) assert audience.fan_count == 1 @pytest.mark.db def test_create_audience_with_songwhip_campaign_ids_exclude( self, handler: CreateAudienceHandler, graphql_router_client_mock: mock.MagicMock, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, identity: Identity, ) -> None: size = 5 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() graphql_router_client_mock.get_global_participant_by_gp_id.return_value = ( GlobalParticipant(id=global_participant_id, name=fake.name()) ) audience_filters_dbt = create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) songwhip_presave_page_fan_dbt = create_reporting_model( SongwhipPresavePageFanDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, fan_id=audience_filters_dbt[0].fan_id, ) audience = handler.handle( CreateAudienceRequest( identity=identity, vendor_id=vendor_id, subaccount_id=subaccount_id, name=fake.name(), fandata_list_ids=[ FanDataListId.from_artist_id(global_participant_id), ], target=AudienceTarget.ADS, filters=AudienceFilters.model_construct( songwhipCampaignIds=SongwhipCampaignInFilter( value=[songwhip_presave_page_fan_dbt.id], operator=Operator.EXCLUDE, ) ), ) ) assert audience.fan_count == 4 @pytest.mark.db def test_create_audience_with_songwhip_campaign_ids_include_fans_from_both_tables( self, handler: CreateAudienceHandler, graphql_router_client_mock: mock.MagicMock, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, identity: Identity, ) -> None: size = 5 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() graphql_router_client_mock.get_global_participant_by_gp_id.return_value = ( GlobalParticipant(id=global_participant_id, name=fake.name()) ) audience_filters_dbt = create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) presave_fan = create_reporting_model( SongwhipPresavePageFanDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, fan_id=audience_filters_dbt[0].fan_id, ) custom_page_fan = create_reporting_model( SongwhipCustomPageFanDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, fan_id=audience_filters_dbt[1].fan_id, ) audience = handler.handle( CreateAudienceRequest( identity=identity, vendor_id=vendor_id, subaccount_id=subaccount_id, name=fake.name(), fandata_list_ids=[ FanDataListId.from_artist_id(global_participant_id), ], target=AudienceTarget.ADS, filters=AudienceFilters.model_construct( songwhipCampaignIds=SongwhipCampaignInFilter( value=[presave_fan.id, custom_page_fan.id], operator=Operator.INCLUDE, ) ), ) ) assert audience.fan_count == 2 @pytest.mark.db def test_create_audience_with_songwhip_campaign_ids_include_only_matching_table( self, handler: CreateAudienceHandler, graphql_router_client_mock: mock.MagicMock, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, identity: Identity, ) -> None: size = 5 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() graphql_router_client_mock.get_global_participant_by_gp_id.return_value = ( GlobalParticipant(id=global_participant_id, name=fake.name()) ) audience_filters_dbt = create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) presave_fan = create_reporting_model( SongwhipPresavePageFanDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, fan_id=audience_filters_dbt[0].fan_id, ) create_reporting_model( SongwhipCustomPageFanDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, fan_id=audience_filters_dbt[1].fan_id, ) audience = handler.handle( CreateAudienceRequest( identity=identity, vendor_id=vendor_id, subaccount_id=subaccount_id, name=fake.name(), fandata_list_ids=[ FanDataListId.from_artist_id(global_participant_id), ], target=AudienceTarget.ADS, filters=AudienceFilters.model_construct( songwhipCampaignIds=SongwhipCampaignInFilter( value=[presave_fan.id], operator=Operator.INCLUDE, ) ), ) ) assert audience.fan_count == 1 @pytest.mark.db def test_create_audience_fandata_list_ids_required( self, handler: CreateAudienceHandler, identity: Identity, fake: FakerTyped ) -> None: target = AudienceTarget.ADS request = CreateAudienceRequest( identity=identity, name=fake.name(), target=target, vendor_id=fake.integer(), subaccount_id=fake.integer(), fandata_list_ids=[], filters=AudienceFilters.model_construct(), ) with pytest.raises(FanDataListIdIsRequiredError): handler.handle(request) @pytest.mark.db @pytest.mark.parametrize("action", list(EmailCampaignAction)) def test_create_audience_with_email_campaigns_include( self, handler: CreateAudienceHandler, graphql_router_client_mock: mock.MagicMock, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, identity: Identity, action: EmailCampaignAction, ) -> None: size = 5 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() campaign_id_1 = fake.uuid4_string() campaign_id_2 = fake.uuid4_string() graphql_router_client_mock.get_global_participant_by_gp_id.return_value = ( GlobalParticipant(id=global_participant_id, name=fake.name()) ) audience_filters_dbt = create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) create_reporting_model( EmailAnalyticsByCampaignFanDbt, campaign_id=campaign_id_1, fan_id=audience_filters_dbt[0].fan_id, delivered=True, opened=True, clicked=True, ) create_reporting_model( EmailAnalyticsByCampaignFanDbt, campaign_id=campaign_id_2, fan_id=audience_filters_dbt[1].fan_id, delivered=True, opened=True, clicked=True, ) audience = handler.handle( CreateAudienceRequest( identity=identity, vendor_id=vendor_id, subaccount_id=subaccount_id, name=fake.name(), fandata_list_ids=[ FanDataListId.from_artist_id(global_participant_id), ], target=AudienceTarget.ADS, filters=AudienceFilters.model_construct( emailCampaigns=EmailCampaignsFilter( value=[campaign_id_1, campaign_id_2], operator=Operator.INCLUDE, action=action, ) ), ) ) assert audience.fan_count == 2 @pytest.mark.db def test_create_audience_with_email_campaigns_not_delivered( self, handler: CreateAudienceHandler, graphql_router_client_mock: mock.MagicMock, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, identity: Identity, ) -> None: size = 5 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() campaign_id_1 = fake.uuid4_string() campaign_id_2 = fake.uuid4_string() graphql_router_client_mock.get_global_participant_by_gp_id.return_value = ( GlobalParticipant(id=global_participant_id, name=fake.name()) ) audience_filters_dbt = create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) create_reporting_model( EmailAnalyticsByCampaignFanDbt, campaign_id=campaign_id_1, fan_id=audience_filters_dbt[0].fan_id, delivered=True, opened=True, clicked=True, ) create_reporting_model( EmailAnalyticsByCampaignFanDbt, campaign_id=campaign_id_2, fan_id=audience_filters_dbt[1].fan_id, delivered=False, opened=False, clicked=False, ) audience = handler.handle( CreateAudienceRequest( identity=identity, vendor_id=vendor_id, subaccount_id=subaccount_id, name=fake.name(), fandata_list_ids=[ FanDataListId.from_artist_id(global_participant_id), ], target=AudienceTarget.ADS, filters=AudienceFilters.model_construct( emailCampaigns=EmailCampaignsFilter( value=[campaign_id_1, campaign_id_2], operator=Operator.EXCLUDE, action=EmailCampaignAction.DELIVERED, ) ), ) ) assert audience.fan_count == 4 @pytest.mark.db @pytest.mark.parametrize( "action", [EmailCampaignAction.CLICKED, EmailCampaignAction.OPENED] ) def test_create_audience_with_email_campaigns_not_opened_and_not_clicked( self, handler: CreateAudienceHandler, graphql_router_client_mock: mock.MagicMock, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, identity: Identity, action: EmailCampaignAction, ) -> None: size = 5 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() campaign_id = fake.uuid4_string() graphql_router_client_mock.get_global_participant_by_gp_id.return_value = ( GlobalParticipant(id=global_participant_id, name=fake.name()) ) audience_filters_dbt = create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) create_reporting_model( EmailAnalyticsByCampaignFanDbt, campaign_id=campaign_id, fan_id=audience_filters_dbt[0].fan_id, delivered=True, opened=False, clicked=False, ) create_reporting_model( EmailAnalyticsByCampaignFanDbt, campaign_id=campaign_id, fan_id=audience_filters_dbt[1].fan_id, delivered=False, opened=False, clicked=False, ) create_reporting_model( EmailAnalyticsByCampaignFanDbt, campaign_id=campaign_id, fan_id=audience_filters_dbt[2].fan_id, delivered=True, opened=True, clicked=True, ) audience = handler.handle( CreateAudienceRequest( identity=identity, vendor_id=vendor_id, subaccount_id=subaccount_id, name=fake.name(), fandata_list_ids=[ FanDataListId.from_artist_id(global_participant_id), ], target=AudienceTarget.ADS, filters=AudienceFilters.model_construct( emailCampaigns=EmailCampaignsFilter( value=[campaign_id], operator=Operator.EXCLUDE, action=action, ) ), ) ) assert audience.fan_count == 1 @pytest.mark.db def test_create_audience_with_city_filter( self, handler: CreateAudienceHandler, create_reporting_model: CreateReportingModel, identity: Identity, fake: FakerTyped, location_client_mock: mock.MagicMock, ) -> None: vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() # New York City in New York State new_york = create_reporting_model( City, country_code2="US", name="New York City", latitude=40, longitude=-74, ) # New York in Minnesota create_reporting_model( City, country_code2="US", name="New York", latitude=46.51802, longitude=-95.37615, ) location_client_mock.get_location.return_value = Location.model_validate( { "PlaceId": "test", "Title": "New York City, United States", "Address": { "Country": {"Code2": "US", "Name": "United States"}, "Locality": "New York", }, "Position": [-74, 40], "MapView": [-74.1, 40.1, -73.9, 39.9], } ) audience = handler.handle( CreateAudienceRequest( identity=identity, vendor_id=vendor_id, subaccount_id=subaccount_id, name=fake.name(), fandata_list_ids=[ FanDataListId.from_artist_id(global_participant_id), ], target=AudienceTarget.ADS, filters=AudienceFilters.model_construct( cities=[CityFilter.model_construct(place_id="test")] ), ) ) assert audience.filters.cities assert audience.filters.cities[0].is_clean assert audience.filters.cities[0].place_id == "test" assert audience.filters.cities[0].title == "New York City, United States" assert audience.filters.cities[0].country_iso2 == new_york.country_code2 assert audience.filters.cities[0].city_id == new_york.id assert audience.filters.cities[0].latitude == new_york.latitude assert audience.filters.cities[0].longitude == new_york.longitude @pytest.mark.db def test_create_audience_is_global( self, container: Container, handler: CreateAudienceHandler, identity: Identity, fake: FakerTyped, create_reporting_model: CreateReportingModel, ) -> None: vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() create_reporting_model( ArtistRosterMainRep, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) create_reporting_model( GlobalAudienceFiltersEmailCampaignDbt, global_participant_id=global_participant_id, ) global_fandata_access_service_mock = mock.MagicMock( spec=GlobalFanDataAccessService, is_enabled_for_any_vendor=mock.MagicMock(return_value=True), ) with container.override( GlobalFanDataAccessService, instance=global_fandata_access_service_mock ): audience = handler.handle( CreateAudienceRequest( identity=identity, name=fake.name(), target=AudienceTarget.EMAIL, vendor_id=vendor_id, subaccount_id=subaccount_id, fandata_list_ids=[ FanDataListId.from_artist_id(global_participant_id), ], filters=AudienceFilters.model_construct(), ) ) assert audience.fan_count == 1 @pytest.mark.db def test_create_audience_local_rep_is_not_allowed( self, container: Container, handler: CreateAudienceHandler, identity: Identity, faker: Faker, create_reporting_model: CreateReportingModel, ) -> None: vendor_id = faker.pyint() subaccount_id = faker.pyint() global_participant_id = faker.uuid4() create_reporting_model( ArtistRosterLocalRep, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) create_reporting_model( GlobalAudienceFiltersEmailCampaignDbt, global_participant_id=global_participant_id, ) global_fandata_access_service_mock = mock.MagicMock( spec=GlobalFanDataAccessService, is_enabled_for_any_vendor=mock.MagicMock(return_value=True), ) with ( container.override( GlobalFanDataAccessService, instance=global_fandata_access_service_mock ), pytest.raises(MainRepArtistOnlyAllowedError) as exc_info, ): handler.handle( CreateAudienceRequest( identity=identity, name=faker.name(), target=AudienceTarget.EMAIL, vendor_id=vendor_id, subaccount_id=subaccount_id, fandata_list_ids=[ FanDataListId.from_artist_id(global_participant_id), ], filters=AudienceFilters.model_construct(), ) ) assert exc_info.value.global_participant_id == global_participant_id @pytest.mark.db def test_create_audience_restricted_for_user_without_target_access( self, handler: CreateAudienceHandler, identity: Identity, faker: Faker, auth_service_mock: mock.MagicMock, ) -> None: countries = ["EE", "US"] fan_segments = FanSegmentInFilter( operator=Operator.INCLUDE, value=[FanSegment.CASUAL_FANS, FanSegment.SECONDARY_FANS], ) target = AudienceTarget.ADS filters = AudienceFilters.model_construct( countries=countries, fan_segments=fan_segments ) auth_service_mock.check_account_resource.side_effect = ( email_target_only_access_side_effect ) with pytest.raises(PermissionDenied): handler.handle( CreateAudienceRequest( identity=identity, name=faker.name(), target=target, vendor_id=faker.pyint(), subaccount_id=faker.pyint(), fandata_list_ids=[ FanDataListId.from_artist_id(faker.uuid4()), ], filters=filters, ) ) @pytest.mark.db def test_create_audience_target_email_exclude_artist( self, handler: CreateAudienceHandler, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, identity: Identity, ) -> None: size = 5 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() audience_filters_dbt = create_reporting_model_batch( AudienceFiltersEmailCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) audience_filters_dbt_excluded = create_reporting_model( AudienceFiltersEmailCampaignDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, fan_id=audience_filters_dbt[0].fan_id, global_participant_id=fake.uuid4_string(), ) audience = handler.handle( CreateAudienceRequest( identity=identity, vendor_id=vendor_id, subaccount_id=subaccount_id, name=fake.name(), fandata_list_ids=[ FanDataListId.from_artist_id(global_participant_id), ], target=AudienceTarget.EMAIL, filters=AudienceFilters( excludedFanDataLists=[ FanDataListId.from_artist_id( audience_filters_dbt_excluded.global_participant_id ), ], ), ) ) assert audience.fan_count == 4 @pytest.mark.db def test_create_audience_target_ads_exclude_artist( self, handler: CreateAudienceHandler, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, identity: Identity, ) -> None: size = 5 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() audience_filters_dbt = create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) audience_filters_dbt_excluded = create_reporting_model( AudienceFiltersAdCampaignDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, fan_id=audience_filters_dbt[0].fan_id, global_participant_id=fake.uuid4_string(), ) audience = handler.handle( CreateAudienceRequest( identity=identity, vendor_id=vendor_id, subaccount_id=subaccount_id, name=fake.name(), fandata_list_ids=[ FanDataListId.from_artist_id(global_participant_id), ], target=AudienceTarget.ADS, filters=AudienceFilters( excludedFanDataLists=[ FanDataListId.from_artist_id( audience_filters_dbt_excluded.global_participant_id ), ], ), ) ) assert audience.fan_count == 4 @pytest.mark.db def test_create_audience_target_ads_exclude_custom_list( self, handler: CreateAudienceHandler, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, identity: Identity, ) -> None: size = 5 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() custom_list = create_reporting_model( CustomList, vendor_id=vendor_id, subaccount_id=subaccount_id, ) audience_filters_dbt = create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) create_reporting_model( AudienceFiltersCustomListAdCampaignDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, fan_id=audience_filters_dbt[0].fan_id, custom_list_id=custom_list.id, ) audience = handler.handle( CreateAudienceRequest( identity=identity, vendor_id=vendor_id, subaccount_id=subaccount_id, name=fake.name(), fandata_list_ids=[ FanDataListId.from_artist_id(global_participant_id), ], target=AudienceTarget.ADS, filters=AudienceFilters( excludedFanDataLists=[ FanDataListId.from_custom_list_id(custom_list.id), ], ), ) ) assert audience.fan_count == 4 @pytest.mark.db def test_create_audience_is_global_exclude_artist( self, container: Container, handler: CreateAudienceHandler, identity: Identity, fake: FakerTyped, create_reporting_model: CreateReportingModel, create_reporting_model_batch: CreateReportingModelBatch, ) -> None: size = 5 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() create_reporting_model( ArtistRosterMainRep, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) global_audience_filters_dbt = create_reporting_model_batch( GlobalAudienceFiltersEmailCampaignDbt, size=size, global_participant_id=global_participant_id, ) audience_filters_dbt_excluded = create_reporting_model( GlobalAudienceFiltersEmailCampaignDbt, fan_id=global_audience_filters_dbt[0].fan_id, global_participant_id=fake.uuid4_string(), ) global_fandata_access_service_mock = mock.MagicMock( spec=GlobalFanDataAccessService, is_enabled_for_any_vendor=mock.MagicMock(return_value=True), ) with container.override( GlobalFanDataAccessService, instance=global_fandata_access_service_mock ): audience = handler.handle( CreateAudienceRequest( identity=identity, name=fake.name(), target=AudienceTarget.EMAIL, vendor_id=vendor_id, subaccount_id=subaccount_id, fandata_list_ids=[ FanDataListId.from_artist_id(global_participant_id), ], filters=AudienceFilters( excludedFanDataLists=[ FanDataListId.from_artist_id( audience_filters_dbt_excluded.global_participant_id ), ], ), ) ) assert audience.fan_count == 4 @pytest.mark.db def test_create_audience_is_global_exclude_multiple_artists( self, container: Container, handler: CreateAudienceHandler, identity: Identity, fake: FakerTyped, create_reporting_model: CreateReportingModel, create_reporting_model_batch: CreateReportingModelBatch, ) -> None: size = 5 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() create_reporting_model( ArtistRosterMainRep, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) global_audience_filters_dbt = create_reporting_model_batch( GlobalAudienceFiltersEmailCampaignDbt, size=size, global_participant_id=global_participant_id, ) audience_filters_dbt_excluded_1 = create_reporting_model( GlobalAudienceFiltersEmailCampaignDbt, fan_id=global_audience_filters_dbt[0].fan_id, global_participant_id=fake.uuid4_string(), ) audience_filters_dbt_excluded_2 = create_reporting_model( GlobalAudienceFiltersEmailCampaignDbt, fan_id=global_audience_filters_dbt[1].fan_id, global_participant_id=fake.uuid4_string(), ) global_fandata_access_service_mock = mock.MagicMock( spec=GlobalFanDataAccessService, is_enabled_for_any_vendor=mock.MagicMock(return_value=True), ) with container.override( GlobalFanDataAccessService, instance=global_fandata_access_service_mock ): audience = handler.handle( CreateAudienceRequest( identity=identity, name=fake.name(), target=AudienceTarget.EMAIL, vendor_id=vendor_id, subaccount_id=subaccount_id, fandata_list_ids=[ FanDataListId.from_artist_id(global_participant_id), ], filters=AudienceFilters( excludedFanDataLists=[ FanDataListId( id=audience_filters_dbt_excluded_1.global_participant_id, type=FanDataListType.ARTIST, ), FanDataListId( id=audience_filters_dbt_excluded_2.global_participant_id, type=FanDataListType.ARTIST, ), ], ), ) ) assert audience.fan_count == 3 @pytest.mark.db def test_create_account_audience_with_crm_campaign_ids_include( self, handler: CreateAudienceHandler, graphql_router_client_mock: mock.MagicMock, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, identity: Identity, ) -> None: size = 5 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() custom_list_id = None graphql_router_client_mock.get_global_participant_by_gp_id.return_value = ( GlobalParticipant(id=global_participant_id, name=fake.name()) ) audience_filters_dbt = create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) crm_campaign_id_fan_dbt = create_reporting_model( CrmCampaignIdFanDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, custom_list_id=custom_list_id, fan_id=audience_filters_dbt[0].fan_id, ) audience = handler.handle( CreateAudienceRequest( identity=identity, vendor_id=vendor_id, subaccount_id=subaccount_id, name=fake.name(), fandata_list_ids=[ FanDataListId.from_artist_id(global_participant_id), ], target=AudienceTarget.ADS, filters=AudienceFilters.model_construct( crm_campaigns=CrmCampaignFilter( value=[crm_campaign_id_fan_dbt.id], operator=Operator.INCLUDE, ) ), ) ) assert audience.filters.crm_campaigns assert audience.filters.crm_campaigns.operator.value == "INCLUDE" assert audience.fan_count == 1 @pytest.mark.db def test_create_account_audience_with_crm_campaign_ids_exclude( self, handler: CreateAudienceHandler, graphql_router_client_mock: mock.MagicMock, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, identity: Identity, ) -> None: size = 5 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() custom_list_id = None graphql_router_client_mock.get_global_participant_by_gp_id.return_value = ( GlobalParticipant(id=global_participant_id, name=fake.name()) ) audience_filters_dbt = create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) crm_campaign_id_fan_dbt = create_reporting_model( CrmCampaignIdFanDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, custom_list_id=custom_list_id, fan_id=audience_filters_dbt[0].fan_id, ) create_reporting_model( CrmCampaignIdFanDbt, vendor_id=vendor_id + 1, subaccount_id=subaccount_id + 1, global_participant_id=global_participant_id, custom_list_id=custom_list_id, fan_id=audience_filters_dbt[1].fan_id, id=crm_campaign_id_fan_dbt.id, ) audience = handler.handle( CreateAudienceRequest( identity=identity, vendor_id=vendor_id, subaccount_id=subaccount_id, name=fake.name(), fandata_list_ids=[ FanDataListId.from_artist_id(global_participant_id), ], target=AudienceTarget.ADS, filters=AudienceFilters.model_construct( crm_campaigns=CrmCampaignFilter( value=[crm_campaign_id_fan_dbt.id], operator=Operator.EXCLUDE, ) ), ) ) assert audience.filters.crm_campaigns assert audience.filters.crm_campaigns.operator.value == "EXCLUDE" assert audience.fan_count == 4 @pytest.mark.db def test_create_global_audience_with_crm_campaign_ids_include( self, container: Container, handler: CreateAudienceHandler, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, identity: Identity, ) -> None: size = 5 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() create_reporting_model( ArtistRosterMainRep, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) global_fandata_access_service_mock = mock.MagicMock( spec=GlobalFanDataAccessService, is_enabled_for_any_vendor=mock.MagicMock(return_value=True), ) global_audience_filters_dbt = create_reporting_model_batch( GlobalAudienceFiltersAdCampaignDbt, size=size, global_participant_id=global_participant_id, ) crm_campaign_id_fan_dbt = create_reporting_model( CrmCampaignIdFanDbt, global_participant_id=global_participant_id, custom_list_id=None, fan_id=global_audience_filters_dbt[0].fan_id, ) with container.override( GlobalFanDataAccessService, instance=global_fandata_access_service_mock ): audience = handler.handle( CreateAudienceRequest( identity=identity, vendor_id=vendor_id, subaccount_id=subaccount_id, name=fake.name(), fandata_list_ids=[ FanDataListId.from_artist_id(global_participant_id), ], target=AudienceTarget.ADS, filters=AudienceFilters.model_construct( crm_campaigns=CrmCampaignFilter( value=[crm_campaign_id_fan_dbt.id], operator=Operator.INCLUDE, ) ), ) ) assert audience.filters.crm_campaigns assert audience.filters.crm_campaigns.operator.value == "INCLUDE" assert audience.fan_count == 1 @pytest.mark.db def test_create_global_audience_with_crm_campaign_ids_exclude( self, container: Container, handler: CreateAudienceHandler, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, identity: Identity, ) -> None: size = 5 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() create_reporting_model( ArtistRosterMainRep, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) global_fandata_access_service_mock = mock.MagicMock( spec=GlobalFanDataAccessService, is_enabled_for_any_vendor=mock.MagicMock(return_value=True), ) global_audience_filters_dbt = create_reporting_model_batch( GlobalAudienceFiltersAdCampaignDbt, size=size, global_participant_id=global_participant_id, ) crm_campaign_id_fan_dbt = create_reporting_model( CrmCampaignIdFanDbt, global_participant_id=global_participant_id, custom_list_id=None, fan_id=global_audience_filters_dbt[0].fan_id, ) with container.override( GlobalFanDataAccessService, instance=global_fandata_access_service_mock ): audience = handler.handle( CreateAudienceRequest( identity=identity, vendor_id=vendor_id, subaccount_id=subaccount_id, name=fake.name(), fandata_list_ids=[ FanDataListId.from_artist_id(global_participant_id), ], target=AudienceTarget.ADS, filters=AudienceFilters.model_construct( crm_campaigns=CrmCampaignFilter( value=[crm_campaign_id_fan_dbt.id], operator=Operator.EXCLUDE, ) ), ) ) assert audience.filters.crm_campaigns assert audience.filters.crm_campaigns.operator.value == "EXCLUDE" assert audience.fan_count == 4 @pytest.mark.db def test_create_custom_list_audience_with_crm_campaign_ids_include( self, handler: CreateAudienceHandler, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, identity_id: str, ) -> None: size = 5 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = None custom_list = create_reporting_model( CustomList, vendor_id=vendor_id, subaccount_id=subaccount_id ) audience_filters_dbt = create_reporting_model_batch( AudienceFiltersCustomListAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, custom_list_id=custom_list.id, ) crm_campaign_id_fan_dbt = create_reporting_model( CrmCampaignIdFanDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, custom_list_id=custom_list.id, fan_id=audience_filters_dbt[0].fan_id, ) audience = handler.handle( CreateAudienceRequest( identity=Identity( id=identity_id, brand="sme", is_internal_employee=True ), vendor_id=vendor_id, subaccount_id=subaccount_id, name=fake.name(), fandata_list_ids=[ FanDataListId.from_custom_list_id(custom_list.id), ], target=AudienceTarget.ADS, filters=AudienceFilters.model_construct( crm_campaigns=CrmCampaignFilter( value=[crm_campaign_id_fan_dbt.id], operator=Operator.INCLUDE, ) ), ) ) assert audience.filters.crm_campaigns assert audience.filters.crm_campaigns.operator.value == "INCLUDE" assert audience.fan_count == 1 @pytest.mark.db def test_create_custom_list_audience_with_crm_campaign_ids_exclude( self, handler: CreateAudienceHandler, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, identity_id: str, ) -> None: size = 5 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = None custom_list = create_reporting_model( CustomList, vendor_id=vendor_id, subaccount_id=subaccount_id ) audience_filters_dbt = create_reporting_model_batch( AudienceFiltersCustomListAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, custom_list_id=custom_list.id, ) crm_campaign_id_fan_dbt = create_reporting_model( CrmCampaignIdFanDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, custom_list_id=custom_list.id, fan_id=audience_filters_dbt[0].fan_id, ) audience = handler.handle( CreateAudienceRequest( identity=Identity( id=identity_id, brand="sme", is_internal_employee=True ), vendor_id=vendor_id, subaccount_id=subaccount_id, name=fake.name(), fandata_list_ids=[ FanDataListId.from_custom_list_id(custom_list.id), ], target=AudienceTarget.ADS, filters=AudienceFilters.model_construct( crm_campaigns=CrmCampaignFilter( value=[crm_campaign_id_fan_dbt.id], operator=Operator.EXCLUDE, ) ), ) ) assert audience.filters.crm_campaigns assert audience.filters.crm_campaigns.operator.value == "EXCLUDE" assert audience.fan_count == 4 @pytest.mark.db def test_account_audience_with_crm_campaign_ids_include_selected_only( self, handler: CreateAudienceHandler, graphql_router_client_mock: mock.MagicMock, create_reporting_model_batch: CreateReportingModelBatch, create_reporting_model: CreateReportingModel, fake: FakerTyped, identity: Identity, ) -> None: size = 10 vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() custom_list_id = None graphql_router_client_mock.get_global_participant_by_gp_id.return_value = ( GlobalParticipant(id=global_participant_id, name=fake.name()) ) audience_filters_dbt = create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=size, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, ) create_reporting_model( CrmCampaignIdFanDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, custom_list_id=custom_list_id, fan_id=audience_filters_dbt[0].fan_id, ) create_reporting_model( CrmCampaignIdFanDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, custom_list_id=custom_list_id, fan_id=audience_filters_dbt[1].fan_id, ) crm_campaign_id_fan_dbt_1 = create_reporting_model( CrmCampaignIdFanDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, custom_list_id=custom_list_id, fan_id=audience_filters_dbt[3].fan_id, ) crm_campaign_id_fan_dbt_2 = create_reporting_model( CrmCampaignIdFanDbt, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, custom_list_id=custom_list_id, fan_id=audience_filters_dbt[4].fan_id, ) audience = handler.handle( CreateAudienceRequest( identity=identity, vendor_id=vendor_id, subaccount_id=subaccount_id, name=fake.name(), fandata_list_ids=[ FanDataListId.from_artist_id(global_participant_id), ], target=AudienceTarget.ADS, filters=AudienceFilters.model_construct( crm_campaigns=CrmCampaignFilter( value=[ crm_campaign_id_fan_dbt_1.id, crm_campaign_id_fan_dbt_2.id, ], operator=Operator.INCLUDE, ) ), ) ) assert audience.filters.crm_campaigns assert audience.fan_count == 2 @pytest.mark.db def test_create_audience_with_exclude_countries( self, handler: CreateAudienceHandler, graphql_router_client_mock: mock.MagicMock, create_reporting_model_batch: CreateReportingModelBatch, fake: FakerTyped, identity: Identity, ) -> None: vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() country_1 = "US" country_2 = "GB" country_3 = "EE" country_4 = None graphql_router_client_mock.get_global_participant_by_gp_id.return_value = ( GlobalParticipant(id=global_participant_id, name=fake.name()) ) create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=3, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, country_iso2=country_1, ) create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=2, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, country_iso2=country_2, ) create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=4, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, country_iso2=country_3, ) create_reporting_model_batch( AudienceFiltersAdCampaignDbt, size=10, vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, country_iso2=country_4, ) audience = handler.handle( CreateAudienceRequest( identity=identity, vendor_id=vendor_id, subaccount_id=subaccount_id, name=fake.name(), fandata_list_ids=[ FanDataListId.from_artist_id(global_participant_id), ], target=AudienceTarget.ADS, filters=AudienceFilters.model_construct( countries=[country_1, country_2], exclude_countries=True, ), ) ) assert audience.fan_count == 14