diff --git a/docs/scenarios/sdsp-f3623/sdsp_heartbeat.md b/docs/scenarios/sdsp-f3623/sdsp_heartbeat.md index a4efd498..5e0d1b53 100644 --- a/docs/scenarios/sdsp-f3623/sdsp_heartbeat.md +++ b/docs/scenarios/sdsp-f3623/sdsp_heartbeat.md @@ -10,7 +10,7 @@ The scenario executes the following sequence of steps: ### 1. Start SDSP Session -- **Step:** `Start/Stop SDSP Session (START)` +- **Step:** `Start SDSP Session` - **Action:** Initiates a new SDSP session with a unique UUID. - **Context:** Signals the beginning of a data provision session. @@ -33,6 +33,6 @@ The scenario executes the following sequence of steps: - **Context:** Provides the time window for the heartbeat verification to collect data and confirm the count. ### 5. Stop SDSP Session -- **Step:** `Start/Stop SDSP Session (STOP)` +- **Step:** `Stop SDSP Session` - **Action:** Terminates the SDSP session. - **Purpose:** Cleanly closes the connection. diff --git a/docs/scenarios/sdsp-f3623/sdsp_track.md b/docs/scenarios/sdsp-f3623/sdsp_track.md index e481543f..d5824f08 100644 --- a/docs/scenarios/sdsp-f3623/sdsp_track.md +++ b/docs/scenarios/sdsp-f3623/sdsp_track.md @@ -10,7 +10,7 @@ The scenario executes the following sequence of steps: ### 1. Start SDSP Session -- **Step:** `Start/Stop SDSP Session (START)` +- **Step:** `Start SDSP Session` - **Action:** Initiates a new SDSP session with a unique UUID. - **Context:** Signals the beginning of a data provision session. @@ -40,7 +40,7 @@ The scenario executes the following sequence of steps: - **Context:** Provides the time window for the verification logic to confirm the track count. ### 6. Stop SDSP Session -- **Step:** `Start/Stop SDSP Session (STOP)` +- **Step:** `Stop SDSP Session` - **Action:** Terminates the SDSP session. - **Purpose:** Cleanly closes the connection. diff --git a/scenarios/README.md b/scenarios/README.md index 21bb2099..6809e487 100644 --- a/scenarios/README.md +++ b/scenarios/README.md @@ -17,9 +17,8 @@ steps: - step: Generate UUID - id: start_session - step: Start / Stop SDSP Session + step: Start SDSP Session arguments: - action: START session_id: ${{ steps.Generate UUID.result }} - step: Wait X seconds @@ -37,9 +36,8 @@ steps: arguments: duration: 5 - - step: Start / Stop SDSP Session + - step: Stop SDSP Session arguments: - action: STOP session_id: ${{ steps.Generate UUID.result }} ``` @@ -134,7 +132,7 @@ python -m pytest tests/test_yaml_scenarios.py -q --tb=no ``` ## Discovering Available Operations -The system exposes registered operations used in YAML (e.g., `Generate UUID`, `Wait X seconds`, `Start / Stop SDSP Session`). These are provided by clients and discovered at runtime. In the web editor, you can browse and insert these operations directly. +The system exposes registered operations used in YAML (e.g., `Generate UUID`, `Wait X seconds`, `Start SDSP Session`, `Stop SDSP Session`). These are provided by clients and discovered at runtime. In the web editor, you can browse and insert these operations directly. ## Tips - Keep `id` short and unique if you plan to reference a step later. diff --git a/scenarios/sdsp-f3623/sdsp_heartbeat.yaml b/scenarios/sdsp-f3623/sdsp_heartbeat.yaml index e34fa1d7..a72ecb48 100644 --- a/scenarios/sdsp-f3623/sdsp_heartbeat.yaml +++ b/scenarios/sdsp-f3623/sdsp_heartbeat.yaml @@ -5,9 +5,8 @@ steps: - step: Generate UUID - id: start_session - step: Start / Stop SDSP Session + step: Start SDSP Session arguments: - action: START session_id: ${{ steps.Generate UUID.result }} - step: Wait X seconds @@ -25,7 +24,6 @@ steps: arguments: duration: 5 - - step: Start / Stop SDSP Session + - step: Stop SDSP Session arguments: - action: STOP session_id: ${{ steps.Generate UUID.result }} diff --git a/scenarios/sdsp-f3623/sdsp_track.yaml b/scenarios/sdsp-f3623/sdsp_track.yaml index bec7867e..652466b3 100644 --- a/scenarios/sdsp-f3623/sdsp_track.yaml +++ b/scenarios/sdsp-f3623/sdsp_track.yaml @@ -3,10 +3,9 @@ description: Runs the SDSP track scenario. steps: - step: Generate UUID - id: start_sdsp_session - step: Start / Stop SDSP Session + step: Start SDSP Session arguments: session_id: ${{ steps.Generate UUID.result }} - action: START - id: stream_air_traffic step: Stream Air Traffic arguments: @@ -27,9 +26,8 @@ steps: arguments: duration: 5 - id: stop_sdsp_session - step: Start / Stop SDSP Session + step: Stop SDSP Session arguments: session_id: ${{ steps.Generate UUID.result }} - action: STOP needs: - stream_air_traffic diff --git a/scenarios/sdsp-f3623/verify_sdsp_metrics.yaml b/scenarios/sdsp-f3623/verify_sdsp_metrics.yaml index 169b2b3c..e41b96dc 100644 --- a/scenarios/sdsp-f3623/verify_sdsp_metrics.yaml +++ b/scenarios/sdsp-f3623/verify_sdsp_metrics.yaml @@ -16,10 +16,9 @@ steps: description: Generate a unique session ID for this test run, this is used to create a SDSP session, the default.yaml config step: Generate UUID - id: start_sdsp_session - step: Start / Stop SDSP Session + step: Start SDSP Session arguments: session_id: ${{ steps.generated_sdsp_session_id.result }} - action: START - id: wait_10_seconds step: Wait X seconds arguments: @@ -31,9 +30,8 @@ steps: observations: ${{ steps.stream_air_traffic.result.observations }} # session_id: ${{ steps.generated_sdsp_session_id.result }} - id: stop_sdsp_session - step: Start / Stop SDSP Session + step: Stop SDSP Session arguments: session_id: ${{ steps.generated_sdsp_session_id.result }} - action: STOP needs: - stream_air_traffic diff --git a/src/openutm_verification/core/clients/flight_blender/flight_blender_client.py b/src/openutm_verification/core/clients/flight_blender/flight_blender_client.py index 8f978bb8..a9250bf1 100644 --- a/src/openutm_verification/core/clients/flight_blender/flight_blender_client.py +++ b/src/openutm_verification/core/clients/flight_blender/flight_blender_client.py @@ -1145,36 +1145,36 @@ async def list_sensor_failure_notifications(self) -> StepResult: result=f"Retrieved {len(notifications)} sensor failure notifications", ) - @scenario_step("Start / Stop SDSP Session") - async def start_stop_sdsp_session(self, session_id: str, action: SDSPSessionAction) -> str: - """ - Starts or stops an SDSP (Strategic Deconfliction Service Provider) session based on the specified action. - This method interacts with the Flight Blender service to manage the lifecycle of an SDSP session. - It can be used to initiate a new session or terminate an existing one. - Args: - session_id (str): The unique identifier of the SDSP session to start or stop. - action (SDSPSessionAction): The action to perform on the session, such as START or STOP. - Returns: - bool: True if the action was successfully performed, False otherwise. - Raises: - ValueError: If the session_id is invalid or the action is not supported. - ConnectionError: If there is an issue communicating with the Flight Blender service. - FlightBlenderError: If the action fails due to service errors. - """ - + async def _sdsp_session_action(self, session_id: str, action: SDSPSessionAction) -> str: endpoint = f"/surveillance_monitoring_ops/start_stop_surveillance_heartbeat_track/{session_id}" - payload = {"action": action.value} response = await self.put(endpoint, json=payload) logger.info(f"SDSP session {session_id} action {action.value} response: {response.status_code}") if response.status_code == 200: logger.info(f"SDSP session {session_id} action {action.value} completed successfully.") return f"{action.value} Heartbeat Track message received for {session_id}" - else: logger.error(f"Failed to perform action {action.value} on SDSP session {session_id}. Response: {response.text}") raise FlightBlenderError(f"{action.value} Heartbeat Track message not received for {session_id}") + @scenario_step("Start SDSP Session", phase=FlightPhase.PRE_FLIGHT) + async def start_sdsp_session(self, session_id: str) -> str: + """Starts an SDSP (Strategic Deconfliction Service Provider) session. + + Args: + session_id: The unique identifier of the SDSP session to start. + """ + return await self._sdsp_session_action(session_id, SDSPSessionAction.START) + + @scenario_step("Stop SDSP Session", phase=FlightPhase.POST_FLIGHT) + async def stop_sdsp_session(self, session_id: str) -> str: + """Stops an SDSP (Strategic Deconfliction Service Provider) session. + + Args: + session_id: The unique identifier of the SDSP session to stop. + """ + return await self._sdsp_session_action(session_id, SDSPSessionAction.STOP) + async def initialize_heartbeat_websocket_connection(self, session_id: str) -> ClientConnection: endpoint = f"/ws/surveillance/heartbeat/{session_id}" ws = await self.create_websocket_connection(endpoint=endpoint) diff --git a/src/openutm_verification/scenarios/test_sdsp_track_with_bluesky_sim.py b/src/openutm_verification/scenarios/test_sdsp_track_with_bluesky_sim.py index e43d8bab..452553d8 100644 --- a/src/openutm_verification/scenarios/test_sdsp_track_with_bluesky_sim.py +++ b/src/openutm_verification/scenarios/test_sdsp_track_with_bluesky_sim.py @@ -8,7 +8,6 @@ FlightBlenderClient, ) from openutm_verification.core.reporting.reporting_models import StepResult -from openutm_verification.models import SDSPSessionAction from openutm_verification.scenarios.registry import register_scenario @@ -23,8 +22,7 @@ async def sdsp_track_with_bluesky_sim( session_id = str(uuid.uuid4()) logger.info(f"Starting SDSP track scenario with session ID: {session_id}") - await fb_client.start_stop_sdsp_session( - action=SDSPSessionAction.START, + await fb_client.start_sdsp_session( session_id=session_id, ) @@ -47,8 +45,7 @@ async def sdsp_track_with_bluesky_sim( await asyncio.sleep(5) - await fb_client.start_stop_sdsp_session( - action=SDSPSessionAction.STOP, + await fb_client.stop_sdsp_session( session_id=session_id, ) diff --git a/tests/test_client_steps.py b/tests/test_client_steps.py index 61b154c1..46662d0e 100644 --- a/tests/test_client_steps.py +++ b/tests/test_client_steps.py @@ -12,7 +12,7 @@ from openutm_verification.core.clients.flight_blender.flight_blender_client import FlightBlenderClient from openutm_verification.core.clients.opensky.opensky_client import OpenSkyClient from openutm_verification.core.reporting.reporting_models import Status -from openutm_verification.models import OperationState, SDSPSessionAction +from openutm_verification.models import OperationState from openutm_verification.simulator.models.flight_data_types import FlightObservationSchema @@ -267,17 +267,28 @@ async def test_submit_air_traffic(fb_client): fb_client.post.assert_called_once() -async def test_start_stop_sdsp_session(fb_client): +async def test_start_sdsp_session(fb_client): mock_response = MagicMock() mock_response.status_code = 200 fb_client.put.return_value = mock_response - result = await fb_client.start_stop_sdsp_session(session_id="sess_123", action=SDSPSessionAction.START) + result = await fb_client.start_sdsp_session(session_id="sess_123") assert "start Heartbeat Track message received" in result.result fb_client.put.assert_called_once() +async def test_stop_sdsp_session(fb_client): + mock_response = MagicMock() + mock_response.status_code = 200 + fb_client.put.return_value = mock_response + + result = await fb_client.stop_sdsp_session(session_id="sess_123") + + assert "stop Heartbeat Track message received" in result.result + fb_client.put.assert_called_once() + + async def test_initialize_verify_sdsp_track(fb_client): mock_ws = MagicMock() # Simulate messages: 2 initial + 3 valid tracks diff --git a/tests/test_yaml_scenarios.py b/tests/test_yaml_scenarios.py index 6ebbceb4..8d427838 100644 --- a/tests/test_yaml_scenarios.py +++ b/tests/test_yaml_scenarios.py @@ -32,7 +32,8 @@ def mock_clients(): # Mock methods that return values used in other steps fb_client.upload_geo_fence.return_value = {"id": "geo_fence_123"} fb_client.upload_flight_declaration.return_value = {"id": "flight_decl_123", "is_approved": True} - fb_client.start_stop_sdsp_session.return_value = "Session Started" + fb_client.start_sdsp_session.return_value = "Session Started" + fb_client.stop_sdsp_session.return_value = "Session Stopped" # Mock methods that return objects with attributes accessed in YAML # e.g. ${{ steps.stream_air_traffic.result.observations }}