Loading src/open_exposure_gateway/api/camara/edge_application_management/v0_1_0_alpha_1/router.py +13 −12 Changes for src/open_exposure_gateway/api/camara/edge_application_management/v0_1_0_alpha_1/router.py: 13 added lines, 12 removed lines. Original line number Diff line number Diff line from typing import Annotated, Any, Optional from uuid import UUID, uuid4 from uuid import uuid4 from fastapi import APIRouter, Depends, Query, Request, Response, status Loading @@ -10,6 +10,7 @@ from open_exposure_gateway.api.camara.edge_application_management.v0_1_0_alpha_1 AppInstanceInfo, AppManifest, AppManifestEnvelope, CamaraUuid, CreateAppDeploymentRequest, CreateAppInstanceRequest, EdgeCloudZone, Loading Loading @@ -130,7 +131,7 @@ async def get_apps( ), ) async def get_app( appId: UUID, appId: CamaraUuid, service: EdgeAppService, caller: Caller, ) -> Any: Loading Loading @@ -182,7 +183,7 @@ async def submit_app( ), ) async def delete_app( appId: UUID, appId: CamaraUuid, service: EdgeAppService, caller: Caller, ) -> Response: Loading Loading @@ -248,8 +249,8 @@ async def create_app_instance( async def get_app_instances( service: EdgeAppService, caller: Caller, appId: Annotated[Optional[UUID], Query()] = None, appInstanceId: Annotated[Optional[UUID], Query()] = None, appId: Annotated[Optional[CamaraUuid], Query()] = None, appInstanceId: Annotated[Optional[CamaraUuid], Query()] = None, region: Annotated[Optional[str], Query(max_length=64)] = None, ) -> Any: return await service.get_app_instances( Loading @@ -274,7 +275,7 @@ async def get_app_instances( ), ) async def delete_app_instance( appInstanceId: UUID, appInstanceId: CamaraUuid, service: EdgeAppService, caller: Caller, ) -> Response: Loading Loading @@ -337,8 +338,8 @@ async def create_app_deployment( async def get_app_deployments( service: EdgeAppService, caller: Caller, appId: Annotated[Optional[UUID], Query()] = None, appDeploymentId: Annotated[Optional[UUID], Query()] = None, appId: Annotated[Optional[CamaraUuid], Query()] = None, appDeploymentId: Annotated[Optional[CamaraUuid], Query()] = None, ) -> Any: return await service.get_app_deployments( app_id=appId, Loading @@ -361,7 +362,7 @@ async def get_app_deployments( ), ) async def delete_app_deployment( appDeploymentId: UUID, appDeploymentId: CamaraUuid, service: EdgeAppService, caller: Caller, ) -> Response: Loading @@ -387,7 +388,7 @@ async def delete_app_deployment( DownstreamServiceException(), ), ) async def update_app_deployment(appDeploymentId: UUID) -> Any: async def update_app_deployment(appDeploymentId: CamaraUuid) -> Any: raise NotImplementedException(message="Deployment update is not implemented") Loading @@ -405,7 +406,7 @@ async def update_app_deployment(appDeploymentId: UUID) -> Any: ) async def get_clusters( region: Annotated[Optional[str], Query(max_length=64)] = None, clusterRef: Annotated[Optional[UUID], Query()] = None, edgeCloudZoneId: Annotated[Optional[UUID], Query()] = None, clusterRef: Annotated[Optional[CamaraUuid], Query()] = None, edgeCloudZoneId: Annotated[Optional[CamaraUuid], Query()] = None, ) -> Any: raise NotImplementedException(message="Cluster catalog is not implemented") src/open_exposure_gateway/api/camara/edge_application_management/v0_1_0_alpha_1/schemas.py +29 −9 Changes for src/open_exposure_gateway/api/camara/edge_application_management/v0_1_0_alpha_1/schemas.py: 29 added lines, 9 removed lines. Original line number Diff line number Diff line import re from datetime import datetime from enum import StrEnum from typing import Any, Literal, Optional from typing import Annotated, Any, Literal, Optional from uuid import UUID from pydantic import BaseModel, ConfigDict, Field, field_validator from pydantic import BaseModel, BeforeValidator, ConfigDict, Field, field_validator # Pattern shared by AppId, AppInstanceId, AppDeploymentId, EdgeCloudZoneId and # KubernetesClusterRef in the spec: lowercase, hyphenated, version 1-5, RFC variant. _CAMARA_UUID_PATTERN = re.compile( r"^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" ) def _check_camara_uuid(value: Any) -> Any: # pydantic's UUID alone also accepts uppercase, unhyphenated, urn:uuid:, braced, # nil and version-0 forms, all of which the spec pattern rejects. text = str(value) if isinstance(value, UUID) else value if not isinstance(text, str) or not _CAMARA_UUID_PATTERN.fullmatch(text): raise ValueError(f"must match pattern {_CAMARA_UUID_PATTERN.pattern}") return value # Input-side UUID for EAM request bodies, path and query params. Still a UUID downstream. CamaraUuid = Annotated[UUID, BeforeValidator(_check_camara_uuid)] class AppInstanceStatus(StrEnum): Loading Loading @@ -215,7 +235,7 @@ RequiredResources = VmResources | ContainerResources | DockerComposeResources | class AppManifest(BaseModel): model_config = ConfigDict(extra="forbid") appId: Optional[UUID] = None appId: Optional[CamaraUuid] = None name: str = Field(max_length=64, pattern=r"^[A-Za-z][A-Za-z0-9_]{1,63}$") appProvider: str = Field(max_length=64, pattern=r"^[A-Za-z][A-Za-z0-9_]{7,63}$") version: str = Field(max_length=64) Loading Loading @@ -283,9 +303,9 @@ class CreateAppInstanceRequest(BaseModel): model_config = ConfigDict(extra="forbid") name: str = Field(max_length=64, pattern=r"^[A-Za-z][A-Za-z0-9_]{1,63}$") appId: UUID edgeCloudZoneId: UUID kubernetesClusterRef: Optional[UUID] = None appId: CamaraUuid edgeCloudZoneId: CamaraUuid kubernetesClusterRef: Optional[CamaraUuid] = None subscriptionRequest: Optional[SubscriptionRequest] = None Loading @@ -293,9 +313,9 @@ class CreateAppDeploymentRequest(BaseModel): model_config = ConfigDict(extra="forbid") appDeploymentName: str = Field(max_length=64, pattern=r"^[A-Za-z][A-Za-z0-9_]{1,63}$") appId: UUID edgeCloudZones: list[UUID] = Field(min_length=1, max_length=100) kubernetesClusterRefs: Optional[list[UUID]] = Field(default=None, max_length=100) appId: CamaraUuid edgeCloudZones: list[CamaraUuid] = Field(min_length=1, max_length=100) kubernetesClusterRefs: Optional[list[CamaraUuid]] = Field(default=None, max_length=100) subscriptionRequest: Optional[SubscriptionRequest] = None Loading tests/unit/test_eam_endpoints.py +87 −1 Changes for tests/unit/test_eam_endpoints.py: 87 added lines, 1 removed line. Original line number Diff line number Diff line from collections.abc import Generator from typing import Any from unittest.mock import ANY, AsyncMock from uuid import uuid4 from uuid import UUID, uuid4 import pytest from fastapi.testclient import TestClient Loading Loading @@ -301,3 +301,89 @@ class TestDeleteAppDeployment: def test_malformed_deployment_id_returns_400(self, client: TestClient) -> None: response = client.delete(f"{EAM_BASE}/deployments/not-a-uuid") assert response.status_code == 400 # The spec pattern for every EAM id: lowercase, hyphenated, version 1-5, RFC variant. _SPEC_VALID_ID = "3fa85f64-5717-4562-b3fc-2c963f66afa6" _NON_CONFORMING_IDS = [ pytest.param(_SPEC_VALID_ID.upper(), id="uppercase"), pytest.param(_SPEC_VALID_ID.replace("-", ""), id="no-hyphens"), pytest.param(f"urn:uuid:{_SPEC_VALID_ID}", id="urn"), pytest.param(f"{{{_SPEC_VALID_ID}}}", id="braced"), pytest.param("00000000-0000-0000-0000-000000000000", id="nil"), pytest.param("3fa85f64-5717-0562-b3fc-2c963f66afa6", id="version-0"), ] def _assert_invalid_argument(response: Any) -> None: assert response.status_code == 400 body = response.json() assert body["status"] == 400 assert body["code"] == "INVALID_ARGUMENT" class TestCamaraUuidFormat: @pytest.mark.parametrize("bad_id", _NON_CONFORMING_IDS) def test_body_field_rejects_non_conforming_id( self, client: TestClient, mock_eam_service: AsyncMock, bad_id: str ) -> None: response = client.post( f"{EAM_BASE}/appinstances", json={**_VALID_CREATE_INSTANCE, "appId": bad_id} ) _assert_invalid_argument(response) mock_eam_service.create_app_instance.assert_not_called() @pytest.mark.parametrize("bad_id", _NON_CONFORMING_IDS) def test_body_list_item_rejects_non_conforming_id( self, client: TestClient, mock_eam_service: AsyncMock, bad_id: str ) -> None: response = client.post( f"{EAM_BASE}/deployments", json={**_VALID_CREATE_DEPLOYMENT, "edgeCloudZones": [str(_ZONE_ID), bad_id]}, ) _assert_invalid_argument(response) mock_eam_service.create_app_deployment.assert_not_called() @pytest.mark.parametrize("bad_id", _NON_CONFORMING_IDS) def test_path_param_rejects_non_conforming_id( self, client: TestClient, mock_eam_service: AsyncMock, bad_id: str ) -> None: response = client.delete(f"{EAM_BASE}/deployments/{bad_id}") _assert_invalid_argument(response) mock_eam_service.delete_app_deployment.assert_not_called() @pytest.mark.parametrize("bad_id", _NON_CONFORMING_IDS) def test_query_param_rejects_non_conforming_id( self, client: TestClient, mock_eam_service: AsyncMock, bad_id: str ) -> None: response = client.get(f"{EAM_BASE}/deployments", params={"appId": bad_id}) _assert_invalid_argument(response) mock_eam_service.get_app_deployments.assert_not_called() def test_body_accepts_lowercase_v4( self, client: TestClient, mock_eam_service: AsyncMock ) -> None: response = client.post( f"{EAM_BASE}/appinstances", json={**_VALID_CREATE_INSTANCE, "appId": _SPEC_VALID_ID} ) assert response.status_code == 202 request = mock_eam_service.create_app_instance.call_args.kwargs["request"] assert request.appId == UUID(_SPEC_VALID_ID) def test_path_param_accepts_lowercase_v4( self, client: TestClient, mock_eam_service: AsyncMock ) -> None: response = client.delete(f"{EAM_BASE}/deployments/{_SPEC_VALID_ID}") assert response.status_code == 202 kwargs = mock_eam_service.delete_app_deployment.call_args.kwargs assert kwargs["app_deployment_id"] == UUID(_SPEC_VALID_ID) def test_query_param_accepts_lowercase_v4( self, client: TestClient, mock_eam_service: AsyncMock ) -> None: mock_eam_service.get_app_deployments.return_value = [] response = client.get(f"{EAM_BASE}/deployments", params={"appId": _SPEC_VALID_ID}) assert response.status_code == 200 assert mock_eam_service.get_app_deployments.call_args.kwargs["app_id"] == UUID( _SPEC_VALID_ID ) tests/unit/test_eam_mapper.py +11 −5 Changes for tests/unit/test_eam_mapper.py: 11 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -60,8 +60,8 @@ from open_exposure_gateway.domain.models import ( AppInstanceState, ) APP_ID = UUID("bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb") ZONE_ID = UUID("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa") APP_ID = UUID("bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb") ZONE_ID = UUID("aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa") INSTANCE_ID = UUID("cccccccc-cccc-cccc-cccc-cccccccccccc") OP_ID = UUID("dddddddd-dddd-dddd-dddd-dddddddddddd") APP_REGISTRATION_ID = UUID("ffffffff-ffff-ffff-ffff-ffffffffffff") Loading Loading @@ -1018,7 +1018,7 @@ class TestBuildDeployTargets: appDeploymentName="video_analytics_eu", appId=APP_ID, edgeCloudZones=[self.ZONE_A], kubernetesClusterRefs=[self.CLUSTER_A, UUID(int=0)], kubernetesClusterRefs=[self.CLUSTER_A, UUID("dddddddd-0000-4000-8000-00000000000b")], ) with pytest.raises(ValueError, match="kubernetesClusterRefs"): build_deploy_targets(request, [self.INSTANCE_A]) Loading Loading @@ -1051,8 +1051,14 @@ class TestBuildMultiZoneDeployCommand: assert cmd.deploy.placement_constraints == {} def test_carries_n_targets_for_multi_zone(self) -> None: zone_a, zone_b = UUID(int=1), UUID(int=2) instance_a, instance_b = UUID(int=3), UUID(int=4) zone_a, zone_b = ( UUID("aaaaaaaa-0000-4000-8000-000000000001"), UUID("aaaaaaaa-0000-4000-8000-000000000002"), ) instance_a, instance_b = ( UUID("cccccccc-0000-4000-8000-000000000003"), UUID("cccccccc-0000-4000-8000-000000000004"), ) request = CreateAppDeploymentRequest( appDeploymentName="video_analytics_eu", appId=APP_ID, Loading tests/unit/test_eam_service.py +2 −2 Changes for tests/unit/test_eam_service.py: 2 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -75,8 +75,8 @@ from tests.unit.fakes import ( FakeOperationRepository, ) APP_ID = UUID("bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb") ZONE_ID = UUID("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa") APP_ID = UUID("bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb") ZONE_ID = UUID("aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa") INSTANCE_ID = UUID("cccccccc-cccc-cccc-cccc-cccccccccccc") APP_REGISTRATION_ID = UUID("ffffffff-ffff-ffff-ffff-ffffffffffff") DEPLOYMENT_ID = UUID("11111111-1111-1111-1111-111111111111") Loading Loading
src/open_exposure_gateway/api/camara/edge_application_management/v0_1_0_alpha_1/router.py +13 −12 Changes for src/open_exposure_gateway/api/camara/edge_application_management/v0_1_0_alpha_1/router.py: 13 added lines, 12 removed lines. Original line number Diff line number Diff line from typing import Annotated, Any, Optional from uuid import UUID, uuid4 from uuid import uuid4 from fastapi import APIRouter, Depends, Query, Request, Response, status Loading @@ -10,6 +10,7 @@ from open_exposure_gateway.api.camara.edge_application_management.v0_1_0_alpha_1 AppInstanceInfo, AppManifest, AppManifestEnvelope, CamaraUuid, CreateAppDeploymentRequest, CreateAppInstanceRequest, EdgeCloudZone, Loading Loading @@ -130,7 +131,7 @@ async def get_apps( ), ) async def get_app( appId: UUID, appId: CamaraUuid, service: EdgeAppService, caller: Caller, ) -> Any: Loading Loading @@ -182,7 +183,7 @@ async def submit_app( ), ) async def delete_app( appId: UUID, appId: CamaraUuid, service: EdgeAppService, caller: Caller, ) -> Response: Loading Loading @@ -248,8 +249,8 @@ async def create_app_instance( async def get_app_instances( service: EdgeAppService, caller: Caller, appId: Annotated[Optional[UUID], Query()] = None, appInstanceId: Annotated[Optional[UUID], Query()] = None, appId: Annotated[Optional[CamaraUuid], Query()] = None, appInstanceId: Annotated[Optional[CamaraUuid], Query()] = None, region: Annotated[Optional[str], Query(max_length=64)] = None, ) -> Any: return await service.get_app_instances( Loading @@ -274,7 +275,7 @@ async def get_app_instances( ), ) async def delete_app_instance( appInstanceId: UUID, appInstanceId: CamaraUuid, service: EdgeAppService, caller: Caller, ) -> Response: Loading Loading @@ -337,8 +338,8 @@ async def create_app_deployment( async def get_app_deployments( service: EdgeAppService, caller: Caller, appId: Annotated[Optional[UUID], Query()] = None, appDeploymentId: Annotated[Optional[UUID], Query()] = None, appId: Annotated[Optional[CamaraUuid], Query()] = None, appDeploymentId: Annotated[Optional[CamaraUuid], Query()] = None, ) -> Any: return await service.get_app_deployments( app_id=appId, Loading @@ -361,7 +362,7 @@ async def get_app_deployments( ), ) async def delete_app_deployment( appDeploymentId: UUID, appDeploymentId: CamaraUuid, service: EdgeAppService, caller: Caller, ) -> Response: Loading @@ -387,7 +388,7 @@ async def delete_app_deployment( DownstreamServiceException(), ), ) async def update_app_deployment(appDeploymentId: UUID) -> Any: async def update_app_deployment(appDeploymentId: CamaraUuid) -> Any: raise NotImplementedException(message="Deployment update is not implemented") Loading @@ -405,7 +406,7 @@ async def update_app_deployment(appDeploymentId: UUID) -> Any: ) async def get_clusters( region: Annotated[Optional[str], Query(max_length=64)] = None, clusterRef: Annotated[Optional[UUID], Query()] = None, edgeCloudZoneId: Annotated[Optional[UUID], Query()] = None, clusterRef: Annotated[Optional[CamaraUuid], Query()] = None, edgeCloudZoneId: Annotated[Optional[CamaraUuid], Query()] = None, ) -> Any: raise NotImplementedException(message="Cluster catalog is not implemented")
src/open_exposure_gateway/api/camara/edge_application_management/v0_1_0_alpha_1/schemas.py +29 −9 Changes for src/open_exposure_gateway/api/camara/edge_application_management/v0_1_0_alpha_1/schemas.py: 29 added lines, 9 removed lines. Original line number Diff line number Diff line import re from datetime import datetime from enum import StrEnum from typing import Any, Literal, Optional from typing import Annotated, Any, Literal, Optional from uuid import UUID from pydantic import BaseModel, ConfigDict, Field, field_validator from pydantic import BaseModel, BeforeValidator, ConfigDict, Field, field_validator # Pattern shared by AppId, AppInstanceId, AppDeploymentId, EdgeCloudZoneId and # KubernetesClusterRef in the spec: lowercase, hyphenated, version 1-5, RFC variant. _CAMARA_UUID_PATTERN = re.compile( r"^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" ) def _check_camara_uuid(value: Any) -> Any: # pydantic's UUID alone also accepts uppercase, unhyphenated, urn:uuid:, braced, # nil and version-0 forms, all of which the spec pattern rejects. text = str(value) if isinstance(value, UUID) else value if not isinstance(text, str) or not _CAMARA_UUID_PATTERN.fullmatch(text): raise ValueError(f"must match pattern {_CAMARA_UUID_PATTERN.pattern}") return value # Input-side UUID for EAM request bodies, path and query params. Still a UUID downstream. CamaraUuid = Annotated[UUID, BeforeValidator(_check_camara_uuid)] class AppInstanceStatus(StrEnum): Loading Loading @@ -215,7 +235,7 @@ RequiredResources = VmResources | ContainerResources | DockerComposeResources | class AppManifest(BaseModel): model_config = ConfigDict(extra="forbid") appId: Optional[UUID] = None appId: Optional[CamaraUuid] = None name: str = Field(max_length=64, pattern=r"^[A-Za-z][A-Za-z0-9_]{1,63}$") appProvider: str = Field(max_length=64, pattern=r"^[A-Za-z][A-Za-z0-9_]{7,63}$") version: str = Field(max_length=64) Loading Loading @@ -283,9 +303,9 @@ class CreateAppInstanceRequest(BaseModel): model_config = ConfigDict(extra="forbid") name: str = Field(max_length=64, pattern=r"^[A-Za-z][A-Za-z0-9_]{1,63}$") appId: UUID edgeCloudZoneId: UUID kubernetesClusterRef: Optional[UUID] = None appId: CamaraUuid edgeCloudZoneId: CamaraUuid kubernetesClusterRef: Optional[CamaraUuid] = None subscriptionRequest: Optional[SubscriptionRequest] = None Loading @@ -293,9 +313,9 @@ class CreateAppDeploymentRequest(BaseModel): model_config = ConfigDict(extra="forbid") appDeploymentName: str = Field(max_length=64, pattern=r"^[A-Za-z][A-Za-z0-9_]{1,63}$") appId: UUID edgeCloudZones: list[UUID] = Field(min_length=1, max_length=100) kubernetesClusterRefs: Optional[list[UUID]] = Field(default=None, max_length=100) appId: CamaraUuid edgeCloudZones: list[CamaraUuid] = Field(min_length=1, max_length=100) kubernetesClusterRefs: Optional[list[CamaraUuid]] = Field(default=None, max_length=100) subscriptionRequest: Optional[SubscriptionRequest] = None Loading
tests/unit/test_eam_endpoints.py +87 −1 Changes for tests/unit/test_eam_endpoints.py: 87 added lines, 1 removed line. Original line number Diff line number Diff line from collections.abc import Generator from typing import Any from unittest.mock import ANY, AsyncMock from uuid import uuid4 from uuid import UUID, uuid4 import pytest from fastapi.testclient import TestClient Loading Loading @@ -301,3 +301,89 @@ class TestDeleteAppDeployment: def test_malformed_deployment_id_returns_400(self, client: TestClient) -> None: response = client.delete(f"{EAM_BASE}/deployments/not-a-uuid") assert response.status_code == 400 # The spec pattern for every EAM id: lowercase, hyphenated, version 1-5, RFC variant. _SPEC_VALID_ID = "3fa85f64-5717-4562-b3fc-2c963f66afa6" _NON_CONFORMING_IDS = [ pytest.param(_SPEC_VALID_ID.upper(), id="uppercase"), pytest.param(_SPEC_VALID_ID.replace("-", ""), id="no-hyphens"), pytest.param(f"urn:uuid:{_SPEC_VALID_ID}", id="urn"), pytest.param(f"{{{_SPEC_VALID_ID}}}", id="braced"), pytest.param("00000000-0000-0000-0000-000000000000", id="nil"), pytest.param("3fa85f64-5717-0562-b3fc-2c963f66afa6", id="version-0"), ] def _assert_invalid_argument(response: Any) -> None: assert response.status_code == 400 body = response.json() assert body["status"] == 400 assert body["code"] == "INVALID_ARGUMENT" class TestCamaraUuidFormat: @pytest.mark.parametrize("bad_id", _NON_CONFORMING_IDS) def test_body_field_rejects_non_conforming_id( self, client: TestClient, mock_eam_service: AsyncMock, bad_id: str ) -> None: response = client.post( f"{EAM_BASE}/appinstances", json={**_VALID_CREATE_INSTANCE, "appId": bad_id} ) _assert_invalid_argument(response) mock_eam_service.create_app_instance.assert_not_called() @pytest.mark.parametrize("bad_id", _NON_CONFORMING_IDS) def test_body_list_item_rejects_non_conforming_id( self, client: TestClient, mock_eam_service: AsyncMock, bad_id: str ) -> None: response = client.post( f"{EAM_BASE}/deployments", json={**_VALID_CREATE_DEPLOYMENT, "edgeCloudZones": [str(_ZONE_ID), bad_id]}, ) _assert_invalid_argument(response) mock_eam_service.create_app_deployment.assert_not_called() @pytest.mark.parametrize("bad_id", _NON_CONFORMING_IDS) def test_path_param_rejects_non_conforming_id( self, client: TestClient, mock_eam_service: AsyncMock, bad_id: str ) -> None: response = client.delete(f"{EAM_BASE}/deployments/{bad_id}") _assert_invalid_argument(response) mock_eam_service.delete_app_deployment.assert_not_called() @pytest.mark.parametrize("bad_id", _NON_CONFORMING_IDS) def test_query_param_rejects_non_conforming_id( self, client: TestClient, mock_eam_service: AsyncMock, bad_id: str ) -> None: response = client.get(f"{EAM_BASE}/deployments", params={"appId": bad_id}) _assert_invalid_argument(response) mock_eam_service.get_app_deployments.assert_not_called() def test_body_accepts_lowercase_v4( self, client: TestClient, mock_eam_service: AsyncMock ) -> None: response = client.post( f"{EAM_BASE}/appinstances", json={**_VALID_CREATE_INSTANCE, "appId": _SPEC_VALID_ID} ) assert response.status_code == 202 request = mock_eam_service.create_app_instance.call_args.kwargs["request"] assert request.appId == UUID(_SPEC_VALID_ID) def test_path_param_accepts_lowercase_v4( self, client: TestClient, mock_eam_service: AsyncMock ) -> None: response = client.delete(f"{EAM_BASE}/deployments/{_SPEC_VALID_ID}") assert response.status_code == 202 kwargs = mock_eam_service.delete_app_deployment.call_args.kwargs assert kwargs["app_deployment_id"] == UUID(_SPEC_VALID_ID) def test_query_param_accepts_lowercase_v4( self, client: TestClient, mock_eam_service: AsyncMock ) -> None: mock_eam_service.get_app_deployments.return_value = [] response = client.get(f"{EAM_BASE}/deployments", params={"appId": _SPEC_VALID_ID}) assert response.status_code == 200 assert mock_eam_service.get_app_deployments.call_args.kwargs["app_id"] == UUID( _SPEC_VALID_ID )
tests/unit/test_eam_mapper.py +11 −5 Changes for tests/unit/test_eam_mapper.py: 11 added lines, 5 removed lines. Original line number Diff line number Diff line Loading @@ -60,8 +60,8 @@ from open_exposure_gateway.domain.models import ( AppInstanceState, ) APP_ID = UUID("bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb") ZONE_ID = UUID("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa") APP_ID = UUID("bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb") ZONE_ID = UUID("aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa") INSTANCE_ID = UUID("cccccccc-cccc-cccc-cccc-cccccccccccc") OP_ID = UUID("dddddddd-dddd-dddd-dddd-dddddddddddd") APP_REGISTRATION_ID = UUID("ffffffff-ffff-ffff-ffff-ffffffffffff") Loading Loading @@ -1018,7 +1018,7 @@ class TestBuildDeployTargets: appDeploymentName="video_analytics_eu", appId=APP_ID, edgeCloudZones=[self.ZONE_A], kubernetesClusterRefs=[self.CLUSTER_A, UUID(int=0)], kubernetesClusterRefs=[self.CLUSTER_A, UUID("dddddddd-0000-4000-8000-00000000000b")], ) with pytest.raises(ValueError, match="kubernetesClusterRefs"): build_deploy_targets(request, [self.INSTANCE_A]) Loading Loading @@ -1051,8 +1051,14 @@ class TestBuildMultiZoneDeployCommand: assert cmd.deploy.placement_constraints == {} def test_carries_n_targets_for_multi_zone(self) -> None: zone_a, zone_b = UUID(int=1), UUID(int=2) instance_a, instance_b = UUID(int=3), UUID(int=4) zone_a, zone_b = ( UUID("aaaaaaaa-0000-4000-8000-000000000001"), UUID("aaaaaaaa-0000-4000-8000-000000000002"), ) instance_a, instance_b = ( UUID("cccccccc-0000-4000-8000-000000000003"), UUID("cccccccc-0000-4000-8000-000000000004"), ) request = CreateAppDeploymentRequest( appDeploymentName="video_analytics_eu", appId=APP_ID, Loading
tests/unit/test_eam_service.py +2 −2 Changes for tests/unit/test_eam_service.py: 2 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -75,8 +75,8 @@ from tests.unit.fakes import ( FakeOperationRepository, ) APP_ID = UUID("bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb") ZONE_ID = UUID("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa") APP_ID = UUID("bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb") ZONE_ID = UUID("aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa") INSTANCE_ID = UUID("cccccccc-cccc-cccc-cccc-cccccccccccc") APP_REGISTRATION_ID = UUID("ffffffff-ffff-ffff-ffff-ffffffffffff") DEPLOYMENT_ID = UUID("11111111-1111-1111-1111-111111111111") Loading