Loading src/open_exposure_gateway/api/camara/traffic_influence/vwip/schemas.py +3 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,9 @@ from uuid import UUID from pydantic import BaseModel, Field SOURCE_API = "traffic-influence" SOURCE_API_VERSION = "wip" class TrafficInfluenceState(StrEnum): ORDERED = "ordered" Loading src/open_exposure_gateway/application/mappers/traffic_influence_mapper.py +7 −1 Original line number Diff line number Diff line Loading @@ -3,11 +3,16 @@ from uuid import UUID, uuid4 from pydantic import ValidationError from open_exposure_gateway.api.camara.traffic_influence.vwip.schemas import PostTrafficInfluence from open_exposure_gateway.api.camara.traffic_influence.vwip.schemas import ( SOURCE_API, SOURCE_API_VERSION, PostTrafficInfluence, ) from open_exposure_gateway.api.camara.traffic_influence.vwip.schemas import ( TrafficInfluence as TrafficInfluenceResponse, ) from open_exposure_gateway.domain.models import TrafficInfluence as TrafficInfluenceRecord from open_exposure_gateway.domain.quality_on_demand import SourceSpec from open_exposure_gateway.domain.traffic_influence import ( NetworkCapabilityDeactivateTarget, NetworkCapabilityParameters, Loading Loading @@ -63,6 +68,7 @@ def build_activate_command( else None, ), ), source_spec=SourceSpec(api=SOURCE_API, version=SOURCE_API_VERSION), ), ) Loading src/open_exposure_gateway/domain/traffic_influence.py +3 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,8 @@ from uuid import UUID from pydantic import BaseModel, Field from open_exposure_gateway.domain.quality_on_demand import SourceSpec class Subject(StrEnum): # Same bus subjects QoD uses (srm/interface-contract.md B.5: "generic for Loading Loading @@ -43,6 +45,7 @@ class NetworkCapabilityPayload(BaseModel): capability_type: str = "traffic_influence" target: NetworkCapabilityTarget parameters: NetworkCapabilityParameters source_spec: SourceSpec class SRMNetworkCapabilityActivateCommand(BaseModel): Loading tests/unit/test_traffic_influence_flows.py +22 −0 Original line number Diff line number Diff line Loading @@ -179,6 +179,28 @@ class TestTrafficInfluenceCreateFlow: assert command.service_instance_id == traffic_influence_id assert command.source == "nbi_camara" def test_activate_command_states_its_source_specification( self, api_client: TestClient, fake_bus: FakeDataBus ) -> None: """srm/interface-contract.md B.5: only OEG has seen the original CAMARA request, so only OEG can state which spec the canonical payload was mapped from. Without it SRM falls back to the catalog template's provenance, which is one row per capability and cannot tell two API versions served side by side apart.""" api_client.post(f"{TI_BASE}/traffic-influences", json=TI_BODY) command = SRMNetworkCapabilityActivateCommand.model_validate( [p for s, p in fake_bus.published if s == Subject.TASK_ACTIVATE][0] ) source_spec = command.network_capability.source_spec assert source_spec.family == "camara" assert source_spec.api == "traffic-influence" # The version the router that served this request implements, not a mapper constant. assert source_spec.version == "wip" # `source` names the publishing component, `source_spec` the specification mapped # from; they answer different questions and neither substitutes for the other. assert command.source != source_spec.family def test_unregistered_app_id_is_rejected( self, api_client: TestClient, Loading Loading
src/open_exposure_gateway/api/camara/traffic_influence/vwip/schemas.py +3 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,9 @@ from uuid import UUID from pydantic import BaseModel, Field SOURCE_API = "traffic-influence" SOURCE_API_VERSION = "wip" class TrafficInfluenceState(StrEnum): ORDERED = "ordered" Loading
src/open_exposure_gateway/application/mappers/traffic_influence_mapper.py +7 −1 Original line number Diff line number Diff line Loading @@ -3,11 +3,16 @@ from uuid import UUID, uuid4 from pydantic import ValidationError from open_exposure_gateway.api.camara.traffic_influence.vwip.schemas import PostTrafficInfluence from open_exposure_gateway.api.camara.traffic_influence.vwip.schemas import ( SOURCE_API, SOURCE_API_VERSION, PostTrafficInfluence, ) from open_exposure_gateway.api.camara.traffic_influence.vwip.schemas import ( TrafficInfluence as TrafficInfluenceResponse, ) from open_exposure_gateway.domain.models import TrafficInfluence as TrafficInfluenceRecord from open_exposure_gateway.domain.quality_on_demand import SourceSpec from open_exposure_gateway.domain.traffic_influence import ( NetworkCapabilityDeactivateTarget, NetworkCapabilityParameters, Loading Loading @@ -63,6 +68,7 @@ def build_activate_command( else None, ), ), source_spec=SourceSpec(api=SOURCE_API, version=SOURCE_API_VERSION), ), ) Loading
src/open_exposure_gateway/domain/traffic_influence.py +3 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,8 @@ from uuid import UUID from pydantic import BaseModel, Field from open_exposure_gateway.domain.quality_on_demand import SourceSpec class Subject(StrEnum): # Same bus subjects QoD uses (srm/interface-contract.md B.5: "generic for Loading Loading @@ -43,6 +45,7 @@ class NetworkCapabilityPayload(BaseModel): capability_type: str = "traffic_influence" target: NetworkCapabilityTarget parameters: NetworkCapabilityParameters source_spec: SourceSpec class SRMNetworkCapabilityActivateCommand(BaseModel): Loading
tests/unit/test_traffic_influence_flows.py +22 −0 Original line number Diff line number Diff line Loading @@ -179,6 +179,28 @@ class TestTrafficInfluenceCreateFlow: assert command.service_instance_id == traffic_influence_id assert command.source == "nbi_camara" def test_activate_command_states_its_source_specification( self, api_client: TestClient, fake_bus: FakeDataBus ) -> None: """srm/interface-contract.md B.5: only OEG has seen the original CAMARA request, so only OEG can state which spec the canonical payload was mapped from. Without it SRM falls back to the catalog template's provenance, which is one row per capability and cannot tell two API versions served side by side apart.""" api_client.post(f"{TI_BASE}/traffic-influences", json=TI_BODY) command = SRMNetworkCapabilityActivateCommand.model_validate( [p for s, p in fake_bus.published if s == Subject.TASK_ACTIVATE][0] ) source_spec = command.network_capability.source_spec assert source_spec.family == "camara" assert source_spec.api == "traffic-influence" # The version the router that served this request implements, not a mapper constant. assert source_spec.version == "wip" # `source` names the publishing component, `source_spec` the specification mapped # from; they answer different questions and neither substitutes for the other. assert command.source != source_spec.family def test_unregistered_app_id_is_rejected( self, api_client: TestClient, Loading