import pytest from fansifter_common.auth.account import Account from ows_text_campaigns.api.schemas import AgeRange, Gender from ows_text_campaigns.campaigns.dtos import ( CampaignAnalyticsLocation, ) from ows_text_campaigns.campaigns.enums import LinkType from ows_text_campaigns.campaigns.handlers import ( GetCampaignLinkAnalyticsHandler, GetCampaignLinkAnalyticsRequest, ) from ows_text_campaigns.campaigns.models import ( Campaign, CampaignSendsCountryAggregated, CampaignUrlAttributes, TextAnalyticsBenchmarkByAccountArtist, UrlShortenerClicksCountryAggregated, UrlShortenerClicksGenderAgeAggregated, ) from tests.unit.types import CreateModel class TestGetCampaignLinkAnalyticsHandler: @pytest.mark.db def test_get_campaign_link_analytics_empty( self, handler: GetCampaignLinkAnalyticsHandler, create_model: CreateModel, identity_id: str, account: Account, ) -> None: campaign = create_model( Campaign, vendor_id=account.vendor_id, subaccount_id=account.subaccount_id, ) result = handler.handle( GetCampaignLinkAnalyticsRequest( identity_id=identity_id, campaign_id=campaign.id, vendor_id=account.vendor_id, subaccount_id=account.subaccount_id, ) ) assert result == [] @pytest.mark.db def test_get_campaign_link_analytics_no_links( self, handler: GetCampaignLinkAnalyticsHandler, create_model: CreateModel, identity_id: str, account: Account, ) -> None: campaign = create_model( Campaign, vendor_id=account.vendor_id, subaccount_id=account.subaccount_id, content="Hello, world!", ) create_model( CampaignSendsCountryAggregated, campaign_id=campaign.id, ) result = handler.handle( GetCampaignLinkAnalyticsRequest( identity_id=identity_id, campaign_id=campaign.id, vendor_id=account.vendor_id, subaccount_id=account.subaccount_id, ) ) assert result == [] @pytest.mark.db def test_get_campaign_link_analytics_no_clicks( self, handler: GetCampaignLinkAnalyticsHandler, create_model: CreateModel, identity_id: str, account: Account, ) -> None: url = "https://example.com/" campaign = create_model( Campaign, vendor_id=account.vendor_id, subaccount_id=account.subaccount_id, content=f""" short_link """, ) create_model( CampaignSendsCountryAggregated, campaign_id=campaign.id, sends=10, country_code="US", ) result = handler.handle( GetCampaignLinkAnalyticsRequest( identity_id=identity_id, campaign_id=campaign.id, vendor_id=account.vendor_id, subaccount_id=account.subaccount_id, ) ) assert len(result) == 1 url_analytics = result[0] assert url_analytics.url == url assert url_analytics.link_type == LinkType.PERSONALIZED assert url_analytics.total_sends == 10 assert url_analytics.total_clicks == 0 assert url_analytics.clickthrough_rate == 0 assert url_analytics.clickthrough_rate_change is None assert url_analytics.demographics is not None assert url_analytics.locations is not None assert len(url_analytics.locations) == 1 assert url_analytics.locations[0] == CampaignAnalyticsLocation( country_code="US", sends=10, clicks=0, ) @pytest.mark.db def test_get_campaign_link_analytics_personalized_link( self, handler: GetCampaignLinkAnalyticsHandler, create_model: CreateModel, identity_id: str, account: Account, ) -> None: url = "https://example.com/" campaign = create_model( Campaign, vendor_id=account.vendor_id, subaccount_id=account.subaccount_id, content=f""" short_link """, ) create_model( CampaignSendsCountryAggregated, campaign_id=campaign.id, sends=10, country_code="US", ) create_model( CampaignSendsCountryAggregated, campaign_id=campaign.id, sends=10, country_code="DE", ) create_model( UrlShortenerClicksGenderAgeAggregated, campaign_id=campaign.id, redirect_url=url, gender=Gender.MALE, age_range=AgeRange.FROM_18_TO_22, clicks=1, ) create_model( UrlShortenerClicksGenderAgeAggregated, campaign_id=campaign.id, redirect_url=url, gender=Gender.FEMALE, age_range=AgeRange.FROM_23_TO_30, clicks=2, ) create_model( UrlShortenerClicksCountryAggregated, campaign_id=campaign.id, redirect_url=url, country_code="US", clicks=2, ) create_model( UrlShortenerClicksCountryAggregated, campaign_id=campaign.id, redirect_url=url, country_code="DE", clicks=1, ) create_model( CampaignUrlAttributes, campaign_id=campaign.id, redirect_url=url, is_personalized=True, ) result = handler.handle( GetCampaignLinkAnalyticsRequest( identity_id=identity_id, campaign_id=campaign.id, vendor_id=account.vendor_id, subaccount_id=account.subaccount_id, ) ) assert len(result) == 1 url_analytics = result[0] assert url_analytics.url == url assert url_analytics.link_type == LinkType.PERSONALIZED assert url_analytics.total_sends == 20 assert url_analytics.total_clicks == 3 assert url_analytics.clickthrough_rate == 0.15 assert url_analytics.clickthrough_rate_change is None assert url_analytics.demographics is not None assert url_analytics.demographics.available_fans_share == 1 # 4 because we generate objects for all genders even if there are no clicks assert len(url_analytics.demographics.data) == 4 demographics_male = url_analytics.demographics.data[0] assert demographics_male.id == Gender.MALE assert demographics_male.total == 1 assert demographics_male.items is not None assert demographics_male.items[1].label == AgeRange.FROM_18_TO_22 assert demographics_male.items[1].value == 1 demographics_female = url_analytics.demographics.data[1] assert demographics_female.id == Gender.FEMALE assert demographics_female.total == 2 assert demographics_female.items is not None assert demographics_female.items[2].label == AgeRange.FROM_23_TO_30 assert demographics_female.items[2].value == 2 assert url_analytics.locations is not None assert len(url_analytics.locations) == 2 assert url_analytics.locations[0] == CampaignAnalyticsLocation( country_code="US", sends=10, clicks=2, ) assert url_analytics.locations[1] == CampaignAnalyticsLocation( country_code="DE", sends=10, clicks=1, ) @pytest.mark.db def test_get_campaign_link_analytics_non_personalized_link( self, handler: GetCampaignLinkAnalyticsHandler, create_model: CreateModel, identity_id: str, account: Account, ) -> None: url = "https://example.com/" campaign = create_model( Campaign, vendor_id=account.vendor_id, subaccount_id=account.subaccount_id, content=f""" short_link """, ) create_model( CampaignSendsCountryAggregated, campaign_id=campaign.id, sends=10, country_code="US", ) create_model( CampaignSendsCountryAggregated, campaign_id=campaign.id, sends=10, country_code="DE", ) create_model( UrlShortenerClicksGenderAgeAggregated, campaign_id=campaign.id, redirect_url=url, gender=None, age_range=None, clicks=3, ) create_model( UrlShortenerClicksCountryAggregated, campaign_id=campaign.id, redirect_url=url, country_code="US", clicks=2, ) create_model( UrlShortenerClicksCountryAggregated, campaign_id=campaign.id, redirect_url=url, country_code="DE", clicks=1, ) create_model( CampaignUrlAttributes, campaign_id=campaign.id, redirect_url=url, is_personalized=False, ) result = handler.handle( GetCampaignLinkAnalyticsRequest( identity_id=identity_id, campaign_id=campaign.id, vendor_id=account.vendor_id, subaccount_id=account.subaccount_id, ) ) assert len(result) == 1 url_analytics = result[0] assert url_analytics.url == url assert url_analytics.link_type == LinkType.STANDARD assert url_analytics.total_sends == 20 assert url_analytics.total_clicks == 3 assert url_analytics.clickthrough_rate == 0.15 assert url_analytics.clickthrough_rate_change is None assert url_analytics.demographics is None assert url_analytics.locations is not None assert len(url_analytics.locations) == 2 assert url_analytics.locations[0] == CampaignAnalyticsLocation( country_code="US", sends=10, clicks=2, ) assert url_analytics.locations[1] == CampaignAnalyticsLocation( country_code="DE", sends=10, clicks=1, ) @pytest.mark.db def test_get_campaign_link_analytics_long_link( self, handler: GetCampaignLinkAnalyticsHandler, create_model: CreateModel, identity_id: str, account: Account, ) -> None: url = "https://example.com/" campaign = create_model( Campaign, vendor_id=account.vendor_id, subaccount_id=account.subaccount_id, content=f'long_link', ) create_model( CampaignSendsCountryAggregated, campaign_id=campaign.id, sends=10, country_code="US", ) result = handler.handle( GetCampaignLinkAnalyticsRequest( identity_id=identity_id, campaign_id=campaign.id, vendor_id=account.vendor_id, subaccount_id=account.subaccount_id, ) ) assert len(result) == 1 url_analytics = result[0] assert url_analytics.url == url assert url_analytics.link_type == LinkType.LONG assert url_analytics.total_sends == 10 assert url_analytics.total_clicks is None assert url_analytics.clickthrough_rate is None assert url_analytics.clickthrough_rate_change is None assert url_analytics.demographics is None assert url_analytics.locations is not None assert len(url_analytics.locations) == 1 assert url_analytics.locations[0] == CampaignAnalyticsLocation( country_code="US", sends=10, clicks=None, ) @pytest.mark.db def test_get_campaign_link_analytics_multiple_links( self, handler: GetCampaignLinkAnalyticsHandler, create_model: CreateModel, identity_id: str, account: Account, ) -> None: url_1 = "https://example.com/1" url_2 = "https://example.com/2" campaign = create_model( Campaign, vendor_id=account.vendor_id, subaccount_id=account.subaccount_id, content=f""" short_link_1 short_link_2 """, ) create_model( CampaignSendsCountryAggregated, campaign_id=campaign.id, sends=10, country_code="US", ) create_model( UrlShortenerClicksGenderAgeAggregated, campaign_id=campaign.id, redirect_url=url_1, gender=Gender.MALE, age_range=AgeRange.FROM_18_TO_22, clicks=1, ) create_model( UrlShortenerClicksGenderAgeAggregated, campaign_id=campaign.id, redirect_url=url_2, gender=Gender.FEMALE, age_range=AgeRange.FROM_23_TO_30, clicks=2, ) create_model( UrlShortenerClicksGenderAgeAggregated, campaign_id=campaign.id, redirect_url=url_2, gender=Gender.MALE, age_range=None, clicks=2, ) create_model( UrlShortenerClicksCountryAggregated, campaign_id=campaign.id, redirect_url=url_1, country_code="US", clicks=1, ) create_model( UrlShortenerClicksCountryAggregated, campaign_id=campaign.id, redirect_url=url_2, country_code="US", clicks=4, ) create_model( CampaignUrlAttributes, campaign_id=campaign.id, redirect_url=url_1, is_personalized=True, ) create_model( CampaignUrlAttributes, campaign_id=campaign.id, redirect_url=url_2, is_personalized=True, ) result = handler.handle( GetCampaignLinkAnalyticsRequest( identity_id=identity_id, campaign_id=campaign.id, vendor_id=account.vendor_id, subaccount_id=account.subaccount_id, ) ) assert len(result) == 2 url_1_analytics = result[0] assert url_1_analytics.url == url_1 assert url_1_analytics.link_type == LinkType.PERSONALIZED assert url_1_analytics.total_sends == 10 assert url_1_analytics.total_clicks == 1 assert url_1_analytics.clickthrough_rate == 0.1 assert url_1_analytics.clickthrough_rate_change is None assert url_1_analytics.demographics is not None assert url_1_analytics.demographics.available_fans_share == 1 # 4 because we generate objects for all genders even if there are no clicks assert len(url_1_analytics.demographics.data) == 4 demographics_male = url_1_analytics.demographics.data[0] assert demographics_male.id == Gender.MALE assert demographics_male.total == 1 assert demographics_male.items is not None assert demographics_male.items[1].label == AgeRange.FROM_18_TO_22 assert demographics_male.items[1].value == 1 assert url_1_analytics.locations is not None assert len(url_1_analytics.locations) == 1 assert url_1_analytics.locations[0] == CampaignAnalyticsLocation( country_code="US", sends=10, clicks=1, ) url_2_analytics = result[1] assert url_2_analytics.url == url_2 assert url_2_analytics.link_type == LinkType.PERSONALIZED assert url_2_analytics.total_sends == 10 assert url_2_analytics.total_clicks == 4 assert url_2_analytics.clickthrough_rate == 0.4 assert url_2_analytics.clickthrough_rate_change is None assert url_2_analytics.demographics is not None assert url_2_analytics.demographics.available_fans_share == 0.5 # 4 because we generate objects for all genders even if there are no clicks assert len(url_2_analytics.demographics.data) == 4 demographics_female = url_2_analytics.demographics.data[1] assert demographics_female.id == Gender.FEMALE assert demographics_female.total == 2 assert demographics_female.items is not None assert demographics_female.items[2].label == AgeRange.FROM_23_TO_30 assert demographics_female.items[2].value == 2 assert url_2_analytics.locations is not None assert len(url_2_analytics.locations) == 1 assert url_2_analytics.locations[0] == CampaignAnalyticsLocation( country_code="US", sends=10, clicks=4, ) @pytest.mark.db def test_get_campaign_link_analytics_rate_change( self, handler: GetCampaignLinkAnalyticsHandler, create_model: CreateModel, identity_id: str, account: Account, ) -> None: url = "https://example.com/" campaign = create_model( Campaign, vendor_id=account.vendor_id, subaccount_id=account.subaccount_id, content=f""" short_link """, ) create_model( CampaignSendsCountryAggregated, campaign_id=campaign.id, sends=10, country_code="US", ) create_model( UrlShortenerClicksGenderAgeAggregated, campaign_id=campaign.id, redirect_url=url, gender=Gender.MALE, age_range=AgeRange.FROM_18_TO_22, clicks=5, ) create_model( UrlShortenerClicksCountryAggregated, campaign_id=campaign.id, redirect_url=url, country_code="US", clicks=5, ) create_model( CampaignUrlAttributes, campaign_id=campaign.id, redirect_url=url, is_personalized=True, ) create_model( TextAnalyticsBenchmarkByAccountArtist, vendor_id=account.vendor_id, subaccount_id=account.subaccount_id, global_participant_id=campaign.global_participant_id, avg_click_through_rate=1, ) result = handler.handle( GetCampaignLinkAnalyticsRequest( identity_id=identity_id, campaign_id=campaign.id, vendor_id=account.vendor_id, subaccount_id=account.subaccount_id, ) ) assert len(result) == 1 url_analytics = result[0] assert url_analytics.clickthrough_rate == 0.5 assert url_analytics.clickthrough_rate_change == -0.5