import datetime import httpx import pytest from owsclient import OwsClient from owsclient.test import OwsClientMock from app.adapters.ows_text_campaigns import OwsTextCampaignsClient from app.types import CampaignSendCountry, CampaignSendTimezone from tests.unit.helpers import build_model class TestOwsTextCampaignsClient: @pytest.fixture(scope="class") @classmethod def ows_client(cls) -> OwsClient: return OwsClient(environment="test", service_name="ows-text-campaigns") @pytest.fixture(scope="class") @classmethod def client(cls, ows_client: OwsClient) -> OwsTextCampaignsClient: return OwsTextCampaignsClient(ows_client=ows_client) def test_get_send_timezones_calls_the_correct_endpoint( self, client: OwsTextCampaignsClient, ows_client_mock: OwsClientMock ) -> None: send_at = datetime.datetime(2026, 7, 8, 10, 0, tzinfo=datetime.UTC) route = ows_client_mock.get( "ows-text-campaigns", path="/campaigns/campaign-1/send-timezones", params={"sendAt": send_at.isoformat()}, ).mock(httpx.Response(status_code=200, json={"countries": []})) client.get_send_timezones(campaign_id="campaign-1", send_at=send_at) assert route.called def test_get_send_timezones_returns_empty_list_when_no_countries( self, client: OwsTextCampaignsClient, ows_client_mock: OwsClientMock ) -> None: send_at = datetime.datetime.now(datetime.UTC) ows_client_mock.get( "ows-text-campaigns", path="/campaigns/campaign-1/send-timezones", params={"sendAt": send_at.isoformat()}, ).mock(httpx.Response(status_code=200, json={"countries": []})) countries = client.get_send_timezones(campaign_id="campaign-1", send_at=send_at) assert countries == [] def test_get_send_timezones_parses_countries_and_timezones( self, client: OwsTextCampaignsClient, ows_client_mock: OwsClientMock ) -> None: send_at = datetime.datetime.now(datetime.UTC) payload = { "countryCode": "US", "timezones": [ build_model(CampaignSendTimezone).model_dump(by_alias=True, mode="json") ], } ows_client_mock.get( "ows-text-campaigns", path="/campaigns/campaign-1/send-timezones", params={"sendAt": send_at.isoformat()}, ).mock(httpx.Response(status_code=200, json={"countries": [payload]})) countries = client.get_send_timezones(campaign_id="campaign-1", send_at=send_at) assert countries == [CampaignSendCountry.model_validate(payload)] assert countries[0].country_code == "US" assert countries[0].timezones[0].iana_tz_id == "America/New_York" assert countries[0].timezones[0].state_provinces == ["NY"] def test_get_send_timezones_parses_multiple_countries( self, client: OwsTextCampaignsClient, ows_client_mock: OwsClientMock ) -> None: send_at = datetime.datetime.now(datetime.UTC) ows_client_mock.get( "ows-text-campaigns", path="/campaigns/campaign-1/send-timezones", params={"sendAt": send_at.isoformat()}, ).mock( httpx.Response( status_code=200, json={ "countries": [ { "countryCode": "US", "timezones": [ build_model(CampaignSendTimezone).model_dump( by_alias=True, mode="json" ) ], }, { "countryCode": "CA", "timezones": [ build_model( CampaignSendTimezone, ianaTzId="America/Toronto" ).model_dump(by_alias=True, mode="json") ], }, ] }, ) ) countries = client.get_send_timezones(campaign_id="campaign-1", send_at=send_at) assert [country.country_code for country in countries] == ["US", "CA"] def test_is_sendable_true_when_in_safe_hours(self) -> None: timezone = CampaignSendCountry.model_validate( { "countryCode": "US", "timezones": [ build_model( CampaignSendTimezone, isInSafeHours=True, isAdjusted=False ).model_dump(by_alias=True, mode="json") ], } ).timezones[0] assert timezone.is_sendable def test_is_sendable_true_when_adjusted_despite_unsafe_hours(self) -> None: timezone = CampaignSendCountry.model_validate( { "countryCode": "US", "timezones": [ build_model( CampaignSendTimezone, isInSafeHours=False, isAdjusted=True ).model_dump(by_alias=True, mode="json") ], } ).timezones[0] assert timezone.is_sendable def test_is_sendable_false_when_unsafe_and_not_adjusted(self) -> None: timezone = CampaignSendCountry.model_validate( { "countryCode": "US", "timezones": [ build_model( CampaignSendTimezone, isInSafeHours=False, isAdjusted=False ).model_dump(by_alias=True, mode="json") ], } ).timezones[0] assert not timezone.is_sendable