from unittest import mock import faker import pytest from anydi import Container from faker import Faker from fansifter_common.auth.account import Account from fansifter_common.utils import timezone from ows_text_campaigns.audiences.enums import AudienceTarget, FanDataListType from ows_text_campaigns.audiences.exceptions import ( ArchivedAudienceError, EmptyAudienceError, InvalidAudienceArtistError, NotSupportedAudienceTargetError, ) from ows_text_campaigns.audiences.models import Audience, AudienceFanDataList from ows_text_campaigns.campaigns.enums import ShorteningMethod from ows_text_campaigns.campaigns.exceptions import ( CampaignUniqueNameError, InvalidUrlDomainIdError, ShorteningPathIsNotAvailableError, ) from ows_text_campaigns.campaigns.models import Campaign, UrlDomain from ows_text_campaigns.campaigns.services import UrlDomainService from ows_text_campaigns.campaigns.validators import ( CampaignValidator, ShortenedUrlValidator, ) from tests.unit.types import CreateModel, CreatePgModel class TestCampaignValidator: @pytest.mark.db def test_validate_name(self, validator: CampaignValidator) -> None: validator.validate_name( name="Test Campaign", account=Account(vendor_id=10, subaccount_id=0) ) assert True @pytest.mark.db def test_validate_name_existing( self, validator: CampaignValidator, create_model: CreateModel ) -> None: campaign = create_model(Campaign) validator.validate_name( name=campaign.name, account=campaign.account, campaign=campaign, ) assert True @pytest.mark.db def test_validate_name_invalid( self, validator: CampaignValidator, create_model: CreateModel ) -> None: campaign = create_model(Campaign) with pytest.raises(CampaignUniqueNameError): validator.validate_name(name=campaign.name, account=campaign.account) @pytest.mark.db def test_validate_audience_success( self, validator: CampaignValidator, create_pg_model: CreatePgModel ) -> None: audience = create_pg_model( Audience, archived_at=None, target=AudienceTarget.TEXT, fan_count=100, fandata_lists=[ AudienceFanDataList(type=FanDataListType.ARTIST, list_id="test-list-id") ], ) validator.validate_audience(audience) assert True @pytest.mark.db def test_validate_audience_success_missing_artist( self, validator: CampaignValidator, create_pg_model: CreatePgModel ) -> None: audience = create_pg_model( Audience, archived_at=None, target=AudienceTarget.TEXT, fan_count=100, fandata_lists=[], ) with pytest.raises(InvalidAudienceArtistError): validator.validate_audience(audience) @pytest.mark.db def test_validate_audience_archived( self, validator: CampaignValidator, create_pg_model: CreatePgModel, faker: faker.Faker, ) -> None: audience = create_pg_model( Audience, archived_at=faker.past_datetime(tzinfo=timezone.UTC) ) with pytest.raises(ArchivedAudienceError): validator.validate_audience(audience) @pytest.mark.db def test_validate_audience_invalid( self, validator: CampaignValidator, create_pg_model: CreatePgModel ) -> None: audience = create_pg_model( Audience, archived_at=None, target=AudienceTarget.EMAIL ) with pytest.raises(NotSupportedAudienceTargetError): validator.validate_audience(audience) @pytest.mark.db def test_validate_audience_empty( self, validator: CampaignValidator, create_pg_model: CreatePgModel ) -> None: audience = create_pg_model( Audience, archived_at=None, target=AudienceTarget.TEXT, fan_count=0, fandata_lists=[ AudienceFanDataList(type=FanDataListType.ARTIST, list_id="test-list-id") ], ) with pytest.raises(EmptyAudienceError): validator.validate_audience(audience) class TestShortenedUrlValidator: def test_validate_availability_non_standard( self, validator: ShortenedUrlValidator, ows_url_shortener_client_mock: mock.MagicMock, ) -> None: validator.validate_availability( method=ShorteningMethod.PERSONALIZED, path="test-path", ) ows_url_shortener_client_mock.check_path.assert_not_called() def test_validate_availability_available( self, validator: ShortenedUrlValidator, ows_url_shortener_client_mock: mock.MagicMock, ) -> None: ows_url_shortener_client_mock.check_path.return_value = True validator.validate_availability( method=ShorteningMethod.STANDARD, path="test-path", ) ows_url_shortener_client_mock.check_path.assert_called_once_with("test-path") def test_validate_availability_not_available( self, validator: ShortenedUrlValidator, ows_url_shortener_client_mock: mock.MagicMock, ) -> None: ows_url_shortener_client_mock.check_path.return_value = False with pytest.raises(ShorteningPathIsNotAvailableError): validator.validate_availability( method=ShorteningMethod.STANDARD, path="test-path", ) ows_url_shortener_client_mock.check_path.assert_called_once_with("test-path") @pytest.mark.db def test_validate_allowed_domain( self, container: Container, validator: ShortenedUrlValidator, create_model: CreateModel, identity_id: str, account: Account, ) -> None: url_domain = create_model(UrlDomain) url_domain_service_mock = mock.MagicMock(spec=UrlDomainService) url_domain_service_mock.get_allowed_domains.return_value = [url_domain] with container.override(UrlDomainService, url_domain_service_mock): result = validator.validate_allowed_domain( identity_id=identity_id, account=account, domain=url_domain.domain, ) assert result == url_domain @pytest.mark.db def test_validate_allowed_domain_invalid( self, container: Container, validator: ShortenedUrlValidator, identity_id: str, account: Account, faker: Faker, ) -> None: url_domain_service_mock = mock.MagicMock(spec=UrlDomainService) url_domain_service_mock.get_allowed_domains.return_value = [] with ( container.override(UrlDomainService, url_domain_service_mock), pytest.raises(InvalidUrlDomainIdError), ): validator.validate_allowed_domain( identity_id=identity_id, account=account, domain=faker.uuid4(), )