Commit 20219328 authored by Dimitrios Gogos's avatar Dimitrios Gogos
Browse files

fix: update build_app_instance_info to include zone_id and adjust related...

fix: update build_app_instance_info to include zone_id and adjust related logic in EdgeApplicationManagementService and tests
parent 290526c9
Loading
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -291,7 +291,9 @@ def build_app_manifest(catalog: SRMCatalogPayload) -> AppManifest:
    )


def build_app_instance_info(instance: SRMServiceInstance, app_id: UUID) -> AppInstanceInfo:
def build_app_instance_info(
    instance: SRMServiceInstance, app_id: UUID, zone_id: UUID
) -> AppInstanceInfo:
    status = _SRM_STATE_TO_APP_INSTANCE_STATUS.get(instance.state, AppInstanceStatus.UNKNOWN)

    endpoint_info: list[ComponentEndpointInfo] = []
@@ -315,7 +317,7 @@ def build_app_instance_info(instance: SRMServiceInstance, app_id: UUID) -> AppIn
        appId=app_id,
        appProvider=instance.app_provider_id,
        status=status,
        edgeCloudZoneId=UUID(instance.zone_id) if instance.zone_id else UUID(int=0),
        edgeCloudZoneId=zone_id,
        componentEndpointInfo=endpoint_info or None,
    )

+17 −1
Original line number Diff line number Diff line
@@ -464,7 +464,23 @@ class EdgeApplicationManagementService:
                    app_registration_id=instance.service_specification_id,
                )
                continue
            result.append(build_app_instance_info(instance, instance_app_id))

            zone_id = UUID(instance.zone_id) if instance.zone_id else None
            if zone_id is None:
                if self._app_instance_repo is None:
                    raise RuntimeError("AppInstanceRepository is not available")
                local_instance = await self._app_instance_repo.get_by_id(
                    UUID(instance.service_instance_id)
                )
                if local_instance is None:
                    logger.warning(
                        "app_instance_zone_unresolvable",
                        app_instance_id=instance.service_instance_id,
                    )
                    continue
                zone_id = local_instance.edge_cloud_zone_id

            result.append(build_app_instance_info(instance, instance_app_id, zone_id))
        return result

    async def delete_app_instance(
+10 −10
Original line number Diff line number Diff line
@@ -339,34 +339,34 @@ class TestBuildAppInstanceInfo:
        )

    def test_maps_ids_and_provider(self) -> None:
        result = build_app_instance_info(self._make_instance(), APP_ID)
        result = build_app_instance_info(self._make_instance(), APP_ID, ZONE_ID)
        assert result.appInstanceId == INSTANCE_ID
        assert result.appId == APP_ID
        assert result.appProvider == "VideoAppsCo"
        assert result.edgeCloudZoneId == ZONE_ID

    def test_state_mapping_active_to_ready(self) -> None:
        result = build_app_instance_info(self._make_instance(state="active"), APP_ID)
        result = build_app_instance_info(self._make_instance(state="active"), APP_ID, ZONE_ID)
        assert result.status == AppInstanceStatus.READY

    def test_state_mapping_creating_to_instantiating(self) -> None:
        result = build_app_instance_info(self._make_instance(state="creating"), APP_ID)
        result = build_app_instance_info(self._make_instance(state="creating"), APP_ID, ZONE_ID)
        assert result.status == AppInstanceStatus.INSTANTIATING

    def test_state_mapping_failed_to_failed(self) -> None:
        result = build_app_instance_info(self._make_instance(state="failed"), APP_ID)
        result = build_app_instance_info(self._make_instance(state="failed"), APP_ID, ZONE_ID)
        assert result.status == AppInstanceStatus.FAILED

    def test_state_mapping_terminating(self) -> None:
        result = build_app_instance_info(self._make_instance(state="terminating"), APP_ID)
        result = build_app_instance_info(self._make_instance(state="terminating"), APP_ID, ZONE_ID)
        assert result.status == AppInstanceStatus.TERMINATING

    def test_state_mapping_terminated_to_unknown(self) -> None:
        result = build_app_instance_info(self._make_instance(state="terminated"), APP_ID)
        result = build_app_instance_info(self._make_instance(state="terminated"), APP_ID, ZONE_ID)
        assert result.status == AppInstanceStatus.UNKNOWN

    def test_unknown_state_defaults_to_unknown(self) -> None:
        result = build_app_instance_info(self._make_instance(state="exotic"), APP_ID)
        result = build_app_instance_info(self._make_instance(state="exotic"), APP_ID, ZONE_ID)
        assert result.status == AppInstanceStatus.UNKNOWN

    def test_endpoints_extracted_from_capability_instances(self) -> None:
@@ -383,7 +383,7 @@ class TestBuildAppInstanceInfo:
                ),
            )
        ]
        result = build_app_instance_info(instance, APP_ID)
        result = build_app_instance_info(instance, APP_ID, ZONE_ID)
        assert result.componentEndpointInfo is not None
        assert len(result.componentEndpointInfo) == 1
        ep = result.componentEndpointInfo[0]
@@ -392,13 +392,13 @@ class TestBuildAppInstanceInfo:
        assert ep.accessPoints.port == 80

    def test_no_endpoints_gives_none(self) -> None:
        result = build_app_instance_info(self._make_instance(), APP_ID)
        result = build_app_instance_info(self._make_instance(), APP_ID, ZONE_ID)
        assert result.componentEndpointInfo is None

    def test_name_falls_back_to_instance_id_when_missing(self) -> None:
        instance = self._make_instance()
        instance.name = None
        result = build_app_instance_info(instance, APP_ID)
        result = build_app_instance_info(instance, APP_ID, ZONE_ID)
        assert result.name == str(INSTANCE_ID)


+41 −2
Original line number Diff line number Diff line
@@ -130,13 +130,15 @@ def _make_srm_catalog() -> SRMCatalogPayload:
    )


def _make_srm_instance(state: str = "active") -> SRMServiceInstance:
def _make_srm_instance(
    state: str = "active", zone_id: str | None = str(ZONE_ID)
) -> SRMServiceInstance:
    return SRMServiceInstance(
        service_instance_id=str(INSTANCE_ID),
        service_specification_id=str(APP_REGISTRATION_ID),
        state=state,
        app_provider_id="VideoAppsCo",
        zone_id=str(ZONE_ID),
        zone_id=zone_id,
        name="myvideoapp_inst",
        capability_instances=[],
    )
@@ -1257,6 +1259,43 @@ class TestGetAppInstances:
        assert result == []
        srm_client.get_app_instances.assert_not_called()

    async def test_falls_back_to_local_zone_when_srm_zone_missing(
        self,
        service: EdgeApplicationManagementService,
        srm_client: AsyncMock,
        app_registration_repo: FakeAppRegistrationRepository,
        app_instance_repo: FakeAppInstanceRepository,
    ) -> None:
        await _seed_registration(app_registration_repo)
        await app_instance_repo.save(
            AppInstance(
                app_instance_id=INSTANCE_ID,
                operation_id=uuid4(),
                app_registration_id=APP_REGISTRATION_ID,
                edge_cloud_zone_id=ZONE_ID,
                state=AppInstanceState.READY,
            )
        )
        srm_client.get_app_instances.return_value = [
            _make_srm_instance(state="active", zone_id=None)
        ]
        result = await service.get_app_instances()
        assert len(result) == 1
        assert result[0].edgeCloudZoneId == ZONE_ID

    async def test_skips_instance_when_zone_unresolvable_locally_too(
        self,
        service: EdgeApplicationManagementService,
        srm_client: AsyncMock,
        app_registration_repo: FakeAppRegistrationRepository,
    ) -> None:
        await _seed_registration(app_registration_repo)
        srm_client.get_app_instances.return_value = [
            _make_srm_instance(state="active", zone_id=None)
        ]
        result = await service.get_app_instances()
        assert result == []


class TestDeleteAppInstance:
    @pytest.fixture(autouse=True)