From 1366212e6cefdc58e877af5850fc668ef531af36 Mon Sep 17 00:00:00 2001 From: Julien Perrochet Date: Thu, 14 Nov 2024 15:45:19 +0100 Subject: [PATCH] [uss_qualifier] netrid: cover net0260 timestamp accuracy (#822) --- monitoring/monitorlib/fetch/rid.py | 15 ++++++ .../astm/netrid/display_data_evaluator.py | 54 ++++++++++++++++++- .../astm/netrid/v19/nominal_behavior.md | 8 +++ .../astm/netrid/v22a/nominal_behavior.md | 8 +++ .../suites/astm/netrid/f3411_19.md | 7 ++- .../suites/astm/netrid/f3411_22a.md | 7 ++- .../suites/uspace/network_identification.md | 7 ++- .../suites/uspace/required_services.md | 7 ++- 8 files changed, 108 insertions(+), 5 deletions(-) diff --git a/monitoring/monitorlib/fetch/rid.py b/monitoring/monitorlib/fetch/rid.py index 8efcb7938d..e03abd045c 100644 --- a/monitoring/monitorlib/fetch/rid.py +++ b/monitoring/monitorlib/fetch/rid.py @@ -343,6 +343,21 @@ def timestamp(self) -> Optional[StringBasedDateTime]: f"Cannot retrieve speed using RID version {self.rid_version}" ) + @property + def timestamp_accuracy(self) -> Optional[float]: + if self.rid_version == RIDVersion.f3411_19: + if not self.v19_value.has_field_with_value("current_state"): + return None + return self.v19_value.current_state.timestamp_accuracy + elif self.rid_version == RIDVersion.f3411_22a: + if not self.v22a_value.has_field_with_value("current_state"): + return None + return self.v22a_value.current_state.timestamp_accuracy + else: + raise NotImplementedError( + f"Cannot retrieve speed using RID version {self.rid_version}" + ) + def errors(self) -> List[str]: try: rid_version = self.rid_version diff --git a/monitoring/uss_qualifier/scenarios/astm/netrid/display_data_evaluator.py b/monitoring/uss_qualifier/scenarios/astm/netrid/display_data_evaluator.py index 0824637b84..030eb67660 100644 --- a/monitoring/uss_qualifier/scenarios/astm/netrid/display_data_evaluator.py +++ b/monitoring/uss_qualifier/scenarios/astm/netrid/display_data_evaluator.py @@ -49,6 +49,7 @@ def _rect_str(rect) -> str: VERTICAL_SPEED_PRECISION = 0.1 SPEED_PRECISION = 0.05 +TIMESTAMP_ACCURACY_PRECISION = 0.05 @dataclass @@ -68,6 +69,16 @@ def most_recent_position(self) -> Optional[Position]: def flight(self) -> fetch.rid.Flight: return self.query.flights[self.flight_index] + # TODO we may rather want to expose the whole flight object (self.query.flights[self.flight]) + # and let callers access subfields directly (will be handled in separate PR) + @property + def timestamp_accuracy(self) -> Optional[float]: + return self.query.flights[self.flight_index].timestamp_accuracy + + @property + def raw_flight(self) -> dict: + return self.query.query.response.json["flights"][self.flight_index] + ObservationType = Union[Flight, DPObservedFlight] @@ -898,7 +909,7 @@ def _evaluate_normal_sp_observation( participants=[mapping.injected_flight.uss_participant_id], ) - # Check that altitudes match for any observed flights matching injected flights + # Check that required fields are present and match for any observed flights matching injected flights for mapping in mappings.values(): injected_telemetry = mapping.injected_flight.flight.telemetry[ mapping.telemetry_index @@ -1036,6 +1047,47 @@ def _evaluate_normal_sp_observation( details=f"{mapping.injected_flight.uss_participant_id}'s flight with injection ID {mapping.injected_flight.flight.injection_id} in test {mapping.injected_flight.test_id} had telemetry index {mapping.telemetry_index} at {injected_telemetry.timestamp} with track={injected_telemetry.track}, but Service Provider reported track={mapping.observed_flight.flight.raw.current_state.track} at {mapping.observed_flight.query.query.request.initiated_at}", ) + # Due to how implicit dicts are deserialized and the timestamp_accuracy is specified in the OpenAPI file for F3411-v22a, + # we need to look into the raw JSON response to determine if the field is present: + # + # Because the spec requires the field to be present while also specifying a default value, the implicit dict based class derived + # from the spec may not catch that a field is missing at deserialization time (because the RIDAircraftState class specifies a default + # value for the field, no ValueError will be thrown when ImplicitDict.parse() is called). + # + # This means that a missing json field will neither raise an exception nor cause the field to be set to None when we access it, + # meaning this part of the logic cannot rely on the deserialized value to determine if the field was present or not. + raw_flight = mapping.observed_flight.raw_flight + raw_state = ( + raw_flight["current_state"] if "current_state" in raw_flight else {} + ) + with self._test_scenario.check( + "Service Provider timestamp accuracy is present", + [mapping.injected_flight.uss_participant_id], + ) as check: + if "timestamp_accuracy" not in raw_state: + check.record_failed( + "Timestamp accuracy not present in Service Provider response", + details=f"Timestamp accuracy not present in Service Provider {mapping.injected_flight.uss_participant_id}'s response for flight with injection ID {mapping.injected_flight.flight.injection_id} in test {mapping.injected_flight.test_id} with telemetry index {mapping.telemetry_index}", + ) + + if "timestamp_accuracy" in raw_state: + # From this point on we can use the 'timestamp_accuracy' field of the deserialized object + with self._test_scenario.check( + "Service Provider timestamp accuracy is correct", + [mapping.injected_flight.uss_participant_id], + ) as check: + if ( + abs( + mapping.observed_flight.timestamp_accuracy + - injected_telemetry.timestamp_accuracy + ) + > TIMESTAMP_ACCURACY_PRECISION + ): + check.record_failed( + "Timestamp accuracy in Service Provider response is incorrect", + details=f"Timestamp accuracy in Service Provider {mapping.injected_flight.uss_participant_id}'s response for flight with injection ID {mapping.injected_flight.flight.injection_id} in test {mapping.injected_flight.test_id} with telemetry index {mapping.telemetry_index} is {mapping.observed_flight.timestamp_accuracy} which is not equal to the injected value of {injected_telemetry.timestamp_accuracy}", + ) + # Verify that flight details queries succeeded and returned correctly-formatted data for mapping in mappings.values(): details_queries = [ diff --git a/monitoring/uss_qualifier/scenarios/astm/netrid/v19/nominal_behavior.md b/monitoring/uss_qualifier/scenarios/astm/netrid/v19/nominal_behavior.md index 2364386883..1da64737ba 100644 --- a/monitoring/uss_qualifier/scenarios/astm/netrid/v19/nominal_behavior.md +++ b/monitoring/uss_qualifier/scenarios/astm/netrid/v19/nominal_behavior.md @@ -112,6 +112,14 @@ The identity of flights is determined by precisely matching the known injected p **[astm.f3411.v19.NET0260,Table1,16](../../../../requirements/astm/f3411/v19.md)** requires that relevant Remote ID data, consistent with the common data dictionary, be reported by the Service Provider. Injected flight data had a specified horizontal accuracy that was different from the reported one. +#### ⚠️ Service Provider timestamp accuracy is present check + +If the timestamp accuracy is not present, the USS under test is not properly implementing the REST interface specified by the OpenAPI definition contained in Annex A4, and is therefore in violation of **[astm.f3411.v19.NET0710,1](../../../../requirements/astm/f3411/v19.md)**. + +#### ⚠️ Service Provider timestamp accuracy is correct check + +**[astm.f3411.v19.NET0260,Table1,5](../../../../requirements/astm/f3411/v19.md)** requires that relevant Remote ID data, consistent with the common data dictionary, be reported by the Service Provider. The observed timestamp accuracy differs from the injected one. + #### Successful flight details query check **[astm.f3411.v19.NET0710,2](../../../../requirements/astm/f3411/v19.md)** and **[astm.f3411.v19.NET0340](../../../../requirements/astm/f3411/v19.md)** require a Service Provider to implement the GET flight details endpoint. This check will fail if uss_qualifier cannot query that endpoint (specified in the ISA present in the DSS) successfully. diff --git a/monitoring/uss_qualifier/scenarios/astm/netrid/v22a/nominal_behavior.md b/monitoring/uss_qualifier/scenarios/astm/netrid/v22a/nominal_behavior.md index e3cc2f3d3e..fcaeb8160d 100644 --- a/monitoring/uss_qualifier/scenarios/astm/netrid/v22a/nominal_behavior.md +++ b/monitoring/uss_qualifier/scenarios/astm/netrid/v22a/nominal_behavior.md @@ -112,6 +112,14 @@ The identity of flights is determined by precisely matching the known injected p **[astm.f3411.v22a.NET0260,Table1,17](../../../../requirements/astm/f3411/v22a.md)** requires that relevant Remote ID data, consistent with the common data dictionary, be reported by the Service Provider. Injected flight data had a specified horizontal accuracy that was different from the reported one. +#### ⚠️ Service Provider timestamp accuracy is present check + +If the timestamp accuracy is not present, the USS under test is not properly implementing the REST interface specified by the OpenAPI definition contained in Annex A4, and is therefore in violation of **[astm.f3411.v22a.NET0710,1](../../../../requirements/astm/f3411/v22a.md)**. + +#### ⚠️ Service Provider timestamp accuracy is correct check + +**[astm.f3411.v22a.NET0260,Table1,6](../../../../requirements/astm/f3411/v22a.md)** requires that relevant Remote ID data, consistent with the common data dictionary, be reported by the Service Provider. The observed timestamp accuracy differs from the injected one. + #### Successful flight details query check **[astm.f3411.v22a.NET0710,2](../../../../requirements/astm/f3411/v22a.md)** and **[astm.f3411.v22a.NET0340](../../../../requirements/astm/f3411/v22a.md) require a Service Provider to implement the GET flight details endpoint. This check will fail if uss_qualifier cannot query that endpoint (specified in the ISA present in the DSS) successfully. diff --git a/monitoring/uss_qualifier/suites/astm/netrid/f3411_19.md b/monitoring/uss_qualifier/suites/astm/netrid/f3411_19.md index 1fbf55b384..a32a77e1aa 100644 --- a/monitoring/uss_qualifier/suites/astm/netrid/f3411_19.md +++ b/monitoring/uss_qualifier/suites/astm/netrid/f3411_19.md @@ -21,7 +21,7 @@ Checked in - astm
.f3411
.v19
+ astm
.f3411
.v19
DSS0010 Implemented ASTM NetRID DSS: Token Validation @@ -286,6 +286,11 @@ Implemented ASTM NetRID nominal behavior + + NET0260,Table1,5 + Implemented + ASTM NetRID nominal behavior + NET0260,Table1,9 Implemented diff --git a/monitoring/uss_qualifier/suites/astm/netrid/f3411_22a.md b/monitoring/uss_qualifier/suites/astm/netrid/f3411_22a.md index c3eaab2923..793bff05dc 100644 --- a/monitoring/uss_qualifier/suites/astm/netrid/f3411_22a.md +++ b/monitoring/uss_qualifier/suites/astm/netrid/f3411_22a.md @@ -21,7 +21,7 @@ Checked in - astm
.f3411
.v22a
+ astm
.f3411
.v22a
DSS0010 Implemented ASTM NetRID DSS: Token Validation @@ -326,6 +326,11 @@ Implemented ASTM NetRID nominal behavior + + NET0260,Table1,6 + Implemented + ASTM NetRID nominal behavior + NET0260,Table1,7 Implemented diff --git a/monitoring/uss_qualifier/suites/uspace/network_identification.md b/monitoring/uss_qualifier/suites/uspace/network_identification.md index 685dba16ac..790fd6fccc 100644 --- a/monitoring/uss_qualifier/suites/uspace/network_identification.md +++ b/monitoring/uss_qualifier/suites/uspace/network_identification.md @@ -17,7 +17,7 @@ Checked in - astm
.f3411
.v22a
+ astm
.f3411
.v22a
DSS0010 Implemented ASTM NetRID DSS: Token Validation @@ -322,6 +322,11 @@ Implemented ASTM NetRID nominal behavior + + NET0260,Table1,6 + Implemented + ASTM NetRID nominal behavior + NET0260,Table1,7 Implemented diff --git a/monitoring/uss_qualifier/suites/uspace/required_services.md b/monitoring/uss_qualifier/suites/uspace/required_services.md index f5aa55e9c5..4365971fcc 100644 --- a/monitoring/uss_qualifier/suites/uspace/required_services.md +++ b/monitoring/uss_qualifier/suites/uspace/required_services.md @@ -18,7 +18,7 @@ Checked in - astm
.f3411
.v22a
+ astm
.f3411
.v22a
DSS0010 Implemented ASTM NetRID DSS: Token Validation @@ -323,6 +323,11 @@ Implemented ASTM NetRID nominal behavior + + NET0260,Table1,6 + Implemented + ASTM NetRID nominal behavior + NET0260,Table1,7 Implemented