from unittest import mock import pytest from anydi import Container from dirty_equals import IsList, IsUUID from faker import Faker from fansifter_common.adapters.graphql_router import GlobalParticipant from fansifter_common.auth.account import Account from fansifter_common.utils import timezone from freezegun import freeze_time from starlette.testclient import TestClient from dmp.adapters.features import AUDIENCE_SHOW_SMS_CAMPAIGNS_PAGE from dmp.audiences.dtos import AudienceAdAccount from dmp.audiences.enums import ( AudienceExportStatus, AudienceSharePlatform, AudienceTarget, ) from dmp.audiences.filters import ( AudienceFilters, Operator, SongwhipCampaignInFilter, SongwhipPresavePageInFilter, ) from dmp.audiences.handlers import ( ExportAudienceHandler, GetAudienceAdAccountsHandler, GetAudienceExportHandler, GetAudienceExportResponse, GetAudiencesArtistsHandler, RefreshAudienceHandler, ) from dmp.audiences.models import ( Audience, AudienceExport, AudienceFanDataList, AudienceShare, ) from dmp.rosters.enums import FanDataListType from dmp.text_campaigns.models import ArtistPhoneNumber from tests.unit.equals import IsISODatetime, IsISODatetimeOrNone from tests.unit.faker import FakerTyped from tests.unit.types import ( BuildModel, CreateModel, CreateReportingModel, EnableFeatures, ) @pytest.mark.db def test_get_audiences( client: TestClient, create_model: CreateModel, faker: Faker, account: Account, ) -> None: global_participant_id = faker.uuid4() refreshed_at = timezone.now() audience = create_model( Audience, vendor_id=account.vendor_id, subaccount_id=account.subaccount_id, refreshed_at=refreshed_at, recipients_count_by_email_provider=None, fandata_lists=[ AudienceFanDataList( list_id=global_participant_id, type=FanDataListType.ARTIST, ) ], ) response = client.get("/audiences") assert response.status_code == 200 assert response.json() == { "total": 1, "items": [ { "id": audience.id, "name": audience.name, "vendorId": audience.vendor_id, "subaccountId": audience.subaccount_id, "fanDataListIds": [ { "id": audience.global_participant_id, "type": "ARTIST", } ], "target": audience.target, "countries": audience.countries, "fanSegments": audience.fan_segments, "filters": { "countries": audience.filters.countries, "excludeCountries": audience.filters.exclude_countries, "crmCampaigns": audience.filters.crm_campaigns, "crmSublists": audience.filters.crm_sublists, "genres": audience.filters.genres, "fanLanguages": audience.filters.fan_languages, "birthMonths": audience.filters.birth_months, "cities": audience.filters.cities, "radius": audience.filters.radius, "radiusUnit": audience.filters.radius_unit, "spendMax": audience.filters.spend_max, "spendMin": audience.filters.spend_min, "heavyRotationV2": audience.filters.heavy_rotation_v2, "dsp": audience.filters.dsp, "lastEngagement": audience.filters.last_engagement, "fanSegments": audience.filters.fan_segments, "songwhipPresavePageIds": audience.filters.songwhip_presave_page_ids, "songwhipCampaignIds": audience.filters.songwhip_campaign_ids, "emailCampaigns": audience.filters.email_campaigns, "includeSecondaryFans": audience.filters.include_secondary_fans, "excludedFanDataLists": audience.filters.excluded_fan_data_lists, "regions": audience.filters.regions, }, "fanCount": audience.fan_count, "isArchived": audience.is_archived, "createdAt": IsISODatetime(audience.created_at), "createdBy": audience.created_by, "updatedAt": IsISODatetime(audience.updated_at), "updatedBy": audience.updated_by, "refreshedAt": IsISODatetime(refreshed_at), "refreshedBy": audience.refreshed_by, } ], "limit": 50, "offset": 0, } @pytest.mark.db @freeze_time("2020-01-01") def test_create_audiences( client: TestClient, fake: FakerTyped, identity_id: str, graphql_router_client_mock: mock.MagicMock, ) -> None: dt_now = timezone.now() name = "Test Audience" vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() target = AudienceTarget.ADS countries = ["US", "EE"] graphql_router_client_mock.get_global_participant_by_gp_id.return_value = ( GlobalParticipant( id=global_participant_id, name="Test Artist", ) ) response = client.post( "/audiences", json={ "name": name, "vendorId": vendor_id, "subaccountId": subaccount_id, "fanDataListIds": [ { "id": global_participant_id, "type": "ARTIST", } ], "target": target, "filters": { "countries": countries, }, }, ) assert response.status_code == 201 assert response.json() == { "id": IsUUID(), "name": name, "vendorId": vendor_id, "subaccountId": subaccount_id, "fanDataListIds": [ { "id": global_participant_id, "type": "ARTIST", } ], "target": target, "countries": IsList(*countries, check_order=False), "fanSegments": [], "filters": { "countries": IsList(*countries, check_order=False), "excludeCountries": None, "crmCampaigns": None, "crmSublists": None, "genres": None, "fanLanguages": None, "birthMonths": None, "cities": None, "radius": None, "radiusUnit": None, "spendMax": None, "spendMin": None, "heavyRotationV2": None, "dsp": None, "lastEngagement": None, "fanSegments": None, "songwhipPresavePageIds": None, "songwhipCampaignIds": None, "emailCampaigns": None, "includeSecondaryFans": False, "excludedFanDataLists": None, "regions": None, }, "fanCount": 0, "isArchived": False, "createdAt": IsISODatetime(dt_now), "createdBy": identity_id, "updatedAt": IsISODatetime(dt_now), "updatedBy": identity_id, "refreshedAt": IsISODatetime(dt_now), "refreshedBy": identity_id, } @pytest.mark.db def test_create_audiences_with_existing_name( client: TestClient, create_model: CreateModel, faker: Faker ) -> None: name = "Test audience" audience = create_model(Audience, name=name) response = client.post( "/audiences", json={ "name": " test audience ", "vendorId": audience.vendor_id, "subaccountId": audience.subaccount_id, "fanDataListIds": [ { "id": faker.uuid4(cast_to=str), "type": "ARTIST", } ], "target": audience.target, "filters": {}, }, ) assert response.status_code == 400 assert response.json() == { "code": "audience_unique_name", "message": "Audience name must be unique", } @pytest.mark.db def test_create_audiences_with_empty_name( client: TestClient, create_model: CreateModel ) -> None: name = "Test audience" audience = create_model(Audience, name=name) response = client.post( "/audiences", json={ "name": " ", "vendorId": audience.vendor_id, "subaccountId": audience.subaccount_id, "globalParticipantId": audience.global_participant_id, "target": audience.target, "filters": {}, }, ) assert response.status_code == 422 assert response.json() == { "code": "invalid_input", "message": "Invalid input", "fieldErrors": { "name": { "code": "string_too_short", "message": "String should have at least 1 character", } }, } @pytest.mark.db def test_get_audience( client: TestClient, create_model: CreateModel, faker: Faker ) -> None: global_participant_id = faker.uuid4() refreshed_at = timezone.now() audience = create_model( Audience, refreshed_at=refreshed_at, fandata_lists=[ AudienceFanDataList( list_id=global_participant_id, type=FanDataListType.ARTIST, ) ], ) response = client.get(f"/audiences/{audience.id}") assert response.status_code == 200 assert response.json() == { "id": audience.id, "name": audience.name, "vendorId": audience.vendor_id, "subaccountId": audience.subaccount_id, "fanDataListIds": [ { "id": audience.global_participant_id, "type": "ARTIST", } ], "target": audience.target, "countries": audience.countries, "fanSegments": audience.fan_segments, "filters": { "countries": audience.filters.countries, "excludeCountries": None, "crmCampaigns": audience.filters.crm_campaigns, "crmSublists": audience.filters.crm_sublists, "genres": audience.filters.genres, "fanLanguages": audience.filters.fan_languages, "birthMonths": audience.filters.birth_months, "cities": audience.filters.cities, "radius": audience.filters.radius, "radiusUnit": audience.filters.radius_unit, "spendMax": audience.filters.spend_max, "spendMin": audience.filters.spend_min, "heavyRotationV2": audience.filters.heavy_rotation_v2, "dsp": audience.filters.dsp, "lastEngagement": audience.filters.last_engagement, "fanSegments": audience.filters.fan_segments, "songwhipPresavePageIds": audience.filters.songwhip_presave_page_ids, "songwhipCampaignIds": audience.filters.songwhip_campaign_ids, "emailCampaigns": audience.filters.email_campaigns, "includeSecondaryFans": audience.filters.include_secondary_fans, "excludedFanDataLists": audience.filters.excluded_fan_data_lists, "regions": audience.filters.regions, }, "fanCount": audience.fan_count, "isArchived": audience.is_archived, "createdAt": IsISODatetime(audience.created_at), "createdBy": audience.created_by, "updatedAt": IsISODatetime(audience.updated_at), "updatedBy": audience.updated_by, "refreshedAt": IsISODatetime(refreshed_at), "refreshedBy": audience.refreshed_by, } @pytest.mark.db def test_get_audience_returns_songwhip_campaign_ids( client: TestClient, create_model: CreateModel, account: Account, ) -> None: campaign_ids = ["campaign-1", "campaign-2"] audience = create_model( Audience, vendor_id=account.vendor_id, subaccount_id=account.subaccount_id, filters=AudienceFilters.model_construct( songwhip_campaign_ids=SongwhipCampaignInFilter( value=campaign_ids, operator=Operator.INCLUDE, ), ), ) response = client.get(f"/audiences/{audience.id}") assert response.status_code == 200 assert response.json()["filters"]["songwhipCampaignIds"] == { "value": campaign_ids, "operator": "INCLUDE", } @pytest.mark.db def test_get_audiences_returns_songwhip_campaign_ids( client: TestClient, create_model: CreateModel, account: Account, ) -> None: campaign_ids = ["campaign-1", "campaign-2"] create_model( Audience, vendor_id=account.vendor_id, subaccount_id=account.subaccount_id, filters=AudienceFilters.model_construct( songwhip_campaign_ids=SongwhipCampaignInFilter( value=campaign_ids, operator=Operator.INCLUDE, ), ), ) response = client.get("/audiences") assert response.status_code == 200 assert response.json()["items"][0]["filters"]["songwhipCampaignIds"] == { "value": campaign_ids, "operator": "INCLUDE", } @pytest.mark.db def test_get_audience_presave_page_ids_backfilled_into_songwhip_campaign_ids( client: TestClient, create_model: CreateModel, account: Account, ) -> None: presave_page_ids = ["presave-1", "presave-2"] audience = create_model( Audience, vendor_id=account.vendor_id, subaccount_id=account.subaccount_id, filters=AudienceFilters.model_construct( songwhip_presave_page_ids=SongwhipPresavePageInFilter( value=presave_page_ids, operator=Operator.INCLUDE, ), ), ) response = client.get(f"/audiences/{audience.id}") assert response.status_code == 200 assert response.json()["filters"]["songwhipCampaignIds"] == { "value": presave_page_ids, "operator": "INCLUDE", } @pytest.mark.db def test_get_audience_archived_not_found( client: TestClient, create_model: CreateModel, fake: FakerTyped ) -> None: audience = create_model( Audience, archived_at=timezone.now(), archived_by=fake.uuid4_string(), ) response = client.get(f"/audiences/{audience.id}") assert response.status_code == 404 assert response.json() == { "code": "audience_not_found", "message": "Audience not found", } def test_refresh_audience( client: TestClient, container: Container, build_model: CreateModel, faker: Faker ) -> None: global_participant_id = faker.uuid4() refreshed_at = timezone.now() audience = build_model( Audience, refreshed_at=refreshed_at, fandata_lists=[ AudienceFanDataList( list_id=global_participant_id, type=FanDataListType.ARTIST, ) ], ) handler_mock = mock.MagicMock(spec=RefreshAudienceHandler) handler_mock.handle.return_value = audience with container.override(RefreshAudienceHandler, instance=handler_mock): response = client.post(f"/audiences/{audience.id}/refresh") assert response.status_code == 200 assert response.json() == { "id": audience.id, "name": audience.name, "vendorId": audience.vendor_id, "subaccountId": audience.subaccount_id, "fanDataListIds": [ { "id": audience.global_participant_id, "type": "ARTIST", } ], "target": audience.target, "countries": audience.countries, "fanSegments": audience.fan_segments, "filters": { "countries": audience.filters.countries, "excludeCountries": None, "crmCampaigns": audience.filters.crm_campaigns, "crmSublists": audience.filters.crm_sublists, "genres": audience.filters.genres, "fanLanguages": audience.filters.fan_languages, "birthMonths": audience.filters.birth_months, "cities": audience.filters.cities, "radius": audience.filters.radius, "radiusUnit": audience.filters.radius_unit, "spendMax": audience.filters.spend_max, "spendMin": audience.filters.spend_min, "heavyRotationV2": audience.filters.heavy_rotation_v2, "dsp": audience.filters.dsp, "lastEngagement": audience.filters.last_engagement, "fanSegments": audience.filters.fan_segments, "songwhipPresavePageIds": audience.filters.songwhip_presave_page_ids, "songwhipCampaignIds": audience.filters.songwhip_campaign_ids, "emailCampaigns": audience.filters.email_campaigns, "includeSecondaryFans": audience.filters.include_secondary_fans, "excludedFanDataLists": audience.filters.excluded_fan_data_lists, "regions": audience.filters.regions, }, "fanCount": audience.fan_count, "isArchived": audience.is_archived, "createdAt": IsISODatetime(audience.created_at), "createdBy": audience.created_by, "updatedAt": IsISODatetime(audience.updated_at), "updatedBy": audience.updated_by, "refreshedAt": IsISODatetime(refreshed_at), "refreshedBy": audience.refreshed_by, } @pytest.mark.db def test_archive_audience(client: TestClient, create_model: CreateModel) -> None: audience = create_model(Audience) response = client.post(f"/audiences/{audience.id}/archive") assert response.status_code == 204 @pytest.mark.db def test_update_audience( client: TestClient, create_model: CreateModel, faker: Faker ) -> None: global_participant_id = faker.uuid4() audience = create_model( Audience, fandata_lists=[ AudienceFanDataList( list_id=global_participant_id, type=FanDataListType.ARTIST, ) ], ) response = client.put( f"/audiences/{audience.id}", json={ "name": audience.name, "target": audience.target, "filters": {}, }, ) assert response.status_code == 200 assert response.json() == { "id": audience.id, "name": audience.name, "vendorId": audience.vendor_id, "subaccountId": audience.subaccount_id, "fanDataListIds": [ { "id": audience.global_participant_id, "type": "ARTIST", } ], "target": audience.target, "countries": audience.countries, "fanSegments": audience.fan_segments, "filters": { "countries": audience.filters.countries, "excludeCountries": None, "crmCampaigns": audience.filters.crm_campaigns, "crmSublists": audience.filters.crm_sublists, "genres": audience.filters.genres, "fanLanguages": audience.filters.fan_languages, "birthMonths": audience.filters.birth_months, "cities": audience.filters.cities, "radius": audience.filters.radius, "radiusUnit": audience.filters.radius_unit, "spendMax": audience.filters.spend_max, "spendMin": audience.filters.spend_min, "heavyRotationV2": audience.filters.heavy_rotation_v2, "dsp": audience.filters.dsp, "lastEngagement": audience.filters.last_engagement, "fanSegments": audience.filters.fan_segments, "songwhipPresavePageIds": audience.filters.songwhip_presave_page_ids, "songwhipCampaignIds": audience.filters.songwhip_campaign_ids, "emailCampaigns": audience.filters.email_campaigns, "includeSecondaryFans": audience.filters.include_secondary_fans, "excludedFanDataLists": audience.filters.excluded_fan_data_lists, "regions": audience.filters.regions, }, "fanCount": audience.fan_count, "isArchived": audience.is_archived, "createdAt": IsISODatetime(audience.created_at), "createdBy": audience.created_by, "updatedAt": IsISODatetime(audience.updated_at), "updatedBy": audience.updated_by, "refreshedAt": IsISODatetimeOrNone(audience.refreshed_at), "refreshedBy": audience.refreshed_by, } @pytest.mark.db def test_update_audience_with_existing_name( client: TestClient, create_model: CreateModel ) -> None: name = "Test audience" create_model(Audience) audience = create_model(Audience, name=name) response = client.put( f"/audiences/{audience.id}", json={ "name": " test audience ", "target": audience.target, "filters": {}, }, ) assert response.status_code == 400 assert response.json() == { "code": "audience_unique_name", "message": "Audience name must be unique", } @pytest.mark.db def test_export_audience( client: TestClient, container: Container, create_model: CreateModel ) -> None: export = create_model(AudienceExport) handler_mock = mock.MagicMock(spec=ExportAudienceHandler) handler_mock.handle.return_value = export with container.override(ExportAudienceHandler, instance=handler_mock): response = client.post( f"/audiences/{export.audience_id}/exports", json={ "reason": "ADS_META", "justification": "OTHER", "reasonNotes": "test", }, ) assert response.status_code == 201 assert response.json() == { "id": export.id, "audienceId": export.audience_id, "audienceName": export.audience_name, "reason": export.reason, "justification": export.justification, "reasonNotes": export.reason_notes, "status": export.status, "createdBy": export.created_by, "createdAt": IsISODatetime(export.created_at), "updatedAt": IsISODatetime(export.updated_at), } @pytest.mark.db def test_get_audience_export( client: TestClient, container: Container, create_model: CreateModel, fake: FakerTyped, ) -> None: export = create_model(AudienceExport) presigned_url = fake.url() handler_mock = mock.MagicMock(spec=GetAudienceExportHandler) handler_mock.handle.return_value = GetAudienceExportResponse( export=export, presigned_url=presigned_url, ) with container.override(GetAudienceExportHandler, instance=handler_mock): response = client.get( f"/audiences/{export.audience_id}/exports/{export.id}", ) assert response.status_code == 200 assert response.json() == { "export": { "id": export.id, "audienceId": export.audience_id, "audienceName": export.audience_name, "reason": export.reason, "justification": export.justification, "reasonNotes": export.reason_notes, "status": export.status, "createdBy": export.created_by, "createdAt": IsISODatetime(export.created_at), "updatedAt": IsISODatetime(export.updated_at), }, "presignedUrl": presigned_url, } @pytest.mark.db @freeze_time("2021-01-01") def test_get_audience_size(client: TestClient, fake: FakerTyped) -> None: dt_now = timezone.now() response = client.post( "/audience-size", json={ "vendorId": fake.integer(), "subaccountId": 0, "fanDataListIds": [ { "id": fake.uuid4_string(), "type": "ARTIST", } ], "target": AudienceTarget.ADS, "filters": {}, }, ) assert response.status_code == 200 assert response.json() == { "size": 0, "createdAt": IsISODatetime(dt_now), } def test_get_audiences_artists( client: TestClient, container: Container, fake: FakerTyped ) -> None: global_participant_id_1 = fake.uuid4_string() global_participant_id_2 = fake.uuid4_string() handler_mock = mock.MagicMock(spec=GetAudiencesArtistsHandler) handler_mock.handle.return_value = [ global_participant_id_1, global_participant_id_2, ] with container.override(GetAudiencesArtistsHandler, handler_mock): response = client.get("/audiences-artists") assert response.status_code == 200 assert response.json() == [ {"id": global_participant_id_1}, {"id": global_participant_id_2}, ] @pytest.mark.db def test_update_audience_export(client: TestClient, create_model: CreateModel) -> None: export = create_model(AudienceExport, status=AudienceExportStatus.PROCESSING) response = client.patch( f"/audience-exports/{export.id}", json={"status": "COMPLETED", "zipKey": "test"}, ) assert response.status_code == 200 assert response.json() == { "id": export.id, "audienceId": export.audience_id, "audienceName": export.audience_name, "reason": export.reason.value, "justification": export.justification, "reasonNotes": export.reason_notes, "status": export.status, "createdBy": export.created_by, "createdAt": IsISODatetime(export.created_at), "updatedAt": IsISODatetime(export.updated_at), } @pytest.mark.db def test_update_audience_share(client: TestClient, create_model: CreateModel) -> None: share = create_model(AudienceShare, status=AudienceExportStatus.PENDING) response = client.patch( f"/audience-shares/{share.id}", json={ "status": "PROCESSING", "processedFans": 100, }, ) assert response.status_code == 200 assert response.json() == { "id": share.id, "platform": share.platform, "status": share.status, "fansCount": share.fans_count, "createdAt": IsISODatetime(share.created_at), } def test_get_audience_ad_accounts( client: TestClient, build_model: BuildModel, container: Container ) -> None: audience = build_model(Audience) ad_account = build_model(AudienceAdAccount, platform=AudienceSharePlatform.TIKTOK) ad_account_2 = build_model(AudienceAdAccount, platform=AudienceSharePlatform.META) handler_mock = mock.MagicMock(spec=GetAudienceAdAccountsHandler) handler_mock.handle.return_value = [ad_account, ad_account_2] with container.override(GetAudienceAdAccountsHandler, handler_mock): response = client.get(f"/audiences/{audience.id}/ad-accounts") assert response.status_code == 200 assert response.json() == [ { "id": ad_account.id, "name": ad_account.name, "platform": ad_account.platform, "isConnected": ad_account.is_connected, "isSelfConnected": ad_account.is_self_connected, "customAudienceTosAccepted": ad_account.custom_audience_tos_accepted, "customAudienceTosUrl": ad_account.custom_audience_tos_url, }, { "id": ad_account_2.id, "name": ad_account_2.name, "platform": ad_account_2.platform, "isConnected": ad_account_2.is_connected, "isSelfConnected": ad_account_2.is_self_connected, "customAudienceTosAccepted": ad_account_2.custom_audience_tos_accepted, "customAudienceTosUrl": ad_account_2.custom_audience_tos_url, }, ] @pytest.mark.db def test_create_audiences_target_text_mock( client: TestClient, fake: FakerTyped, graphql_router_client_mock: mock.MagicMock, enable_features: EnableFeatures, create_reporting_model: CreateReportingModel, ) -> None: name = "Test Audience" vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() target = AudienceTarget.TEXT countries = ["US", "EE"] graphql_router_client_mock.get_global_participant_by_gp_id.return_value = ( GlobalParticipant( id=global_participant_id, name="Test Artist", ) ) create_reporting_model( ArtistPhoneNumber, global_participant_id=global_participant_id ) with enable_features([AUDIENCE_SHOW_SMS_CAMPAIGNS_PAGE]): response = client.post( "/audiences", json={ "name": name, "vendorId": vendor_id, "subaccountId": subaccount_id, "fanDataListIds": [ { "id": global_participant_id, "type": "ARTIST", } ], "target": target, "filters": { "countries": countries, }, }, ) assert response.status_code == 201 @pytest.mark.db def test_create_audiences_target_text_phone_number_not_found_error( client: TestClient, fake: FakerTyped, graphql_router_client_mock: mock.MagicMock, enable_features: EnableFeatures, ) -> None: name = "Test Audience" vendor_id = fake.integer() subaccount_id = fake.integer() global_participant_id = fake.uuid4_string() target = AudienceTarget.TEXT countries = ["US", "EE"] graphql_router_client_mock.get_global_participant_by_gp_id.return_value = ( GlobalParticipant( id=global_participant_id, name="Test Artist", ) ) with enable_features([AUDIENCE_SHOW_SMS_CAMPAIGNS_PAGE]): response = client.post( "/audiences", json={ "name": name, "vendorId": vendor_id, "subaccountId": subaccount_id, "fanDataListIds": [ { "id": global_participant_id, "type": "ARTIST", } ], "target": target, "filters": { "countries": countries, }, }, ) assert response.status_code == 400 assert response.json() == { "code": "artist_phone_number_not_found", "message": "Artist phone number not found", } @pytest.mark.db def test_update_audience_target_text_mock( client: TestClient, create_model: CreateModel, create_reporting_model: CreateReportingModel, enable_features: EnableFeatures, fake: FakerTyped, ) -> None: global_participant_id = fake.uuid4_string() audience = create_model( Audience, fandata_lists=[ AudienceFanDataList( list_id=global_participant_id, type=FanDataListType.ARTIST, ) ], ) create_reporting_model( ArtistPhoneNumber, global_participant_id=global_participant_id ) with enable_features([AUDIENCE_SHOW_SMS_CAMPAIGNS_PAGE]): response = client.put( f"/audiences/{audience.id}", json={ "name": audience.name, "target": AudienceTarget.TEXT, "filters": {}, }, ) assert response.status_code == 200 @pytest.mark.db def test_update_audience_target_text_phone_number_not_found_error( client: TestClient, create_model: CreateModel, create_reporting_model: CreateReportingModel, enable_features: EnableFeatures, fake: FakerTyped, ) -> None: audience = create_model( Audience, fandata_lists=[ AudienceFanDataList( list_id=fake.uuid4_string(), type=FanDataListType.ARTIST, ) ], ) create_reporting_model(ArtistPhoneNumber, global_participant_id=fake.uuid4_string()) with enable_features([AUDIENCE_SHOW_SMS_CAMPAIGNS_PAGE]): response = client.put( f"/audiences/{audience.id}", json={ "name": audience.name, "target": AudienceTarget.TEXT, "filters": {}, }, ) assert response.status_code == 400 assert response.json() == { "code": "artist_phone_number_not_found", "message": "Artist phone number not found", } @pytest.mark.db def test_get_audience_size_target_text_mock( client: TestClient, fake: FakerTyped, enable_features: EnableFeatures, create_reporting_model: CreateReportingModel, ) -> None: global_participant_id = fake.uuid4_string() create_reporting_model( ArtistPhoneNumber, global_participant_id=global_participant_id ) with enable_features([AUDIENCE_SHOW_SMS_CAMPAIGNS_PAGE]): response = client.post( "/audience-size", json={ "vendorId": fake.integer(), "subaccountId": 0, "fanDataListIds": [ { "id": global_participant_id, "type": "ARTIST", } ], "target": AudienceTarget.TEXT, "filters": {}, }, ) assert response.status_code == 200 @pytest.mark.db def test_get_audience_size_target_text_phone_number_not_found_error( client: TestClient, fake: FakerTyped, enable_features: EnableFeatures, create_reporting_model: CreateReportingModel, ) -> None: create_reporting_model(ArtistPhoneNumber, global_participant_id=fake.uuid4_string()) with enable_features([AUDIENCE_SHOW_SMS_CAMPAIGNS_PAGE]): response = client.post( "/audience-size", json={ "vendorId": fake.integer(), "subaccountId": 0, "fanDataListIds": [ { "id": fake.uuid4_string(), "type": "ARTIST", } ], "target": AudienceTarget.TEXT, "filters": {}, }, ) assert response.status_code == 400 assert response.json() == { "code": "artist_phone_number_not_found", "message": "Artist phone number not found", } @pytest.mark.db def test_upsert_audience_fans(client: TestClient, create_model: CreateModel) -> None: audience = create_model( Audience, target=AudienceTarget.EMAIL, ) response = client.post( f"/audiences/{audience.id}/fans/upsert", ) assert response.status_code == 200 assert response.json() == { "fanCount": 0, }