import uuid from typing import Any, Dict, Optional from unittest.mock import AsyncMock, MagicMock, call, patch from uuid import UUID import pytest from pdp.constants.constants import TenantType from pdp.fastapi.schemas.get_allowed_tenants import ( AllowedTenant, GetAllowedTenantsRequest, GetAllowedTenantsResponse, ) from pdp.fastapi.schemas.tenant import IdExchangeTenantHierarchy, Tenant @pytest.mark.parametrize( "payload, expect_exception, expected", [ pytest.param({}, True, None, id="empty dict is not valid"), pytest.param({"resource_type": "dog"}, True, None, id="action is required"), pytest.param({"action": "view"}, True, None, id="resource_type is required"), pytest.param( { "resource_type": "dog", "action": "", }, True, None, id="action cannot be empty string", ), pytest.param( { "resource_type": "", "action": "view", }, True, None, id="resource_type cannot be empty string", ), pytest.param( { "resource_type": "dog", "action": "view", }, False, { "resource_type": "dog", "action": "view", }, id="resource_type and action are present", ), ], ) def test_get_allowed_tenants_request_model_validate( payload: Any, expect_exception: bool, expected: Dict[str, Any], ) -> None: """Parametrized testing of GetAllowedTenantsRequest schema.""" if expect_exception: with pytest.raises(Exception): GetAllowedTenantsRequest.model_validate(payload) else: actual = GetAllowedTenantsRequest.model_validate(payload) assert actual == GetAllowedTenantsRequest(**expected) @pytest.mark.parametrize( "payload, expect_exception, expected", [ pytest.param({}, True, None, id="empty dict is not valid"), pytest.param( {"resource_type": "dog", "tenants": []}, True, None, id="action is required", ), pytest.param( {"action": "view", "tenants": []}, True, None, id="resource_type is required", ), pytest.param( {"action": "view", "resource_type": "dog"}, True, None, id="tenants is required", ), pytest.param( { "resource_type": "dog", "action": "", "tenants": [], }, True, None, id="action cannot be empty string", ), pytest.param( { "resource_type": "", "action": "view", "tenants": [], }, True, None, id="resource_type cannot be empty string", ), pytest.param( { "resource_type": "dog", "action": "view", "tenants": [], }, False, { "resource_type": "dog", "action": "view", "tenants": [], }, id="all required fields are present", ), pytest.param( { "resource_type": "dog", "action": "view", "tenants": [ { "tenant_type": "account", "tenant_uuid": UUID("89b79b52-de18-4644-bd2b-bd28fdbeebaa"), } ], }, False, { "resource_type": "dog", "action": "view", "tenants": [ { "tenant_type": "account", "tenant_uuid": "89b79b52-de18-4644-bd2b-bd28fdbeebaa", } ], }, id="tenant schema is used/validated", ), pytest.param( { "resource_type": "dog", "action": "view", "tenants": [ { "tenant_type": "account", "tenant_uuid": UUID("89b79b52-de18-4644-bd2b-bd28fdbeebaa"), "tenant_id": 123, "company_brand": { "tenant_type": "company_brand", "tenant_uuid": UUID("9b2b7698-be33-4426-9644-e58c9c708027"), }, } ], }, False, { "resource_type": "dog", "action": "view", "tenants": [ { "tenant_type": "account", "tenant_uuid": "89b79b52-de18-4644-bd2b-bd28fdbeebaa", "tenant_id": 123, "company_brand": { "tenant_type": "company_brand", "tenant_uuid": "9b2b7698-be33-4426-9644-e58c9c708027", }, } ], }, id="IdExchangeTenantHierarchy schema is used/validated", ), ], ) def test_get_allowed_tenants_response_model_validate( payload: Any, expect_exception: bool, expected: Dict[str, Any], ) -> None: """Parametrized testing of GetAllowedTenantsResponse schema.""" if expect_exception: with pytest.raises(Exception): GetAllowedTenantsResponse.model_validate(payload) else: actual = GetAllowedTenantsResponse.model_validate(payload) assert actual == GetAllowedTenantsResponse(**expected) @patch("pdp.fastapi.schemas.get_allowed_tenants.UuidToIdExchangeTenantProxy") @patch("pdp.fastapi.schemas.get_allowed_tenants.RedisConnector") @patch("pdp.fastapi.schemas.get_allowed_tenants.OwsAccountClient") async def test_get_allowed_tenants_response_update_with_uuid_to_id_exchange( mock_ows_account_client: MagicMock, mock_redis_connector: MagicMock, mock_proxy: MagicMock, tenant_1_uuid: uuid.UUID, tenant_1_uuid_as_string: str, ) -> None: """Test it""" company_brand_uuid = uuid.uuid4() unexchanged_tenant = AllowedTenant( tenant_type=TenantType.TENANT_TYPE_LABEL_PARTICIPANT, tenant_uuid=uuid.uuid4(), ) exchangeable_tenant = AllowedTenant( tenant_type=TenantType.TENANT_TYPE_ACCOUNT, tenant_uuid=tenant_1_uuid, ) exchanged_tenant = IdExchangeTenantHierarchy( tenant_id=789, company_brand=Tenant( tenant_type=TenantType.TENANT_TYPE_COMPANY_BRAND, tenant_uuid=company_brand_uuid, ), tenant_type=exchangeable_tenant.tenant_type, tenant_uuid=exchangeable_tenant.tenant_uuid, ) def mock_get_tenant_exchange( uuid: uuid.UUID, ) -> Optional[IdExchangeTenantHierarchy]: if str(uuid) == tenant_1_uuid_as_string: return exchanged_tenant return None mock_proxy.return_value.gather_tenant_exchange = AsyncMock() mock_proxy.return_value.get_tenant_exchange = MagicMock( side_effect=mock_get_tenant_exchange ) response = GetAllowedTenantsResponse( resource_type="food", action="eat", tenants=[ unexchanged_tenant, exchangeable_tenant, ], ) await response.update_with_uuid_to_id_exchange( mock_redis_connector, mock_ows_account_client ) mock_proxy.assert_called_once_with( tenants=[unexchanged_tenant, exchangeable_tenant], redis_connector=mock_redis_connector, ows_account_client=mock_ows_account_client, ) mock_proxy.return_value.gather_tenant_exchange.assert_called_once() mock_proxy.return_value.get_tenant_exchange.assert_has_calls( [ call(unexchanged_tenant.tenant_uuid), call(exchangeable_tenant.tenant_uuid), ] ) assert response.tenants == [ AllowedTenant(**unexchanged_tenant.model_dump()), AllowedTenant(**exchanged_tenant.model_dump()), ]