Commit 273fc7f3 authored by George Papathanail's avatar George Papathanail
Browse files

test: extend fake SRM work and wire_app_deployment_repo for completions

parent 6a2c2017
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -66,7 +66,9 @@ def service_overrides() -> Generator[None, None, None]:
    operation_repo = FakeOperationRepository()
    app_instance_repo = FakeAppInstanceRepository()
    app_deployment_repo = FakeAppDeploymentRepository()
    wire_operation_consumer(bus, operation_repo, app_instance_repo)
    wire_operation_consumer(
        bus, operation_repo, app_instance_repo, app_deployment_repo=app_deployment_repo
    )
    wire_srm_worker(bus, srm)
    app.dependency_overrides[get_edge_app_service] = lambda: EdgeApplicationManagementService(
        srm_client=srm,
+2 −0
Original line number Diff line number Diff line
@@ -119,6 +119,7 @@ def live_srm(
    callback_registration_repo: FakeCallbackRegistrationRepository,
    callback_delivery_port: FakeCallbackDeliveryPort,
    callback_delivery_repo: FakeCallbackDeliveryRepository,
    app_deployment_repo: FakeAppDeploymentRepository,
) -> FakeSRMClient:
    """Fake SRM with its async side running: consumes commands, publishes completions."""
    wire_operation_consumer(
@@ -129,6 +130,7 @@ def live_srm(
        callback_registration_repo=callback_registration_repo,
        callback_delivery_port=callback_delivery_port,
        callback_delivery_repo=callback_delivery_repo,
        app_deployment_repo=app_deployment_repo,
    )
    wire_srm_worker(fake_bus, fake_srm)
    return fake_srm
+28 −22
Original line number Diff line number Diff line
@@ -220,9 +220,12 @@ def operation_status_payload(operation_id: str, **overrides: Any) -> dict[str, A

def wire_srm_worker(bus: FakeDataBus, srm: FakeSRMClient) -> None:
    async def on_deploy(command: dict[str, Any]) -> None:
        # POST /appinstances always carries exactly one targets[] entry
        # (ADR-0005); multi-zone /deployments (N entries) is out of scope here.
        target = command["targets"][0]
        # One targets[] entry for single-zone POST /appinstances, N for
        # multi-zone POST /deployments (ADR-0005) -- both produce one
        # instances[] entry per target in a single completion event, same as
        # real SRM would for a multi-zone deploy.
        instances = []
        for target in command["targets"]:
            # SRM adopts the OEG-minted app_instance_id as its own service_instance_id (ADR-0005).
            srm_id = target["app_instance_id"]
            srm.instances[srm_id] = SRMServiceInstance(
@@ -233,18 +236,19 @@ def wire_srm_worker(bus: FakeDataBus, srm: FakeSRMClient) -> None:
                zone_id=target["zone_id"],
                name=command["deploy"]["instance_name"],
            )
        await bus.publish(
            Subject.OPERATION_COMPLETED,
            completion_payload(
                command["operation_id"],
                correlation_id=command["correlation_id"],
                instances=[
            instances.append(
                {
                    "service_instance_id": srm_id,
                    "zone_id": target["zone_id"],
                    "status": "completed",
                }
                ],
            )
        await bus.publish(
            Subject.OPERATION_COMPLETED,
            completion_payload(
                command["operation_id"],
                correlation_id=command["correlation_id"],
                instances=instances,
            ),
        )

@@ -303,12 +307,13 @@ def wire_operation_consumer(
    callback_registration_repo: CallbackRegistrationRepository | None = None,
    callback_delivery_port: CallbackDeliveryPort | None = None,
    callback_delivery_repo: CallbackDeliveryRepository | None = None,
    app_deployment_repo: AppDeploymentRepository | None = None,
) -> NatsOperationConsumer:
    """Wires OEG's real completion handler (EdgeApplicationManagementService.handle_completed)
    behind the fake bus -- pass the same repo/port instances used to build the service under
    test so a completion event updates the rows (and, for callback tests, deliveries) the test
    can see. app_registration_repo/callback_* are optional: only needed by tests exercising
    webhook delivery."""
    can see. app_registration_repo/callback_*/app_deployment_repo are optional: only needed by
    tests exercising webhook delivery or the app_deployments rollup, respectively."""
    service = EdgeApplicationManagementService(
        srm_client=AsyncMock(),
        app_registration_repo=app_registration_repo,
@@ -317,6 +322,7 @@ def wire_operation_consumer(
        callback_registration_repo=callback_registration_repo,
        callback_delivery_port=callback_delivery_port,
        callback_delivery_repo=callback_delivery_repo,
        app_deployment_repo=app_deployment_repo,
    )
    consumer = NatsOperationConsumer(
        client=AsyncMock(), subject=Subject.OPERATION_COMPLETED, handler=service.handle_completed
+29 −0
Original line number Diff line number Diff line
@@ -453,6 +453,35 @@ class TestCreateAppDeploymentFlow:
        response = api_client.post(f"{EAM_BASE}/deployments", json=body)
        assert response.status_code == 400

    def test_operations_app_deployment_and_app_instances_reach_ready_after_srm_completes(
        self,
        api_client: TestClient,
        live_srm: FakeSRMClient,
        operation_repo: FakeOperationRepository,
        app_deployment_repo: FakeAppDeploymentRepository,
        app_instance_repo: FakeAppInstanceRepository,
    ) -> None:
        """End-to-end through the real DI wiring, matching
        TestCreateAppInstanceFlow's single-zone completion test: proves both
        the N app_instances rows AND the app_deployments rollup reach their
        terminal state once SRM completes, not just the operations row."""
        response = api_client.post(f"{EAM_BASE}/deployments", json=CREATE_DEPLOYMENT_BODY)
        deployment_id = UUID(response.json()["appDeploymentId"])

        (operation,) = list(operation_repo.rows.values())
        assert operation.status == OperationStatus.COMPLETED

        stored_deployment = app_deployment_repo.rows.get(deployment_id)
        assert stored_deployment is not None
        assert stored_deployment.state == AppDeploymentState.READY

        instances = [
            i for i in app_instance_repo.rows.values() if i.app_deployment_id == deployment_id
        ]
        assert len(instances) == 2
        assert all(i.state == AppInstanceState.READY for i in instances)
        assert len(live_srm.instances) == 2


class TestCreateAppDeploymentUnregisteredAppFlow:
    """No autouse app registration here — this class exists to prove the