From 3a2ccc58ffeb3c870d7cb221747aa1e1a3423319 Mon Sep 17 00:00:00 2001 From: Punam Verma Date: Sun, 19 Nov 2023 16:24:50 -0800 Subject: [PATCH] Fixing PR review comments --- .../clients/flight_planning/client.py | 4 +- .../clients/flight_planning/client_scd.py | 6 +-- .../clients/flight_planning/client_v1.py | 5 +- .../flight_intents_resource.py | 1 - .../flight_planning/flight_planner.py | 2 +- .../get_op_data_validation.py | 47 +++++++---------- .../scenarios/astm/utm/test_steps.py | 50 ++++++++++++++++--- .../scenarios/flight_planning/test_steps.py | 21 ++------ 8 files changed, 72 insertions(+), 64 deletions(-) diff --git a/monitoring/monitorlib/clients/flight_planning/client.py b/monitoring/monitorlib/clients/flight_planning/client.py index babf2b2b5b..e00ab90d31 100644 --- a/monitoring/monitorlib/clients/flight_planning/client.py +++ b/monitoring/monitorlib/clients/flight_planning/client.py @@ -25,9 +25,11 @@ class PlanningActivityError(QueryError): class FlightPlannerClient(ABC): """Client to interact with a USS as a user performing flight planning activities and as the test director preparing for tests involving flight planning activities.""" + participant_id: ParticipantID + def __init__(self, participant_id: ParticipantID): self.participant_id = participant_id - self.created_flight_ids: Set[str] = set() + self.created_flight_ids: Set[FlightID] = set() super(FlightPlannerClient, self).__init__() # ===== Emulation of user actions ===== diff --git a/monitoring/monitorlib/clients/flight_planning/client_scd.py b/monitoring/monitorlib/clients/flight_planning/client_scd.py index 88227385ae..4472aefac0 100644 --- a/monitoring/monitorlib/clients/flight_planning/client_scd.py +++ b/monitoring/monitorlib/clients/flight_planning/client_scd.py @@ -131,7 +131,7 @@ def _inject( ] if response.activity_result == PlanningActivityResult.Completed: if response.flight_plan_status in created_status: - self.created_flight_ids.add(str(flight_id)) + self.created_flight_ids.add(flight_id) self._plan_statuses[flight_id] = response.flight_plan_status return response @@ -196,7 +196,7 @@ def try_end_flight( ) if resp.result == scd_api.DeleteFlightResponseResult.Closed: del self._plan_statuses[flight_id] - self.created_flight_ids.discard(str(flight_id)) + self.created_flight_ids.discard(flight_id) else: self._plan_statuses[flight_id] = response.flight_plan_status @@ -260,6 +260,4 @@ def clear_area(self, area: Volume4D) -> TestPreparationActivityResponse: else: errors = [f"[{resp.outcome.timestamp}]: {resp.outcome.message}"] - self.created_flight_ids.clear() - return TestPreparationActivityResponse(errors=errors, queries=[query]) diff --git a/monitoring/monitorlib/clients/flight_planning/client_v1.py b/monitoring/monitorlib/clients/flight_planning/client_v1.py index c5be7ed140..54d5024971 100644 --- a/monitoring/monitorlib/clients/flight_planning/client_v1.py +++ b/monitoring/monitorlib/clients/flight_planning/client_v1.py @@ -88,7 +88,7 @@ def _inject( ] if resp.planning_result == PlanningActivityResult.Completed: if resp.flight_plan_status in created_status: - self.created_flight_ids.add(str(flight_plan_id)) + self.created_flight_ids.add(flight_plan_id) response = PlanningActivityResponse( flight_id=flight_plan_id, @@ -150,7 +150,7 @@ def try_end_flight( raise PlanningActivityError( f"Response to delete flight plan could not be parsed: {str(e)}", query ) - self.created_flight_ids.discard(str(flight_id)) + self.created_flight_ids.discard(flight_id) response = PlanningActivityResponse( flight_id=flight_id, queries=[query], @@ -220,7 +220,6 @@ def clear_area(self, area: Volume4D) -> TestPreparationActivityResponse: raise PlanningActivityError( f"Response to clear area could not be parsed: {str(e)}", query ) - self.created_flight_ids.clear() if resp.outcome.success: errors = None else: diff --git a/monitoring/uss_qualifier/resources/flight_planning/flight_intents_resource.py b/monitoring/uss_qualifier/resources/flight_planning/flight_intents_resource.py index 9566191ae3..bffc95ffbc 100644 --- a/monitoring/uss_qualifier/resources/flight_planning/flight_intents_resource.py +++ b/monitoring/uss_qualifier/resources/flight_planning/flight_intents_resource.py @@ -1,4 +1,3 @@ -import json from typing import Dict from implicitdict import ImplicitDict diff --git a/monitoring/uss_qualifier/resources/flight_planning/flight_planner.py b/monitoring/uss_qualifier/resources/flight_planning/flight_planner.py index a0e94a1281..0b28f7cf79 100644 --- a/monitoring/uss_qualifier/resources/flight_planning/flight_planner.py +++ b/monitoring/uss_qualifier/resources/flight_planning/flight_planner.py @@ -1,4 +1,4 @@ -from typing import Tuple, Optional, Set, get_type_hints +from typing import Tuple, Optional, Set from urllib.parse import urlparse from implicitdict import ImplicitDict from monitoring.monitorlib import infrastructure, fetch diff --git a/monitoring/uss_qualifier/scenarios/astm/utm/data_exchange_validation/get_op_data_validation.py b/monitoring/uss_qualifier/scenarios/astm/utm/data_exchange_validation/get_op_data_validation.py index d99267e6ec..14536879b0 100644 --- a/monitoring/uss_qualifier/scenarios/astm/utm/data_exchange_validation/get_op_data_validation.py +++ b/monitoring/uss_qualifier/scenarios/astm/utm/data_exchange_validation/get_op_data_validation.py @@ -1,5 +1,6 @@ from typing import Optional -from urllib.parse import urlsplit +from monitoring.monitorlib.temporal import Time +import arrow from monitoring.monitorlib.clients.flight_planning.client import FlightPlannerClient from monitoring.uss_qualifier.resources.astm.f3548.v21 import DSSInstanceResource @@ -7,14 +8,12 @@ from monitoring.uss_qualifier.resources.flight_planning import ( FlightIntentsResource, ) -from monitoring.uss_qualifier.resources.flight_planning.flight_intent import ( - FlightIntent, -) from monitoring.uss_qualifier.resources.flight_planning.flight_planners import ( FlightPlannerResource, ) from monitoring.monitorlib.geotemporal import Volume4DCollection from monitoring.monitorlib.clients.flight_planning.flight_info import FlightInfo + from monitoring.uss_qualifier.resources.interuss.mock_uss.client import ( MockUSSClient, MockUSSResource, @@ -36,13 +35,11 @@ plan_flight, delete_flight, ) -from implicitdict import StringBasedDateTime -from datetime import datetime class GetOpResponseDataValidationByUSS(TestScenario): - flight_1: FlightIntent - flight_2: FlightIntent + flight_1: FlightInfo + flight_2: FlightInfo tested_uss_client: FlightPlannerClient control_uss: MockUSSClient @@ -70,18 +67,15 @@ def __init__( ) raise ScenarioCannotContinueError(msg) + t = Time(arrow.utcnow().datetime) _flight_intents = { - k: FlightIntent.from_flight_info_template(v) - for k, v in flight_intents.get_flight_intents().items() + k: v.resolve(t) for k, v in flight_intents.get_flight_intents().items() } extents = [] for intent in _flight_intents.values(): - extents.extend(intent.request.operational_intent.volumes) - extents.extend(intent.request.operational_intent.off_nominal_volumes) - self._intents_extent = Volume4DCollection.from_interuss_scd_api( - extents - ).bounding_volume.to_f3548v21() + extents.append(intent.basic_information.area.bounding_volume) + self._intents_extent = Volume4DCollection(extents).bounding_volume.to_f3548v21() try: (self.flight_1, self.flight_2,) = ( @@ -89,12 +83,8 @@ def __init__( _flight_intents["flight_2"], ) - assert not Volume4DCollection.from_interuss_scd_api( - self.flight_1.request.operational_intent.volumes - ).intersects_vol4s( - Volume4DCollection.from_interuss_scd_api( - self.flight_2.request.operational_intent.volumes - ) + assert not self.flight_1.basic_information.area.intersects_vol4s( + self.flight_2.basic_information.area ), "flight_1 and flight_2 must not intersect" except KeyError as e: @@ -141,10 +131,10 @@ def _tested_uss_plans_deconflicted_flight_near_existing_flight(self): self, "Control_uss plans flight 2", self.control_uss_client, - FlightInfo.from_scd_inject_flight_request(self.flight_2.request), + self.flight_2, ) - flight_2_oi_ref = validator.expect_shared(self.flight_2.request) + validator.expect_shared(self.flight_2) self.begin_test_step( "Precondition - check tested_uss has no subscription in flight 2 area" @@ -163,11 +153,11 @@ def _tested_uss_plans_deconflicted_flight_near_existing_flight(self): self, "Tested_uss plans flight 1", self.tested_uss_client, - FlightInfo.from_scd_inject_flight_request(self.flight_1.request), + self.flight_1, ) - flight_1_oi_ref = validator.expect_shared( - self.flight_1.request, + validator.expect_shared( + self.flight_1, ) self.begin_test_step("Validate flight2 GET interaction") @@ -186,7 +176,7 @@ def _tested_uss_plans_deconflicted_flight_near_existing_flight(self): ) def _tested_uss_unable_to_plan_flight_near_invalid_shared_existing_flight(self): - req = self.flight_2.request + flight_info = self.flight_2 # Modifying the request with invalid data behavior = MockUssFlightBehavior( modify_sharing_methods=["GET", "POST"], @@ -196,7 +186,6 @@ def _tested_uss_unable_to_plan_flight_near_invalid_shared_existing_flight(self): }, ) - flight_info = FlightInfo.from_scd_inject_flight_request(req) additional_fields = {"behavior": behavior} _, self.flight_2_id = plan_flight( @@ -223,7 +212,7 @@ def _tested_uss_unable_to_plan_flight_near_invalid_shared_existing_flight(self): self, "Tested_uss attempts to plan flight 1, expect failure", self.tested_uss_client, - FlightInfo.from_scd_inject_flight_request(self.flight_1.request), + self.flight_1, ) self.begin_test_step("Validate flight 1 not shared by tested_uss") diff --git a/monitoring/uss_qualifier/scenarios/astm/utm/test_steps.py b/monitoring/uss_qualifier/scenarios/astm/utm/test_steps.py index 1021a20c1f..df805e9704 100644 --- a/monitoring/uss_qualifier/scenarios/astm/utm/test_steps.py +++ b/monitoring/uss_qualifier/scenarios/astm/utm/test_steps.py @@ -11,11 +11,16 @@ OperationalIntentReference, ) +from monitoring.monitorlib.clients.flight_planning.flight_info import ( + UasState, + AirspaceUsageState, +) from monitoring.uss_qualifier.common_data_definitions import Severity from monitoring.uss_qualifier.resources.astm.f3548.v21.dss import DSSInstance from monitoring.uss_qualifier.resources.flight_planning.flight_planner import ( FlightPlanner, ) +from monitoring.monitorlib.clients.flight_planning.flight_info import FlightInfo from monitoring.uss_qualifier.scenarios.astm.utm.evaluation import ( validate_op_intent_details, ) @@ -141,7 +146,9 @@ def expect_not_shared(self) -> None: self._scenario.end_test_step() def expect_shared( - self, flight_intent: InjectFlightRequest, skip_if_not_found: bool = False + self, + flight_intent: Union[InjectFlightRequest, FlightInfo], + skip_if_not_found: bool = False, ) -> Optional[OperationalIntentReference]: """Validate that operational intent information was correctly shared for a flight intent. @@ -177,8 +184,23 @@ def expect_shared( if modified_oi_ref is None: if not skip_if_not_found: if ( - flight_intent.operational_intent.state - == OperationalIntentState.Activated + (isinstance(flight_intent, InjectFlightRequest)) + and ( + flight_intent.operational_intent.state + == OperationalIntentState.Activated + ) + ) or ( + isinstance(flight_intent, FlightInfo) + and ( + ( + flight_intent.basic_information.uas_state + == UasState.Nominal + ) + and ( + flight_intent.basic_information.usage_state + == AirspaceUsageState.InUse + ) + ) ): with self._scenario.check( "Operational intent for active flight not deleted", @@ -258,13 +280,25 @@ def expect_shared( with self._scenario.check( "Correct operational intent details", [self._flight_planner.participant_id] ) as check: - error_text = validate_op_intent_details( - oi_full.details, - flight_intent.operational_intent.priority, - Volume4DCollection.from_interuss_scd_api( + priority = ( + flight_intent.operational_intent.priority + if isinstance(flight_intent, InjectFlightRequest) + else flight_intent.astm_f3548_21.priority + ) + if isinstance(flight_intent, InjectFlightRequest): + priority = flight_intent.operational_intent.priority + vols = Volume4DCollection.from_interuss_scd_api( flight_intent.operational_intent.volumes + flight_intent.operational_intent.off_nominal_volumes - ).bounding_volume.to_f3548v21(), + ) + elif isinstance(flight_intent, FlightInfo): + priority = flight_intent.astm_f3548_21.priority + vols = flight_intent.basic_information.area + + error_text = validate_op_intent_details( + oi_full.details, + priority, + vols.bounding_volume.to_f3548v21(), ) if error_text: check.record_failed( diff --git a/monitoring/uss_qualifier/scenarios/flight_planning/test_steps.py b/monitoring/uss_qualifier/scenarios/flight_planning/test_steps.py index 5473de21ec..b3a1caffbe 100644 --- a/monitoring/uss_qualifier/scenarios/flight_planning/test_steps.py +++ b/monitoring/uss_qualifier/scenarios/flight_planning/test_steps.py @@ -53,7 +53,7 @@ def plan_flight_intent( flight_intent: InjectFlightRequest, ) -> Tuple[InjectFlightResponse, Optional[str]]: """Plan a flight intent that should result in success. - Note: This method will be deprecated in favor of plan_flight + Note: This method is deprecated in favor of plan_flight This function implements the test step described in plan_flight_intent.md. @@ -203,7 +203,7 @@ def submit_flight_intent( flight_id: Optional[str] = None, ) -> Tuple[InjectFlightResponse, Optional[str]]: """Submit a flight intent with an expected result. - Note: This method will be deprecated in favor of submit_flight + Note: This method is deprecated in favor of submit_flight A check fail is considered by default of high severity and as such will raise an ScenarioCannotContinueError. The severity of each failed check may be overridden if needed. @@ -273,7 +273,7 @@ def delete_flight_intent( flight_id: str, ) -> DeleteFlightResponse: """Delete an existing flight intent that should result in success. - Note: This method will be deprecated in favor of delete_flight + Note: This method is deprecated in favor of delete_flight A check fail is considered of high severity and as such will raise an ScenarioCannotContinueError. @@ -319,7 +319,7 @@ def cleanup_flights( scenario: TestScenarioType, flight_planners: Iterable[FlightPlanner] ) -> None: """Remove flights during a cleanup test step. - Note: This method will be deprecated in favor of cleanup_flights_fp_client + Note: This method is deprecated in favor of cleanup_flights_fp_client This function assumes: * `scenario` is currently cleaning up (cleanup has started) @@ -468,12 +468,7 @@ def request_flight( additional_fields: Optional[dict] = None, ) -> Tuple[PlanningActivityResponse, Query, str]: """ - This method is needed till we are able to have checks with PlanningActivityResult. Uses FlightPlannerClient to plan the flight - Args: - flight_planner: - flight_info: - flight_id: Returns: * Response from planning activity to request new flight or update existing flight @@ -502,15 +497,7 @@ def request_flight( def cleanup_flight( flight_planner: FlightPlannerClient, flight_id: str ) -> Tuple[PlanningActivityResponse, Query]: - """ - This method is required till we are able to have checks with PlanningActivityResult - Args: - flight_planner: - flight_id: - - Returns: - """ try: resp = flight_planner.try_end_flight(flight_id, ExecutionStyle.IfAllowed) except PlanningActivityError as e: