diff --git a/monitoring/prober/infrastructure.py b/monitoring/prober/infrastructure.py index 4598697aa7..9022444a94 100644 --- a/monitoring/prober/infrastructure.py +++ b/monitoring/prober/infrastructure.py @@ -100,7 +100,7 @@ def wrapper_default_scope(*args, **kwargs): resource_type_code_descriptions: Dict[ResourceType, str] = {} -# Next code: 398 +# Next code: 400 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/fragments/oir/oir_has_expected_subscription.md b/monitoring/uss_qualifier/scenarios/astm/utm/dss/fragments/oir/oir_has_expected_subscription.md new file mode 100644 index 0000000000..b4cb2a2083 --- /dev/null +++ b/monitoring/uss_qualifier/scenarios/astm/utm/dss/fragments/oir/oir_has_expected_subscription.md @@ -0,0 +1,17 @@ +# OIR is attached to expected subscription test step fragment + +## [Query Success](./crud/read_query.md) + +Check query succeeds + +## 🛑 OIR is attached to expected subscription check + +If the OIR returned by the DSS under test is not attached to the expected subscription, +it is in violation of **[astm.f3548.v21.DSS0005,1](../../../../../../requirements/astm/f3548/v21.md)** + +## [Get referenced Subscription](../sub/crud/read_query.md) + +Attempt to fetch the subscription referenced by the OIR in order to confirm that it does not exist. + +This is only used in circumstances where the subscription is expected to not exist and the DSS implementation +is not using the _null_ subscription ID with value `00000000-0000-4000-8000-000000000000`. diff --git a/monitoring/uss_qualifier/scenarios/astm/utm/dss/op_intent_ref_simple.md b/monitoring/uss_qualifier/scenarios/astm/utm/dss/op_intent_ref_simple.md index e6c98dd7d9..afa59473ac 100644 --- a/monitoring/uss_qualifier/scenarios/astm/utm/dss/op_intent_ref_simple.md +++ b/monitoring/uss_qualifier/scenarios/astm/utm/dss/op_intent_ref_simple.md @@ -28,14 +28,137 @@ Verifies the behavior of a DSS for simple interactions pertaining to operational This step ensures that no entities with the known test IDs exists in the DSS. +## OIR in ACCEPTED state can be created without subscription test case + +Checks that a DSS allows an OIR to be created in the accepted state without any subscription. + +### [Create an operational intent reference test step](./fragments/oir/crud/create_query.md) + +This step verifies that an OIR can be created in the ACCEPTED state without providing any subscription information (implicit or explicit) in the request. + +### [OIR is not attached to any subscription test step](./fragments/oir/oir_has_expected_subscription.md) + +This step verifies that the OIR is not attached to any subscription. + +#### 🛑 Referenced subscription does not exist check + +If the placeholder subscription contained in the OIR returned to the qualifier by the DSS references an existing subscription, +then the DSS under test is in violation of **[astm.f3548.v21.DSS0005,1](../../../../requirements/astm/f3548/v21.md)**, as the creation request +did not specify any subscription. + +## Validate explicit subscription being attached to OIR without subscription test case + +Ensures that an explicit subscription can be attached to an OIR without subscription attached, and that the subscription is required to properly cover the OIR. + +### [Create a subscription test step](./fragments/sub/crud/create_query.md) + +Create an explicit subscription to be used in this test cases. + +### Attempt to attach insufficient subscription to OIR test step + +This step verifies that the DSS refuses the request to attach an insufficient subscription to an OIR that currently has no subscription. + +#### 🛑 Request to attach insufficient subscription to OIR fails check + +If the DSS under test allows the qualifier to attach an insufficient explicit subscription to a subscription-free OIR, +it is in violation of **[astm.f3548.v21.DSS0005,1](../../../../requirements/astm/f3548/v21.md)** + +### [OIR is not attached to any subscription test step](./fragments/oir/oir_has_expected_subscription.md) + +This step verifies that the OIR is not attached to any subscription. + +### [Attach explicit subscription to OIR test step](./fragments/oir/crud/update_query.md) + +This step verifies that an explicit subscription covering the OIR can be attached to an OIR that currently has no subscription. + +### [OIR is attached to expected subscription test step](./fragments/oir/oir_has_expected_subscription.md) + +This step verifies that the OIR is attached to the subscription provided upon creation. + +## Validate explicit subscription on OIR creation test case + +Ensures that the explicit subscription provided upon creation of an OIR is properly validated and attached to the OIR. + +### [Ensure clean workspace test step](./clean_workspace.md) + +This step ensures that no entities with the known test IDs exists in the DSS. + +### [Create a subscription test step](./fragments/sub/crud/create_query.md) + +Create an explicit subscription to be used in this and the following test cases. + +### Provide subscription not covering extent of OIR being created test step + +This step verifies that an OIR cannot be created when an explicit subscription that does not cover the extent of the OIR is specified. + +#### 🛑 Request to create OIR with incorrect subscription fails check + +If the DSS under test allows the qualifier to create an OIR with an explicit subscription that does not cover the extent of the OIR, +it is in violation of **[astm.f3548.v21.DSS0005,1](../../../../requirements/astm/f3548/v21.md)** + ### [Create an operational intent reference test step](./fragments/oir/crud/create_query.md) -Create an operational intent reference to be used in this scenario. +When the provided subscription covers the extent of the OIR, the OIR can be created. + +### [OIR is attached to expected subscription test step](./fragments/oir/oir_has_expected_subscription.md) + +This step verifies that the OIR is attached to the subscription provided upon creation. + +## Validate explicit subscription upon subscription replacement test case + +Ensures that when the explicit subscription tied to an OIR is replaced with another explicit subscription, +this subscription is properly validated and attached to the OIR. + +### [Create a subscription test step](./fragments/sub/crud/create_query.md) + +Create an additional explicit subscription to be used in this test case. + +### Attempt to replace OIR's existing explicit subscription with an insufficient one test step + +This step verifies that an OIR's existing explicit subscription cannot be replaced with an explicit subscription that does not cover the extent of the OIR. + +#### 🛑 Request to mutate OIR while providing an incorrect subscription fails check + +If the DSS under test allows the qualifier to replace an OIR's existing explicit subscription with an explicit subscription that does not cover the extent of the OIR, +it is in violation of **[astm.f3548.v21.DSS0005,1](../../../../requirements/astm/f3548/v21.md)** + +### [OIR is attached to expected subscription test step](./fragments/oir/oir_has_expected_subscription.md) + +This step verifies that the OIR is still attached to the previous, valid, subscription. + +### [Replace the OIR's explicit subscription test step](./fragments/oir/crud/update_query.md) + +This step verifies that an OIR attached to an explicit subscription can be mutated in order to be attached +to another explicit subscription that properly covers the extent of the OIR. + +### [OIR is attached to expected subscription test step](./fragments/oir/oir_has_expected_subscription.md) + +This step verifies that the OIR is attached to the subscription provided upon mutation. + +## Remove explicit subscription from OIR test case + +Checks that an OIR in the ACCEPTED state that is attached to an explicit subscription can be mutated in order to not be attached to any subscription. + +### [Remove explicit subscription from OIR test step](./fragments/oir/crud/update_query.md) + +This step verifies that an OIR attached to an explicit subscription can be mutated in order to not be attached to any subscription. + +### [OIR is not attached to any subscription test step](./fragments/oir/oir_has_expected_subscription.md) + +This step verifies that the OIR is not attached to any subscription. ## Deletion requires correct OVN test case Ensures that a DSS will only delete OIRs when the correct OVN is presented. +### [Ensure clean workspace test step](./clean_workspace.md) + +This step resets the workspace for the present and following test cases by ensuring that no entities with the known test IDs exists in the DSS. + +### [Create an operational intent reference test step](./fragments/oir/crud/create_query.md) + +Create an operational intent reference to be used in this and the following test cases. + ### Attempt deletion with missing OVN test step This step verifies that an existing OIR cannot be deleted with a missing OVN. diff --git a/monitoring/uss_qualifier/scenarios/astm/utm/dss/op_intent_ref_simple.py b/monitoring/uss_qualifier/scenarios/astm/utm/dss/op_intent_ref_simple.py index 39b5e3dfac..3818f3165d 100644 --- a/monitoring/uss_qualifier/scenarios/astm/utm/dss/op_intent_ref_simple.py +++ b/monitoring/uss_qualifier/scenarios/astm/utm/dss/op_intent_ref_simple.py @@ -5,10 +5,14 @@ EntityID, OperationalIntentReference, OperationalIntentState, + SubscriptionID, + Subscription, + PutOperationalIntentReferenceParameters, ) from uas_standards.astm.f3548.v21.constants import Scope from monitoring.monitorlib.fetch import QueryError +from monitoring.monitorlib.fetch.rid import subscription from monitoring.monitorlib.geotemporal import Volume4D from monitoring.prober.infrastructure import register_resource_type from monitoring.uss_qualifier.resources.astm.f3548.v21 import PlanningAreaResource @@ -19,6 +23,9 @@ from monitoring.uss_qualifier.resources.astm.f3548.v21.planning_area import ( PlanningAreaSpecification, ) +from monitoring.uss_qualifier.resources.astm.f3548.v21.subscription_params import ( + SubscriptionParams, +) from monitoring.uss_qualifier.resources.communications import ClientIdentityResource from monitoring.uss_qualifier.resources.interuss.id_generator import IDGeneratorResource from monitoring.uss_qualifier.scenarios.astm.utm.dss import test_step_fragments @@ -27,6 +34,14 @@ ) from monitoring.uss_qualifier.suites.suite import ExecutionContext +# The official DSS implementation will set an OIR's subscription ID to 00000000-0000-4000-8000-000000000000 +# when the OIR is not attached to any subscription, as the OpenAPI spec does not allow the value to be empty. +# Other implementations may use a different value. One way to check that an OIR is not attached to any subscription +# is to attempt to retrieve the subscription reportedly attached to it: if a 404 is returned then we may assume +# no subscription is attached. +# Note that this is only allowed for OIRs in the ACCEPTED state. +NULL_SUBSCRIPTION_ID = "00000000-0000-4000-8000-000000000000" + class OIRSimple(TestScenario): """ @@ -38,10 +53,13 @@ class OIRSimple(TestScenario): """ OIR_TYPE = register_resource_type(396, "Operational Intent Reference") - + SUB_TYPE = register_resource_type(398, "Subscription") + EXTRA_SUB_TYPE = register_resource_type(399, "Subscription") _dss: DSSInstance _oir_id: EntityID + _sub_id: SubscriptionID + _extra_sub_id: SubscriptionID # Keep track of the current OIR state _current_oir: Optional[OperationalIntentReference] @@ -49,6 +67,12 @@ class OIRSimple(TestScenario): _planning_area: PlanningAreaSpecification _planning_area_volume4d: Volume4D + # Keep track of the current subscription + _sub_params: Optional[SubscriptionParams] + _current_sub: Optional[Subscription] + + _current_extra_sub: Optional[Subscription] + def __init__( self, dss: DSSInstanceResource, @@ -73,6 +97,8 @@ def __init__( self._pid = [self._dss.participant_id] self._oir_id = id_generator.id_factory.make_id(self.OIR_TYPE) + self._sub_id = id_generator.id_factory.make_id(self.SUB_TYPE) + self._extra_sub_id = id_generator.id_factory.make_id(self.EXTRA_SUB_TYPE) self._expected_manager = client_identity.subject() @@ -84,9 +110,68 @@ def __init__( def run(self, context: ExecutionContext): self.begin_test_scenario(context) + self.begin_test_case("Setup") self._setup_case() + self.end_test_case() + + self.begin_test_case( + "OIR in ACCEPTED state can be created without subscription" + ) + self._step_create_oir( + oir_params=self._planning_area.get_new_operational_intent_ref_params( + key=[], + state=OperationalIntentState.Accepted, + uss_base_url=self._planning_area.get_base_url(), + time_start=datetime.now() - timedelta(seconds=10), + time_end=datetime.now() + timedelta(minutes=20), + subscription_id=None, + implicit_sub_base_url=None, + ), + ) + self._step_oir_has_correct_subscription(expected_sub_id=None) + self.end_test_case() + + self.begin_test_case( + "Validate explicit subscription being attached to OIR without subscription" + ) + self._step_update_oir_with_insufficient_explicit_sub(is_replacement=False) + self._step_oir_has_correct_subscription(expected_sub_id=None) + self._step_update_oir_with_sufficient_explicit_sub(is_replacement=False) + self._step_oir_has_correct_subscription(expected_sub_id=self._extra_sub_id) + self.end_test_case() + + self.begin_test_case("Validate explicit subscription on OIR creation") + self._setup_case(create_explicit_sub=True) + self._step_create_oir_insufficient_subscription() + self._step_create_oir( + oir_params=self._planning_area.get_new_operational_intent_ref_params( + key=[], + state=OperationalIntentState.Accepted, + uss_base_url=self._planning_area.get_base_url(), + time_start=datetime.now() - timedelta(seconds=10), + time_end=self._sub_params.end_time, # OIR ends at the same time as subscription + subscription_id=self._sub_id, + ), + ) + self._step_oir_has_correct_subscription(expected_sub_id=self._sub_id) + self.end_test_case() + + self.begin_test_case( + "Validate explicit subscription upon subscription replacement" + ) + self._step_update_oir_with_insufficient_explicit_sub(is_replacement=True) + self._step_oir_has_correct_subscription(expected_sub_id=self._sub_id) + self._step_update_oir_with_sufficient_explicit_sub(is_replacement=True) + self._step_oir_has_correct_subscription(expected_sub_id=self._extra_sub_id) + self.end_test_case() + + self.begin_test_case("Remove explicit subscription from OIR") + self._step_remove_subscription_from_oir() + self._step_oir_has_correct_subscription(expected_sub_id=None) + self.end_test_case() self.begin_test_case("Deletion requires correct OVN") + self._setup_case(create_oir=True) self._step_attempt_delete_missing_ovn() self._step_attempt_delete_incorrect_ovn() self.end_test_case() @@ -98,28 +183,52 @@ def run(self, context: ExecutionContext): self.end_test_scenario() - def _step_create_oir(self): - oir_params = self._planning_area.get_new_operational_intent_ref_params( - key=[], - state=OperationalIntentState.Accepted, - uss_base_url=self._planning_area.get_base_url(), - time_start=datetime.now() - timedelta(seconds=10), - time_end=datetime.now() + timedelta(minutes=20), - subscription_id=None, + def _step_create_subscription(self, params: SubscriptionParams) -> Subscription: + self.begin_test_step("Create a subscription") + with self.check("Create subscription query succeeds", self._pid) as check: + try: + mutated_sub = self._dss.upsert_subscription(**params) + self.record_query(mutated_sub) + except QueryError as qe: + self.record_queries(qe.queries) + check.record_failed( + summary="Could not create subscription", + details=f"Failed to create subscription with error code {qe.cause_status_code}: {qe.msg}", + query_timestamps=qe.query_timestamps, + ) + self.end_test_step() + return mutated_sub.subscription + + def _step_create_explicit_sub(self): + self._sub_params = self._planning_area.get_new_subscription_params( + subscription_id=self._sub_id, + start_time=datetime.now() - timedelta(seconds=10), + duration=timedelta(minutes=20), + notify_for_op_intents=True, + notify_for_constraints=False, ) + self._current_sub = self._step_create_subscription(self._sub_params) + def _step_create_oir(self, oir_params: PutOperationalIntentReferenceParameters): self.begin_test_step("Create an operational intent reference") + sub_id = oir_params.subscription_id if "subscription_id" in oir_params else None with self.check( "Create operational intent reference query succeeds", self._pid, ) as check: try: + no_implicit_sub = ( + "new_subscription" not in oir_params + or "uss_base_url" not in oir_params.new_subscription + ) new_oir, subs, query = self._dss.put_op_intent( extents=oir_params.extents, key=oir_params.key, state=oir_params.state, base_url=oir_params.uss_base_url, oi_id=self._oir_id, + subscription_id=sub_id, + force_no_implicit_subscription=no_implicit_sub, ) self.record_query(query) self._current_oir = new_oir @@ -132,6 +241,264 @@ def _step_create_oir(self): ) self.end_test_step() + def _step_create_oir_insufficient_subscription(self): + self.begin_test_step( + "Provide subscription not covering extent of OIR being created" + ) + + oir_params = self._planning_area.get_new_operational_intent_ref_params( + key=[], + state=OperationalIntentState.Accepted, + uss_base_url=self._planning_area.get_base_url(), + time_start=datetime.now() - timedelta(seconds=10), + time_end=self._sub_params.end_time + + timedelta(seconds=1), # OIR ends 1 sec after subscription + subscription_id=self._sub_id, + ) + + with self.check( + "Request to create OIR with incorrect subscription fails", self._pid + ) as check: + try: + _, _, q = self._dss.put_op_intent( + extents=oir_params.extents, + key=oir_params.key, + state=oir_params.state, + base_url=oir_params.uss_base_url, + oi_id=self._oir_id, + subscription_id=oir_params.subscription_id, + ) + self.record_query(q) + # We don't expect to reach this point: + check.record_failed( + summary="OIR creation with too short subscription was not expected to succeed", + details=f"Was expecting an HTTP 400 response because of an insufficient subscription, but got {q.status_code} instead", + query_timestamps=[q.request.timestamp], + ) + except QueryError as qe: + self.record_queries(qe.queries) + if qe.cause_status_code == 400: + pass + else: + check.record_failed( + summary="OIR creation with too short subscription failed for unexpected reason", + details=f"Was expecting an HTTP 400 response because of an insufficient subscription, but got {qe.cause_status_code} instead", + query_timestamps=qe.query_timestamps, + ) + + self.end_test_step() + + def _step_update_oir_with_insufficient_explicit_sub(self, is_replacement: bool): + # Create another subscription that is a few seconds short of covering the OIR: + oir_duration = ( + self._current_oir.time_end.value.datetime + - self._current_oir.time_start.value.datetime + ) + new_sub_params = self._planning_area.get_new_subscription_params( + subscription_id=self._extra_sub_id, + start_time=datetime.now() - timedelta(seconds=10), + duration=oir_duration - timedelta(seconds=2), + notify_for_op_intents=True, + notify_for_constraints=False, + ) + + self._current_extra_sub = self._step_create_subscription(new_sub_params) + + # Now attempt to mutate the OIR for it to use the invalid subscription: + oir_update_params = self._planning_area.get_new_operational_intent_ref_params( + key=[], + state=OperationalIntentState.Accepted, + uss_base_url=self._planning_area.get_base_url(), + time_start=self._current_oir.time_start.value.datetime, + time_end=self._current_oir.time_end.value.datetime, + subscription_id=self._extra_sub_id, + ) + step_name = ( + "Attempt to replace OIR's existing explicit subscription with an insufficient one" + if is_replacement + else "Attempt to attach insufficient subscription to OIR" + ) + self.begin_test_step(step_name) + check_name = ( + "Request to mutate OIR while providing an incorrect subscription fails" + if is_replacement + else "Request to attach insufficient subscription to OIR fails" + ) + with self.check( + check_name, + self._pid, + ) as check: + try: + _, _, q = self._dss.put_op_intent( + extents=oir_update_params.extents, + key=oir_update_params.key, + state=oir_update_params.state, + base_url=oir_update_params.uss_base_url, + oi_id=self._oir_id, + subscription_id=oir_update_params.subscription_id, + ovn=self._current_oir.ovn, + ) + self.record_query(q) + # We don't expect to reach this point: + check.record_failed( + summary="Request for OIR with too short subscription was not expected to succeed", + details=f"Was expecting an HTTP 400 response because of an insufficient subscription, but got {q.status_code} instead", + query_timestamps=[q.request.timestamp], + ) + except QueryError as qe: + self.record_queries(qe.queries) + if qe.cause_status_code == 400: + pass + else: + check.record_failed( + summary="Request for OIR with too short subscription failed for unexpected reason", + details=f"Was expecting an HTTP 400 response because of an insufficient subscription, but got {qe.cause_status_code} instead. {qe.msg}", + query_timestamps=qe.query_timestamps, + ) + self.end_test_step() + + def _step_update_oir_with_sufficient_explicit_sub(self, is_replacement: bool): + step_name = ( + "Replace the OIR's explicit subscription" + if is_replacement + else "Attach explicit subscription to OIR" + ) + self.begin_test_step(step_name) + oir_update_params = self._planning_area.get_new_operational_intent_ref_params( + key=[], + state=OperationalIntentState.Accepted, + uss_base_url=self._planning_area.get_base_url(), + time_start=self._current_extra_sub.time_start.value.datetime, + time_end=self._current_extra_sub.time_end.value.datetime, + subscription_id=self._extra_sub_id, + ) + with self.check( + "Mutate operational intent reference query succeeds", + self._pid, + ) as check: + try: + mutated_oir, _, q = self._dss.put_op_intent( + extents=oir_update_params.extents, + key=oir_update_params.key, + state=oir_update_params.state, + base_url=oir_update_params.uss_base_url, + oi_id=self._oir_id, + subscription_id=oir_update_params.subscription_id, + ovn=self._current_oir.ovn, + ) + self.record_query(q) + self._current_oir = mutated_oir + except QueryError as qe: + self.record_queries(qe.queries) + check.record_failed( + summary="OIR mutation with correct subscription failed", + details=f"Was expecting an HTTP 200 response for a mutation with valid parameters, but got {qe.cause_status_code} instead. {qe.msg}", + query_timestamps=qe.query_timestamps, + ) + self.end_test_step() + + def _step_remove_subscription_from_oir(self): + self.begin_test_step("Remove explicit subscription from OIR") + oir_update_params = self._planning_area.get_new_operational_intent_ref_params( + key=[], + state=OperationalIntentState.Accepted, + uss_base_url=self._planning_area.get_base_url(), + time_start=self._current_oir.time_start.value.datetime, + time_end=self._current_oir.time_end.value.datetime, + subscription_id=None, + ) + with self.check( + "Mutate operational intent reference query succeeds", + self._pid, + ) as check: + try: + mutated_oir, _, q = self._dss.put_op_intent( + extents=oir_update_params.extents, + key=oir_update_params.key, + state=oir_update_params.state, + base_url=oir_update_params.uss_base_url, + oi_id=self._oir_id, + subscription_id=None, + ovn=self._current_oir.ovn, + force_no_implicit_subscription=True, + ) + self.record_query(q) + self._current_oir = mutated_oir + except QueryError as qe: + self.record_queries(qe.queries) + check.record_failed( + summary="Removal of explicit subscription from OIR failed", + details=f"Was expecting an HTTP 200 response for a mutation with valid parameters, but got {qe.cause_status_code} instead. {qe.msg}", + query_timestamps=qe.query_timestamps, + ) + self.end_test_step() + + def _step_oir_has_correct_subscription( + self, expected_sub_id: Optional[SubscriptionID] + ): + step_check_name = ( + "OIR is attached to expected subscription" + if expected_sub_id + else "OIR is not attached to any subscription" + ) + self.begin_test_step(step_check_name) + with self.check("Get operational intent reference by ID", self._pid) as check: + try: + oir, q = self._dss.get_op_intent_reference(self._oir_id) + self.record_query(q) + except QueryError as qe: + self.record_queries(qe.queries) + check.record_failed( + summary="Could not get OIR", + details=f"Failed to get OIR with error code {qe.cause_status_code}: {qe.msg}", + query_timestamps=qe.query_timestamps, + ) + + sub_is_as_expected = False + referenced_sub_was_found_when_non_expected = False + if expected_sub_id is None: + # The official DSS implementation will set the subscription ID to 00000000-0000-4000-8000-000000000000 when the OIR is not attached to any subscription. + # Other implementations may use a different value, as the OpenAPI spec does not allow the value to be empty + # We may at some point decide to tolerate accepting empty returned values here, + # but in the meantime we simply attempt to obtain the subscription and check that it does not exist + if oir.subscription_id == NULL_SUBSCRIPTION_ID: + # Sub ID explicitly set to the value representing the null subscription: all good + sub_is_as_expected = True + elif oir.subscription_id is None: + # Sub ID not set at all: not strictly compliant with the spec, but acceptable in this context + sub_is_as_expected = True + else: + # If the subscription ID is defined and not set to the known 'null' value, we assume that the DSS used another + # placeholder for the non-existing subscription, and we check that it does not exist. + with self.check("Get referenced Subscription") as check: + sub = self._dss.get_subscription(oir.subscription_id) + self.record_query(sub) + if sub.status_code not in [200, 404]: + check.record_failed( + summary="Failed to try to obtain the subscription referenced by the OIR", + details=f"Failed in an unexpected way while querying subscription with ID {oir.subscription_id}: expected a 404 or 200, but got {sub.status_code}", + query_timestamps=[sub.request.timestamp], + ) + if sub.status_code == 200: + referenced_sub_was_found_when_non_expected = True + else: + sub_is_as_expected = oir.subscription_id == expected_sub_id + + with self.check("OIR is attached to expected subscription", self._pid) as check: + if referenced_sub_was_found_when_non_expected: + check.record_failed( + summary="OIR is attached to a subscription although it should not be", + details=f"Expected OIR to not be attached to any subscription, but the referenced subscription {oir.subscription_id} does exist.", + query_timestamps=[sub.request.timestamp], + ) + if not sub_is_as_expected: + check.record_failed( + summary="OIR is not attached to the correct subscription", + details=f"Expected OIR to be attached to subscription {expected_sub_id}, but it is attached to {oir.subscription_id}", + query_timestamps=[q.request.timestamp], + ) + self.end_test_step() + def _step_attempt_delete_missing_ovn(self): self.begin_test_step("Attempt deletion with missing OVN") @@ -270,18 +637,24 @@ def _step_attempt_mutation_incorrect_ovn(self): self.end_test_step() - def _setup_case(self): - self.begin_test_case("Setup") + def _setup_case(self, create_oir=False, create_explicit_sub=False): # Multiple runs of the scenario seem to rely on the same instance of it: # thus we need to reset the state of the scenario before running it. self._current_oir = None + self._current_sub = None + self._current_extra_sub = None self.begin_test_step("Ensure clean workspace") self._ensure_clean_workspace_step() self.end_test_step() - self._step_create_oir() + if create_oir: + sub_id = self._sub_id if create_explicit_sub else None + self._step_create_oir( + oir_params=self._default_oir_params(subscription_id=sub_id) + ) - self.end_test_case() + if create_explicit_sub: + self._step_create_explicit_sub() def _ensure_clean_workspace_step(self): @@ -315,3 +688,15 @@ def _test_params_for_current_time(self): time_end=datetime.now() + timedelta(minutes=20), subscription_id=None, ) + + def _default_oir_params( + self, subscription_id: SubscriptionID + ) -> PutOperationalIntentReferenceParameters: + return self._planning_area.get_new_operational_intent_ref_params( + key=[], + state=OperationalIntentState.Accepted, + uss_base_url=self._planning_area.get_base_url(), + time_start=datetime.now() - timedelta(seconds=10), + time_end=datetime.now() + timedelta(minutes=20), + subscription_id=subscription_id, + )