"""Tests for site and site config CRUD endpoints and schemas.""" import uuid import pytest from pydantic import ValidationError from src.schemas.site import ( BlockingMode, SiteConfigCreate, SiteConfigResponse, SiteConfigUpdate, SiteCreate, SiteResponse, SiteUpdate, ) class TestSiteSchemas: def test_create_valid(self): site = SiteCreate(domain="example.com", display_name="Example Site") assert site.domain == "example.com" def test_create_empty_domain_rejected(self): with pytest.raises(ValidationError): SiteCreate(domain="", display_name="Test") def test_update_partial(self): update = SiteUpdate(display_name="New Name") data = update.model_dump(exclude_unset=True) assert data == {"display_name": "New Name"} def test_response_from_attributes(self): now = "2026-01-01T00:00:00Z" resp = SiteResponse( id=uuid.uuid4(), organisation_id=uuid.uuid4(), domain="example.com", display_name="Example", is_active=True, additional_domains=None, created_at=now, updated_at=now, ) assert resp.is_active class TestSiteConfigSchemas: def test_create_defaults(self): config = SiteConfigCreate() assert config.blocking_mode == BlockingMode.OPT_IN assert config.gcm_enabled is True assert config.tcf_enabled is False assert config.scan_max_pages == 50 assert config.consent_expiry_days == 365 def test_create_with_regional_modes(self): config = SiteConfigCreate( regional_modes={"EU": "opt_in", "US-CA": "opt_out", "DEFAULT": "opt_in"} ) assert config.regional_modes["EU"] == "opt_in" def test_scan_max_pages_bounds(self): with pytest.raises(ValidationError): SiteConfigCreate(scan_max_pages=0) with pytest.raises(ValidationError): SiteConfigCreate(scan_max_pages=1001) def test_consent_expiry_bounds(self): with pytest.raises(ValidationError): SiteConfigCreate(consent_expiry_days=0) with pytest.raises(ValidationError): SiteConfigCreate(consent_expiry_days=731) def test_update_partial(self): update = SiteConfigUpdate(blocking_mode=BlockingMode.OPT_OUT) data = update.model_dump(exclude_unset=True) assert data == {"blocking_mode": "opt_out"} def test_response_from_attributes(self): now = "2026-01-01T00:00:00Z" resp = SiteConfigResponse( id=uuid.uuid4(), site_id=uuid.uuid4(), blocking_mode="opt_in", regional_modes=None, tcf_enabled=False, tcf_publisher_cc=None, gcm_enabled=True, gcm_default=None, banner_config=None, privacy_policy_url=None, scan_schedule_cron=None, scan_max_pages=50, consent_expiry_days=365, created_at=now, updated_at=now, ) assert resp.blocking_mode == "opt_in" def test_display_mode_in_banner_config(self): """Display mode is stored inside banner_config, not as a top-level field.""" config = SiteConfigCreate( banner_config={"displayMode": "overlay"}, ) assert config.banner_config["displayMode"] == "overlay" class TestEnums: def test_blocking_modes(self): assert BlockingMode.OPT_IN == "opt_in" assert BlockingMode.OPT_OUT == "opt_out" assert BlockingMode.INFORMATIONAL == "informational" @pytest.mark.asyncio class TestSiteRoutesRegistered: async def test_site_routes_exist(self, client): response = await client.get("/openapi.json") paths = response.json()["paths"] assert "/api/v1/sites/" in paths assert "/api/v1/sites/{site_id}" in paths assert "/api/v1/sites/{site_id}/config" in paths async def test_site_endpoints_require_auth(self, client): response = await client.get("/api/v1/sites/") assert response.status_code == 401 async def test_site_config_endpoints_require_auth(self, client): site_id = uuid.uuid4() response = await client.get(f"/api/v1/sites/{site_id}/config") assert response.status_code == 401