Commit 104f349b authored by George Papathanail's avatar George Papathanail
Browse files

fix(ti): send service_specification_ref in TI activate command

SRM rejects every Traffic Influence activate command because
network_capability.target.application_reference.service_specification_ref
is required by its ApplicationReferenceTarget model.

build_activate_command now sets service_specification_ref to the appId,
matching the spec ref build_catalog_payload registers on POST /apps.
external_app_id is kept.

The parameters_snapshot read path gets its own target/application_reference
models where service_specification_ref is optional, so snapshots stored
before this change still load on GET.
parent fccc7bc9
Loading
Loading
Loading
Loading
Loading
+1 −0
Changes for src/open_exposure_gateway/application/mappers/traffic_influence_mapper.py: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ def build_activate_command(

    target = NetworkCapabilityTarget(
        application_reference=NetworkCapabilityTargetApplicationReference(
            service_specification_ref=str(request.appId),
            external_app_id=str(request.appId),
        ),
    )
+11 −1
Changes for src/open_exposure_gateway/domain/traffic_influence.py: 11 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ class Subject(StrEnum):


class NetworkCapabilityTargetApplicationReference(BaseModel):
    service_specification_ref: str
    external_app_id: str


@@ -79,9 +80,18 @@ class SRMNetworkCapabilityDeactivateCommand(BaseModel):
    network_capability: NetworkCapabilityDeactivateTarget


class NetworkCapabilitySnapshotApplicationReference(BaseModel):
    service_specification_ref: str | None = None
    external_app_id: str


class NetworkCapabilitySnapshotTarget(BaseModel):
    application_reference: NetworkCapabilitySnapshotApplicationReference


class NetworkCapabilityParametersSnapshot(BaseModel):
    schema_version: str | None = None
    target: NetworkCapabilityTarget
    target: NetworkCapabilitySnapshotTarget
    parameters: dict[str, Any] = Field(default_factory=dict)


+43 −6
Changes for tests/unit/test_traffic_influence_flows.py: 43 added lines, 6 removed lines.
Original line number Diff line number Diff line
@@ -38,8 +38,8 @@ from open_exposure_gateway.domain.models import (
)
from open_exposure_gateway.domain.traffic_influence import (
    NetworkCapabilityParametersSnapshot,
    NetworkCapabilityTarget,
    NetworkCapabilityTargetApplicationReference,
    NetworkCapabilitySnapshotApplicationReference,
    NetworkCapabilitySnapshotTarget,
    SRMNetworkCapabilityActivateCommand,
    SRMNetworkCapabilityDeactivateCommand,
    SRMTrafficInfluenceCapability,
@@ -244,6 +244,14 @@ class TestTrafficInfluenceCreateFlow:
            command.network_capability.target.application_reference.external_app_id
            == TI_BODY["appId"]
        )
        assert (
            command.network_capability.target.application_reference.service_specification_ref
            == TI_BODY["appId"]
        )
        assert activates[0]["network_capability"]["target"]["application_reference"] == {
            "service_specification_ref": TI_BODY["appId"],
            "external_app_id": TI_BODY["appId"],
        }
        assert source.port == 45678
        assert destination.port == 443
        assert destination.protocol == "TCP"
@@ -724,8 +732,8 @@ class TestTrafficInfluenceGetFlow:
            app_provider_id="provider-1",
            external_ref=traffic_influence_id,
            parameters_snapshot=NetworkCapabilityParametersSnapshot(
                target=NetworkCapabilityTarget(
                    application_reference=NetworkCapabilityTargetApplicationReference(
                target=NetworkCapabilitySnapshotTarget(
                    application_reference=NetworkCapabilitySnapshotApplicationReference(
                        external_app_id=TI_BODY["appId"]
                    )
                ),
@@ -773,8 +781,8 @@ class TestTrafficInfluenceGetFlow:
            app_provider_id="provider-1",
            external_ref=traffic_influence_id,
            parameters_snapshot=NetworkCapabilityParametersSnapshot(
                target=NetworkCapabilityTarget(
                    application_reference=NetworkCapabilityTargetApplicationReference(
                target=NetworkCapabilitySnapshotTarget(
                    application_reference=NetworkCapabilitySnapshotApplicationReference(
                        external_app_id=TI_BODY["appId"]
                    )
                ),
@@ -787,6 +795,35 @@ class TestTrafficInfluenceGetFlow:
        assert response.status_code == 200
        assert response.json()["edgeCloudZoneId"] == TI_BODY["edgeCloudZoneId"]

    def test_get_reads_snapshot_saved_without_service_specification_ref(
        self, api_client: TestClient, fake_srm: FakeSRMClient
    ) -> None:
        traffic_influence_id = api_client.post(
            f"{TI_BASE}/traffic-influences", json=TI_BODY
        ).json()["trafficInfluenceID"]

        fake_srm.traffic_influences[traffic_influence_id] = (
            SRMTrafficInfluenceCapability.model_validate(
                {
                    "service_instance_id": traffic_influence_id,
                    "capability_type": "traffic_influence",
                    "state": "active",
                    "zone_id": "9f8d7c6b-5a4e-3d2c-1b0a-9f8d7c6b5a4e",
                    "app_provider_id": "provider-1",
                    "external_ref": traffic_influence_id,
                    "parameters_snapshot": {
                        "target": {"application_reference": {"external_app_id": TI_BODY["appId"]}},
                        "parameters": {},
                    },
                }
            )
        )

        response = api_client.get(f"{TI_BASE}/traffic-influences/{traffic_influence_id}")

        assert response.status_code == 200
        assert response.json()["appId"] == TI_BODY["appId"]

    def test_get_surfaces_srm_outage_instead_of_thinning_the_response(
        self, api_client: TestClient, fake_srm: FakeSRMClient
    ) -> None: