diff --git a/monitoring/monitorlib/mutate/scd.py b/monitoring/monitorlib/mutate/scd.py index 3543fe2c58..818f27470c 100644 --- a/monitoring/monitorlib/mutate/scd.py +++ b/monitoring/monitorlib/mutate/scd.py @@ -9,6 +9,7 @@ OperationID, Subscription, PutSubscriptionParameters, + OperationalIntentReference, ) from yaml.representer import Representer @@ -51,6 +52,22 @@ def subscription(self) -> Optional[Subscription]: except ValueError: return None + @property + def operational_intent_references(self) -> List[OperationalIntentReference]: + if self.json_result is None: + return [] + try: + if "operational_intent_references" not in self.json_result: + return [] + oirs_json = self.json_result["operational_intent_references"] + if not isinstance(oirs_json, list): + return [] + return [ + ImplicitDict.parse(oir, OperationalIntentReference) for oir in oirs_json + ] + except ValueError: + return [] + yaml.add_representer(MutatedSubscription, Representer.represent_dict) diff --git a/monitoring/prober/infrastructure.py b/monitoring/prober/infrastructure.py index d29533be0a..f941fe8c95 100644 --- a/monitoring/prober/infrastructure.py +++ b/monitoring/prober/infrastructure.py @@ -99,7 +99,8 @@ def wrapper_default_scope(*args, **kwargs): ResourceType = int resource_type_code_descriptions: Dict[ResourceType, str] = {} -# Next code: 388 + +# Next code: 389 def register_resource_type(code: int, description: str) -> ResourceType: """Register that the specified code refers to the described resource. diff --git a/monitoring/uss_qualifier/scenarios/astm/utm/dss/subscription_interactions.md b/monitoring/uss_qualifier/scenarios/astm/utm/dss/subscription_interactions.md index 31aeb3947b..047795456f 100644 --- a/monitoring/uss_qualifier/scenarios/astm/utm/dss/subscription_interactions.md +++ b/monitoring/uss_qualifier/scenarios/astm/utm/dss/subscription_interactions.md @@ -77,4 +77,26 @@ are in violation of **[astm.f3548.v21.DSS0210,A2-7-2,4b](../../../../requirement More specifically, they are breaking the above requirement by failing one or both of the following requirements: +## Subscription creation returns relevant OIRs test case + +This test case checks that, when a newly crete subscription intersects with an existing OIR and that the subscription is intended for operational intent references, +the DSS includes the relevant OIRs in the response to the creation. + +### Create a subscription at every DSS in sequence test step + +This test step will create a new subscription at every DSS, in sequence, each time verifying that the DSS +returns any OIRs that intersect with the newly created subscription. + +Note that this step is run once for each involved DSS (that is, once for the primary DSS and once for every secondary DSS) + +#### [Create subscription](./fragments/sub/crud/create_query.md) + +Check that the subscription creation succeeds + +#### 🛑 DSS response contains the expected OIRs check + +The response from a DSS to a valid subscription creation request is expected to contain any relevant OIRs for the subscription's extents if the subscription had the `notify_for_op_intents` flag set to `true`. + +If the DSS omits the intersecting OIR, it fails to comply with **[astm.f3548.v21.DSS0210,A2-7-2,4a](../../../../requirements/astm/f3548/v21.md)**. + ## [Cleanup](./clean_workspace.md) diff --git a/monitoring/uss_qualifier/scenarios/astm/utm/dss/subscription_interactions.py b/monitoring/uss_qualifier/scenarios/astm/utm/dss/subscription_interactions.py index 908e51068d..2f841cf39a 100644 --- a/monitoring/uss_qualifier/scenarios/astm/utm/dss/subscription_interactions.py +++ b/monitoring/uss_qualifier/scenarios/astm/utm/dss/subscription_interactions.py @@ -12,6 +12,7 @@ ) from uas_standards.astm.f3548.v21.constants import Scope +from monitoring.monitorlib import fetch from monitoring.monitorlib.delay import sleep from monitoring.monitorlib.fetch import QueryError, Query from monitoring.monitorlib.geotemporal import Volume4D @@ -44,14 +45,19 @@ class SubscriptionInteractions(TestScenario): A scenario that tests interactions between subscriptions and entities across a DSS cluster. """ - SUB_TYPES = [ - register_resource_type(385, "Subscription"), - register_resource_type(386, "Subscription"), + BG_SUB_TYPES = [ + register_resource_type(385, "Background subscription 1"), + register_resource_type(386, "Background subscription 2"), ] - OIR_TYPE = register_resource_type(387, "Operational Intent References") + PER_DSS_OIR_TYPE = register_resource_type( + 387, "Multiple Operational Intent References" + ) + PER_DSS_SUB_TYPE = register_resource_type(388, "Multiple Subscriptions") + + _background_sub_ids: List[SubscriptionID] - _sub_ids: List[SubscriptionID] _oir_ids: List[EntityID] + _sub_ids: List[SubscriptionID] _current_subs: Dict[SubscriptionID, Subscription] _current_oirs: Dict[EntityID, OperationalIntentReference] @@ -92,17 +98,23 @@ def __init__( dss.get_instance(scopes) for dss in other_instances.dss_instances ] - # Prepare the two subscription ids: - self._sub_ids = [ - id_generator.id_factory.make_id(sub_type) for sub_type in self.SUB_TYPES + # Prepare the two background subscription ids: + self._background_sub_ids = [ + id_generator.id_factory.make_id(sub_type) for sub_type in self.BG_SUB_TYPES ] # Prepare one OIR id for each DSS we will interact with (one for the main and one for each secondary) - base_oir_id = id_generator.id_factory.make_id(self.OIR_TYPE) + base_oir_id = id_generator.id_factory.make_id(self.PER_DSS_OIR_TYPE) self._oir_ids = [ f"{base_oir_id[:-3]}{i:03d}" for i in range(len(self._secondary_instances) + 1) ] + # Prepare one subscription id for each DSS we will interact with (one for the main and one for each secondary) + base_sub_id = id_generator.id_factory.make_id(self.PER_DSS_SUB_TYPE) + self._sub_ids = [ + f"{base_sub_id[:-3]}{i:03d}" + for i in range(len(self._secondary_instances) + 1) + ] # First subscription from now to 20 minutes in the future self._sub_1_start = datetime.utcnow() @@ -119,22 +131,24 @@ def run(self, context: ExecutionContext): self._setup_case() self.begin_test_case("OIR creation triggers relevant notifications") - self.begin_test_step("Create background subscriptions") self._step_create_background_subs() - self.end_test_step() - self._steps_create_oirs_at_each_dss() self.end_test_case() + self.begin_test_case("Subscription creation returns relevant OIRs") + self._steps_create_subs_at_each_dss() + self.end_test_case() + self.end_test_scenario() def _step_create_background_subs(self): """Creates two subscription through the primary DSS: one that is valid from now into a short future, and one that starts one hour after the first ends""" + self.begin_test_step("Create background subscriptions") # Create the first subscription sub_now_params = self._planning_area.get_new_subscription_params( - subscription_id=self._sub_ids[0], + subscription_id=self._background_sub_ids[0], start_time=self._sub_1_start, duration=self._sub_1_end - self._sub_1_start, # This is a planning area without constraint processing @@ -147,7 +161,7 @@ def _step_create_background_subs(self): # Create the second subscription, that starts later sub_later_params = self._planning_area.get_new_subscription_params( - subscription_id=self._sub_ids[1], + subscription_id=self._background_sub_ids[1], start_time=self._sub_2_start, duration=self._sub_2_end - self._sub_2_start, # This is a planning area without constraint processing @@ -155,9 +169,11 @@ def _step_create_background_subs(self): notify_for_constraints=False, ) - sub_later = self._create_sub_with_params(sub_later_params) + sub_later, _, _ = self._create_sub_with_params(sub_later_params) self._current_subs[sub_later_params.sub_id] = sub_later + self.end_test_step() + def _steps_create_oirs_at_each_dss(self): """Creates an OIR at each DSS instance""" @@ -190,10 +206,10 @@ def _steps_create_oirs_at_each_dss(self): "DSS response contains the expected background subscription", dss.participant_id, ) as check: - if self._sub_ids[0] not in notification_ids: + if self._background_sub_ids[0] not in notification_ids: check.record_failed( summary="DSS did not return the intersecting background subscription", - details=f"Expected subscription {self._sub_ids[0]} (first background subscription) in the" + details=f"Expected subscription {self._background_sub_ids[0]} (first background subscription) in the" f" list of subscriptions to notify, but got {notification_ids}", query_timestamps=[q.request.timestamp], ) @@ -202,10 +218,10 @@ def _steps_create_oirs_at_each_dss(self): "DSS does not return non-intersecting background subscription", dss.participant_id, ) as check: - if self._sub_ids[1] in notification_ids: + if self._background_sub_ids[1] in notification_ids: check.record_failed( summary="DSS returned the non-intersecting background subscription", - details=f"Expected subscription {self._sub_ids[1]} (second background subscription) to not be in the" + details=f"Expected subscription {self._background_sub_ids[1]} (second background subscription) to not be in the" f" list of subscriptions to notify, but got {notification_ids}", query_timestamps=[q.request.timestamp], ) @@ -228,6 +244,46 @@ def _steps_create_oirs_at_each_dss(self): self._current_oirs[oir_id] = oir self.end_test_step() + def _steps_create_subs_at_each_dss(self): + """Creates a subscription at each DSS instance""" + + # The new subscriptions use the same parameters as the first background subscription + common_params = self._planning_area.get_new_subscription_params( + subscription_id="", + start_time=self._sub_1_start, + duration=self._sub_1_end - self._sub_1_start, + notify_for_op_intents=True, + notify_for_constraints=False, + ) + + # All previously created OIRs are relevant to each subscription + expected_oir_ids = set(self._oir_ids) + + for i, dss in enumerate([self._dss] + self._secondary_instances): + self.begin_test_step("Create a subscription at every DSS in sequence") + + sub_id = self._sub_ids[i] + common_params.sub_id = sub_id + sub, oirs, r = self._create_sub_with_params(common_params) + self._current_subs[sub_id] = sub + + returned_oir_ids = set(oir.id for oir in oirs) + + with self.check( + "DSS response contains the expected OIRs", + dss.participant_id, + ) as check: + if not expected_oir_ids.issubset(returned_oir_ids): + missing_oirs = expected_oir_ids - returned_oir_ids + check.record_failed( + summary="DSS did not return the expected OIRs", + details=f"Expected OIRs {expected_oir_ids} in the list of OIRs to notify, but got {returned_oir_ids}. " + f"Missing: {missing_oirs}", + query_timestamps=[r.request.timestamp], + ) + + self.end_test_step() + def _put_op_intent( self, dss: DSSInstance, @@ -258,7 +314,9 @@ def _put_op_intent( return oir, subs, q - def _create_sub_with_params(self, params: SubscriptionParams) -> Subscription: + def _create_sub_with_params( + self, params: SubscriptionParams + ) -> Tuple[Subscription, List[OperationalIntentReference], fetch.Query]: """Create a subscription with the given parameters via the primary DSS instance""" with self.check("Create subscription query succeeds") as check: r = self._dss.upsert_subscription(**params) @@ -268,7 +326,7 @@ def _create_sub_with_params(self, params: SubscriptionParams) -> Subscription: details=f"Failed to create a subscription on primary DSS with code {r.status_code}: {r.error_message}", query_timestamps=[r.request.timestamp], ) - return r.subscription + return r.subscription, r.operational_intent_references, r def _setup_case(self): self.begin_test_case("Setup") @@ -302,7 +360,7 @@ def _clean_workspace(self): self._dss, extents, ) - for sub_id in self._sub_ids: + for sub_id in self._background_sub_ids: test_step_fragments.cleanup_sub(self, self._dss, sub_id) def cleanup(self): diff --git a/monitoring/uss_qualifier/suites/astm/utm/dss_probing.md b/monitoring/uss_qualifier/suites/astm/utm/dss_probing.md index 5d060448a5..41e2d10ed0 100644 --- a/monitoring/uss_qualifier/suites/astm/utm/dss_probing.md +++ b/monitoring/uss_qualifier/suites/astm/utm/dss_probing.md @@ -25,7 +25,7 @@ Checked in - astm
.f3548
.v21
+ astm
.f3548
.v21
DSS0005,1 Implemented ASTM F3548-21 UTM DSS Operational Intent Reference Access Control
ASTM SCD DSS: Interfaces authentication
ASTM SCD DSS: Operational Intent Reference Key Validation
ASTM SCD DSS: Subscription Simple
ASTM SCD DSS: Subscription Synchronization
ASTM SCD DSS: Subscription Validation
ASTM SCD DSS: Subscription and entity interaction @@ -120,6 +120,11 @@ Implemented ASTM SCD DSS: Operational Intent Reference Key Validation + + DSS0210,A2-7-2,4a + Implemented + ASTM SCD DSS: Subscription and entity interaction + DSS0210,A2-7-2,4b Implemented diff --git a/monitoring/uss_qualifier/suites/astm/utm/f3548_21.md b/monitoring/uss_qualifier/suites/astm/utm/f3548_21.md index 43ea482144..b8ac929765 100644 --- a/monitoring/uss_qualifier/suites/astm/utm/f3548_21.md +++ b/monitoring/uss_qualifier/suites/astm/utm/f3548_21.md @@ -35,7 +35,7 @@ Checked in - astm
.f3548
.v21
+ astm
.f3548
.v21
DSS0005,1 Implemented ASTM F3548 flight planners preparation
ASTM F3548-21 UTM DSS Operational Intent Reference Access Control
ASTM SCD DSS: Interfaces authentication
ASTM SCD DSS: Operational Intent Reference Key Validation
ASTM SCD DSS: Subscription Simple
ASTM SCD DSS: Subscription Synchronization
ASTM SCD DSS: Subscription Validation
ASTM SCD DSS: Subscription and entity interaction
Off-Nominal planning: down USS
Off-Nominal planning: down USS with equal priority conflicts not permitted @@ -135,6 +135,11 @@ Implemented ASTM SCD DSS: Operational Intent Reference Key Validation + + DSS0210,A2-7-2,4a + Implemented + ASTM SCD DSS: Subscription and entity interaction + DSS0210,A2-7-2,4b Implemented diff --git a/monitoring/uss_qualifier/suites/faa/uft/message_signing.md b/monitoring/uss_qualifier/suites/faa/uft/message_signing.md index 3b64b5dd03..27b45ae2f4 100644 --- a/monitoring/uss_qualifier/suites/faa/uft/message_signing.md +++ b/monitoring/uss_qualifier/suites/faa/uft/message_signing.md @@ -18,7 +18,7 @@ Checked in - astm
.f3548
.v21
+ astm
.f3548
.v21
DSS0005,1 Implemented ASTM F3548 flight planners preparation
ASTM F3548-21 UTM DSS Operational Intent Reference Access Control
ASTM SCD DSS: Interfaces authentication
ASTM SCD DSS: Operational Intent Reference Key Validation
ASTM SCD DSS: Subscription Simple
ASTM SCD DSS: Subscription Synchronization
ASTM SCD DSS: Subscription Validation
ASTM SCD DSS: Subscription and entity interaction
Off-Nominal planning: down USS
Off-Nominal planning: down USS with equal priority conflicts not permitted @@ -118,6 +118,11 @@ Implemented ASTM SCD DSS: Operational Intent Reference Key Validation + + DSS0210,A2-7-2,4a + Implemented + ASTM SCD DSS: Subscription and entity interaction + DSS0210,A2-7-2,4b Implemented diff --git a/monitoring/uss_qualifier/suites/interuss/dss/all_tests.md b/monitoring/uss_qualifier/suites/interuss/dss/all_tests.md index c26a957463..c9bd88f28e 100644 --- a/monitoring/uss_qualifier/suites/interuss/dss/all_tests.md +++ b/monitoring/uss_qualifier/suites/interuss/dss/all_tests.md @@ -408,7 +408,7 @@ ASTM NetRID DSS: Concurrent Requests
ASTM NetRID DSS: ISA Expiry
ASTM NetRID DSS: ISA Subscription Interactions
ASTM NetRID DSS: Simple ISA
ASTM NetRID DSS: Submitted ISA Validations
ASTM NetRID DSS: Subscription Simple
ASTM NetRID DSS: Subscription Validation
ASTM NetRID DSS: Token Validation - astm
.f3548
.v21
+ astm
.f3548
.v21
DSS0005,1 Implemented ASTM F3548-21 UTM DSS Operational Intent Reference Access Control
ASTM SCD DSS: Interfaces authentication
ASTM SCD DSS: Operational Intent Reference Key Validation
ASTM SCD DSS: Subscription Simple
ASTM SCD DSS: Subscription Synchronization
ASTM SCD DSS: Subscription Validation
ASTM SCD DSS: Subscription and entity interaction @@ -503,6 +503,11 @@ Implemented ASTM SCD DSS: Operational Intent Reference Key Validation + + DSS0210,A2-7-2,4a + Implemented + ASTM SCD DSS: Subscription and entity interaction + DSS0210,A2-7-2,4b Implemented diff --git a/monitoring/uss_qualifier/suites/uspace/flight_auth.md b/monitoring/uss_qualifier/suites/uspace/flight_auth.md index e34c0e4e54..2f6ddd2f3f 100644 --- a/monitoring/uss_qualifier/suites/uspace/flight_auth.md +++ b/monitoring/uss_qualifier/suites/uspace/flight_auth.md @@ -19,7 +19,7 @@ Checked in - astm
.f3548
.v21
+ astm
.f3548
.v21
DSS0005,1 Implemented ASTM F3548 flight planners preparation
ASTM F3548-21 UTM DSS Operational Intent Reference Access Control
ASTM SCD DSS: Interfaces authentication
ASTM SCD DSS: Operational Intent Reference Key Validation
ASTM SCD DSS: Subscription Simple
ASTM SCD DSS: Subscription Synchronization
ASTM SCD DSS: Subscription Validation
ASTM SCD DSS: Subscription and entity interaction
Off-Nominal planning: down USS
Off-Nominal planning: down USS with equal priority conflicts not permitted @@ -119,6 +119,11 @@ Implemented ASTM SCD DSS: Operational Intent Reference Key Validation + + DSS0210,A2-7-2,4a + Implemented + ASTM SCD DSS: Subscription and entity interaction + DSS0210,A2-7-2,4b Implemented diff --git a/monitoring/uss_qualifier/suites/uspace/required_services.md b/monitoring/uss_qualifier/suites/uspace/required_services.md index 90ac288aa6..c490e61357 100644 --- a/monitoring/uss_qualifier/suites/uspace/required_services.md +++ b/monitoring/uss_qualifier/suites/uspace/required_services.md @@ -454,7 +454,7 @@ ASTM NetRID DSS: Concurrent Requests
ASTM NetRID DSS: ISA Expiry
ASTM NetRID DSS: ISA Subscription Interactions
ASTM NetRID DSS: Simple ISA
ASTM NetRID DSS: Submitted ISA Validations
ASTM NetRID DSS: Subscription Simple
ASTM NetRID DSS: Subscription Validation
ASTM NetRID DSS: Token Validation - astm
.f3548
.v21
+ astm
.f3548
.v21
DSS0005,1 Implemented ASTM F3548 flight planners preparation
ASTM F3548-21 UTM DSS Operational Intent Reference Access Control
ASTM SCD DSS: Interfaces authentication
ASTM SCD DSS: Operational Intent Reference Key Validation
ASTM SCD DSS: Subscription Simple
ASTM SCD DSS: Subscription Synchronization
ASTM SCD DSS: Subscription Validation
ASTM SCD DSS: Subscription and entity interaction
Off-Nominal planning: down USS
Off-Nominal planning: down USS with equal priority conflicts not permitted @@ -554,6 +554,11 @@ Implemented ASTM SCD DSS: Operational Intent Reference Key Validation + + DSS0210,A2-7-2,4a + Implemented + ASTM SCD DSS: Subscription and entity interaction + DSS0210,A2-7-2,4b Implemented