diff --git a/monitoring/uss_qualifier/scenarios/astm/utm/dss/constraint_ref_simple.md b/monitoring/uss_qualifier/scenarios/astm/utm/dss/constraint_ref_simple.md index 6d5ce85cd1..9e1934548a 100644 --- a/monitoring/uss_qualifier/scenarios/astm/utm/dss/constraint_ref_simple.md +++ b/monitoring/uss_qualifier/scenarios/astm/utm/dss/constraint_ref_simple.md @@ -54,4 +54,26 @@ This step verifies that an existing CR cannot be deleted with an incorrect OVN. If the DSS under test allows the qualifier to delete an existing CR with a request that provided an incorrect OVN, it is in violation of **[astm.f3548.v21.DSS0005,3](../../../../requirements/astm/f3548/v21.md)** +## Mutation requires correct OVN test case + +Ensures that an existing CR can only be mutated when the correct OVN is provided. + +### Attempt mutation with missing OVN test step + +This step verifies that an existing CR cannot be mutated with a missing OVN. + +#### 🛑 Request to mutate CR with empty OVN fails check + +If the DSS under test allows the qualifier to mutate an existing CR with a request that provided an empty OVN, +it is in violation of **[astm.f3548.v21.DSS0005,3](../../../../requirements/astm/f3548/v21.md)** + +### Attempt mutation with incorrect OVN test step + +This step verifies that an existing CR cannot be mutated with an incorrect OVN. + +#### 🛑 Request to mutate CR with incorrect OVN fails check + +If the DSS under test allows the qualifier to mutate an existing CR with a request that provided an incorrect OVN, +it is in violation of **[astm.f3548.v21.DSS0005,3](../../../../requirements/astm/f3548/v21.md)** + ## [Cleanup](./clean_workspace.md) diff --git a/monitoring/uss_qualifier/scenarios/astm/utm/dss/constraint_ref_simple.py b/monitoring/uss_qualifier/scenarios/astm/utm/dss/constraint_ref_simple.py index 5eb7e673d3..98249bfa32 100644 --- a/monitoring/uss_qualifier/scenarios/astm/utm/dss/constraint_ref_simple.py +++ b/monitoring/uss_qualifier/scenarios/astm/utm/dss/constraint_ref_simple.py @@ -84,6 +84,11 @@ def run(self, context: ExecutionContext): self._step_attempt_delete_incorrect_ovn() self.end_test_case() + self.begin_test_case("Mutation requires correct OVN") + self._step_attempt_mutation_missing_ovn() + self._step_attempt_mutation_incorrect_ovn() + self.end_test_case() + self.end_test_scenario() def _step_create_cr(self): @@ -125,19 +130,19 @@ def _step_attempt_delete_missing_ovn(self): # We don't expect the reach this point: check.record_failed( summary="CR Deletion with empty OVN was not expected to succeed", - details=f"Was expecting an HTTP 400 or 409 response because of an empty OVN, but got {q.status_code} instead", + details=f"Was expecting an HTTP 400, 404 or 409 response because of an empty OVN, 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 in [400, 409]: - # An empty OVN cen be seen as both an incorrect parameter as well as a conflict - # because the value is incorrect: we accept both a 400 and 409 return code here. + if qe.cause_status_code in [400, 404, 409]: + # An empty OVN can be seen as: + # an incorrect parameter (400), a reference to a non-existing entity (404) as well as a conflict (409) pass else: check.record_failed( summary="CR Deletion with empty OVN failed for unexpected reason", - details=f"Was expecting an HTTP 400 or 409 response because of an empty OVN, but got {qe.cause_status_code} instead", + details=f"Was expecting an HTTP 400, 404 or 409 response because of an empty OVN, but got {qe.cause_status_code} instead", query_timestamps=qe.query_timestamps, ) @@ -175,6 +180,83 @@ def _step_attempt_delete_incorrect_ovn(self): self.end_test_step() + def _step_attempt_mutation_missing_ovn(self): + self.begin_test_step("Attempt mutation with missing OVN") + cr_params = self._planning_area.get_new_constraint_ref_params( + time_start=datetime.now() - timedelta(seconds=10), + time_end=datetime.now() + timedelta(minutes=20), + ) + + with self.check( + "Request to mutate CR with empty OVN fails", self._pid + ) as check: + try: + _, _, q = self._dss.put_constraint_ref( + cr_id=self._cr_id, + extents=cr_params.extents, + uss_base_url=self._planning_area.base_url, + ovn="", + ) + self.record_query(q) + # We don't expect the reach this point: + check.record_failed( + summary="CR mutation with empty OVN was not expected to succeed", + details=f"Was expecting an HTTP 400, 404 or 409 response because of an empty OVN, 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 in [400, 404, 409]: + # An empty OVN can be seen as: + # an incorrect parameter (400), a reference to a non-existing entity (404) as well as a conflict (409) + pass + else: + check.record_failed( + summary="CR mutation with empty OVN failed for unexpected reason", + details=f"Was expecting an HTTP 400, 404 or 409 response because of an empty OVN, but got {qe.cause_status_code} instead", + query_timestamps=qe.query_timestamps, + ) + + self.end_test_step() + + def _step_attempt_mutation_incorrect_ovn(self): + self.begin_test_step("Attempt mutation with incorrect OVN") + cr_params = self._planning_area.get_new_constraint_ref_params( + time_start=datetime.now() - timedelta(seconds=10), + time_end=datetime.now() + timedelta(minutes=20), + ) + + with self.check( + "Request to mutate CR with incorrect OVN fails", self._pid + ) as check: + try: + _, _, q = self._dss.put_constraint_ref( + cr_id=self._cr_id, + extents=cr_params.extents, + uss_base_url=self._planning_area.base_url, + ovn="ThisIsAnIncorrectOVN", + ) + self.record_query(q) + # We don't expect the reach this point: + check.record_failed( + summary="CR mutation with incorrect OVN was not expected to succeed", + details=f"Was expecting an HTTP 400 or 409 response because of an incorrect OVN, 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 in [400, 409]: + # An empty OVN cen be seen as both an incorrect parameter as well as a conflict + # because the value is incorrect: we accept both a 400 and 409 return code here. + pass + else: + check.record_failed( + summary="CR mutation with incorrect OVN failed for unexpected reason", + details=f"Was expecting an HTTP 400 or 409 response because of an incorrect OVN, but got {qe.cause_status_code} instead", + query_timestamps=qe.query_timestamps, + ) + self.end_test_step() + def _setup_case(self): self.begin_test_case("Setup") self.begin_test_step("Ensure clean workspace")