Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 0 additions & 40 deletions .basedpyright/baseline.json
Original file line number Diff line number Diff line change
Expand Up @@ -5405,22 +5405,6 @@
"lineCount": 1
}
},
{
"code": "reportArgumentType",
"range": {
"startColumn": 16,
"endColumn": 58,
"lineCount": 1
}
},
{
"code": "reportOptionalMemberAccess",
"range": {
"startColumn": 33,
"endColumn": 36,
"lineCount": 1
}
},
{
"code": "reportOptionalMemberAccess",
"range": {
Expand Down Expand Up @@ -22059,14 +22043,6 @@
"lineCount": 1
}
},
{
"code": "reportOptionalMemberAccess",
"range": {
"startColumn": 76,
"endColumn": 83,
"lineCount": 1
}
},
{
"code": "reportInvalidTypeVarUse",
"range": {
Expand Down Expand Up @@ -22147,22 +22123,6 @@
"lineCount": 1
}
},
{
"code": "reportArgumentType",
"range": {
"startColumn": 43,
"endColumn": 50,
"lineCount": 1
}
},
{
"code": "reportPossiblyUnboundVariable",
"range": {
"startColumn": 43,
"endColumn": 46,
"lineCount": 1
}
},
{
"code": "reportInvalidTypeVarUse",
"range": {
Expand Down
4 changes: 3 additions & 1 deletion monitoring/monitorlib/fetch/scd.py
Original file line number Diff line number Diff line change
Expand Up @@ -392,11 +392,13 @@ def errors(self) -> list[str]:

@property
def subscription(self) -> Subscription | None:
if self.json_result is None:
return None
try:
# We get a ValueError if .parse is fed a None,
# or if the JSON can't be parsed as a Subscription.
return ImplicitDict.parse(
self.json_result.get("subscription", None), Subscription
self.json_result.get("subscription", {}), Subscription
)
except ValueError:
return None
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Verify secondary DSS contains no OIRs with a test ID test step fragment

Ensures that a secondary DSS is ready to be used for testing by confirming that no OIR bearing an ID used for testing exists on it.

## 🛑 Operational intent references can be queried by ID check

If an existing operational intent reference cannot directly be queried by its ID, or if for a non-existing one the DSS replies with a status code different than 404,
the DSS implementation is in violation of **[astm.f3548.v21.DSS0005,1](../../../../../../requirements/astm/f3548/v21.md)**.

## 🛑 Operational intent reference with test ID does not exist check

If an OIR that was deleted from the primary DSS can still be found on a secondary DSS, either one of them may be improperly pooled
and in violation of **[astm.f3548.v21.DSS0020](../../../../../../requirements/astm/f3548/v21.md)**.


Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Verify secondary DSS contains no Subscriptions with a test ID test step fragment

Ensures that a secondary DSS is ready to be used for testing by confirming that no Subscription bearing an ID used for testing exists on it.

## 🛑 Subscription can be queried by ID check

If an existing subscription cannot directly be queried by its ID, or if for a non-existing one the DSS replies with a status code different than 404,
the DSS implementation is in violation of **[astm.f3548.v21.DSS0005,5](../../../../../../requirements/astm/f3548/v21.md)** correctly.

## 🛑 Subscription with test ID does not exist check

If a Subscription that was deleted from the primary DSS can still be found on a secondary DSS, either one of them may be improperly pooled
and in violation of **[astm.f3548.v21.DSS0020](../../../../../../requirements/astm/f3548/v21.md)**.
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,25 @@ Create and mutate subscriptions as well as entities, and verify that the DSS han

## Setup test case

### Ensure clean workspace test step
Ensure that no subscriptions and OIRs with the known test IDs exists in the DSS deployment.

### Ensure clean workspace on primary DSS test step

#### [Clean any existing OIRs with known test IDs](clean_workspace_op_intents.md)

#### [Clean any existing subscriptions with known test IDs](clean_workspace_subs.md)

This step ensures that no subscriptions and OIRs with the known test IDs exists in the DSS deployment.
### Verify secondary DSS instances are clean test step

This test step queries all secondary instances to confirm that none of the test IDs that are used in the scenario exist.

#### [Verify secondary DSS contains no OIRs with a test ID](./fragments/oir/verify_clean_secondary_workspace.md)

#### [Verify secondary DSS contains no Subscriptions with a test ID](./fragments/sub/verify_clean_secondary_workspace.md)

#### OIRs with known test IDs do not exist on secondary DSS instance check

#### Subscriptions with known test IDs do not exist on secondary DSS instance check

## OIR creation and modification trigger relevant notifications test case

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -427,15 +427,48 @@ def _setup_case(self):
self._current_subs = {}
self._current_oirs = {}

self._ensure_clean_workspace_step()
self._ensure_clean_primary_workspace_step()
self._verify_clean_secondaries_step()

self.end_test_case()

def _ensure_clean_workspace_step(self):
self.begin_test_step("Ensure clean workspace")
def _ensure_clean_primary_workspace_step(self):
self.begin_test_step("Ensure clean workspace on primary DSS")
self._clean_workspace()
self.end_test_step()

def _verify_clean_secondaries_step(self):
self.begin_test_step("Verify secondary DSS instances are clean")
for dss in self._secondary_instances:
for oir_id in self._oir_ids:
oir_found = test_step_fragments.cleanup_op_intent(
self, dss, oir_id, delete_if_exists=False
)
with self.check(
"Operational intent reference with test ID does not exist",
dss.participant_id,
) as check:
if oir_found:
check.record_failed(
summary=f"Operational intent reference {oir_id} was still found on DSS {dss.participant_id}",
details=f"Expected operational intent reference {oir_id} to not be found on secondary DSS because it was not present on, or has been removed, from the primary DSS, but it was returned.",
)

for sub_id in self._sub_ids:
sub_found = test_step_fragments.cleanup_sub(
self, dss, sub_id, delete_if_exists=False
)
with self.check(
"Subscription with test ID does not exist",
[self._dss.participant_id, dss.participant_id],
) as check:
if sub_found:
check.record_failed(
summary=f"Subscription {sub_id} was still found on DSS {dss.participant_id}",
details=f"Expected subscription {sub_id} to not be found on secondary DSS because it was not present on, or has been removed, from the primary DSS, but it was returned.",
)
self.end_test_step()

def _clean_workspace(self):
extents = Volume4D(volume=self._planning_area.volume)
test_step_fragments.cleanup_active_oirs(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
from uas_standards.astm.f3548.v21.api import EntityID, Volume4D
from uas_standards.astm.f3548.v21.api import (
EntityID,
Volume4D,
)

from monitoring.monitorlib import fetch
from monitoring.monitorlib.fetch import QueryError
from monitoring.monitorlib.mutate.scd import MutatedSubscription
from monitoring.uss_qualifier.resources.astm.f3548.v21.dss import DSSInstance
from monitoring.uss_qualifier.scenarios.scenario import TestScenarioType
from monitoring.uss_qualifier.scenarios.scenario import (
ScenarioDidNotStopError,
TestScenarioType,
)


def remove_op_intent(
Expand Down Expand Up @@ -62,11 +67,15 @@ def remove_constraint_ref(


def cleanup_sub(
scenario: TestScenarioType, dss: DSSInstance, sub_id: EntityID
) -> MutatedSubscription | None:
"""Cleanup a subscription at the DSS. Does not fail if it is not found.
scenario: TestScenarioType,
dss: DSSInstance,
sub_id: EntityID,
delete_if_exists: bool = True,
) -> bool:
"""Determines if the subscription identified by sub_id exists at the passed DSS, and
removes it if it was found and delete_if_exists is True (the default).

:return: the DSS response if the subscription exists
:return: True if the subscription was found to exist, False if no subscription was found.
"""
existing_sub = dss.get_subscription(sub_id)
scenario.record_query(existing_sub)
Expand All @@ -79,21 +88,35 @@ def cleanup_sub(
details=f"When attempting to query subscription {sub_id} from the DSS, received {existing_sub.status_code}: {existing_sub.error_message}",
query_timestamps=[existing_sub.request.timestamp],
)

if existing_sub.status_code != 200:
return None

deleted_sub = dss.delete_subscription(sub_id, existing_sub.subscription.version)
scenario.record_query(deleted_sub)
with scenario.check("Subscription can be deleted", [dss.participant_id]) as check:
if deleted_sub.status_code != 200:
raise ScenarioDidNotStopError(check)
if existing_sub.status_code != 200:
return False
sub_to_delete = existing_sub.subscription
if sub_to_delete is None:
check.record_failed(
summary=f"Could not delete subscription {sub_id}",
details=f"When attempting to delete subscription {sub_id} from the DSS, received {deleted_sub.status_code} with body {deleted_sub.error_message}",
query_timestamps=[deleted_sub.request.timestamp],
summary=f"Subscription {sub_id} is not defined in the response",
details=f"When attempting to query subscription {sub_id} from the DSS, the response did not include a valid subscription object: {existing_sub.errors}",
query_timestamps=[existing_sub.request.timestamp],
)
raise ScenarioDidNotStopError(check)

if existing_sub.status_code != 200:
return False

if delete_if_exists:
deleted_sub = dss.delete_subscription(sub_id, sub_to_delete.version)
scenario.record_query(deleted_sub)
with scenario.check(
"Subscription can be deleted", [dss.participant_id]
) as check:
if deleted_sub.status_code != 200:
check.record_failed(
summary=f"Could not delete subscription {sub_id}",
details=f"When attempting to delete subscription {sub_id} from the DSS, received {deleted_sub.status_code} with body {deleted_sub.error_message}",
query_timestamps=[deleted_sub.request.timestamp],
)

return deleted_sub
return True


def cleanup_active_subs(
Expand Down Expand Up @@ -179,10 +202,16 @@ def cleanup_active_oirs(


def cleanup_op_intent(
scenario: TestScenarioType, dss: DSSInstance, oi_id: EntityID
) -> None:
"""Remove the specified operational intent reference from the DSS, if it exists."""
scenario: TestScenarioType,
dss: DSSInstance,
oi_id: EntityID,
delete_if_exists: bool = True,
) -> bool:
"""Determines if the operational intent reference identified by oi_id exists at the passed DSS, and
removes it if it was found and delete_if_exists is True (the default).

:return: True if the OIR was found to exist, False if no OIR was found.
"""
with scenario.check(
"Operational intent references can be queried by ID", [dss.participant_id]
) as check:
Expand All @@ -197,10 +226,19 @@ def cleanup_op_intent(
details=e.msg,
query_timestamps=e.query_timestamps,
)
else:
return
return False
if oir.ovn is None:
check.record_failed(
summary=f"OIR {oi_id} is missing OVN",
details="The OIR retrieved from the DSS did not include an OVN, despite the OIR being owned by uss_qualifier. The scenario cannot proceed.",
query_timestamps=[q.request.timestamp],
)
return False

if delete_if_exists:
remove_op_intent(scenario, dss, oi_id, oir.ovn)

remove_op_intent(scenario, dss, oi_id, oir.ovn)
return True


def cleanup_constraint_ref(
Expand Down
24 changes: 24 additions & 0 deletions monitoring/uss_qualifier/scenarios/scenario.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,30 @@ def record_passed(self) -> None:
def skip(self) -> None:
self._outcome_recorded = True

def describe(self) -> str:
doc = self._documentation
severity = doc.severity or "NoSeverity"
url = doc.url
participant_str = (
f" for participants {', '.join(self._participants)}"
if getattr(self, "_participants", None)
else ""
)
url_str = f", doc: {url}" if url else ""
return f"check '{doc.name}'{participant_str} (severity {severity}{url_str})"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: since the participant string will be, e.g., "uss1, uss2", this will produce a string like

check 'Operational intent references can be queried by ID'uss1, uss2 (severity High https://github.com/interuss/monitoring/blob/main/monitoring/uss_qualifier/scenarios/astm/utm/dss/fragments/oir/oir_has_expected_subscription.md#-oir-is-attached-to-expected-subscription-check)

...which doesn't seem super clear or clean.

Suggested change
return f"check '{doc.name}'{participant_str} (severity {severity}{url_str})"
return f"'{doc.name} check' ({severity} severity involving {participant_str}) documented at {url_str})"

...which will produce

'Operational intent references can be queried by ID check' (High severity involving uss1, uss2) documented at https://github.com/interuss/monitoring/blob/main/monitoring/uss_qualifier/scenarios/astm/utm/dss/fragments/oir/oir_has_expected_subscription.md#-oir-is-attached-to-expected-subscription-check

This can be adjusted in a separate PR.



class ScenarioLogicError(Exception):
def __init__(self, msg: str):
super().__init__(msg)


class ScenarioDidNotStopError(ScenarioLogicError):
def __init__(self, check: PendingCheck):
super().__init__(
f"Scenario did not stop as expected upon failed check: {check.describe()}"
)


def get_scenario_type_by_name(scenario_type_name: TestScenarioTypeName) -> type:
inspection.import_submodules(scenarios_module)
Expand Down
2 changes: 1 addition & 1 deletion monitoring/uss_qualifier/suites/astm/utm/dss_probing.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
<tr>
<td><a href="../../../requirements/astm/f3548/v21.md">DSS0020</a></td>
<td>Implemented</td>
<td><a href="../../../scenarios/astm/utm/dss/synchronization/constraint_ref_synchronization.md">ASTM SCD DSS: Constraint Reference Synchronization</a><br><a href="../../../scenarios/astm/utm/dss/synchronization/op_intent_ref_synchronization.md">ASTM SCD DSS: Operational Intent Reference Synchronization</a><br><a href="../../../scenarios/astm/utm/dss/synchronization/subscription_synchronization.md">ASTM SCD DSS: Subscription Synchronization</a><br><a href="../../../scenarios/astm/utm/dss/synchronization/uss_availability_synchronization.md">ASTM SCD DSS: USS Availability Synchronization</a></td>
<td><a href="../../../scenarios/astm/utm/dss/synchronization/constraint_ref_synchronization.md">ASTM SCD DSS: Constraint Reference Synchronization</a><br><a href="../../../scenarios/astm/utm/dss/synchronization/op_intent_ref_synchronization.md">ASTM SCD DSS: Operational Intent Reference Synchronization</a><br><a href="../../../scenarios/astm/utm/dss/synchronization/subscription_synchronization.md">ASTM SCD DSS: Subscription Synchronization</a><br><a href="../../../scenarios/astm/utm/dss/subscription_interactions.md">ASTM SCD DSS: Subscription and entity interaction</a><br><a href="../../../scenarios/astm/utm/dss/synchronization/uss_availability_synchronization.md">ASTM SCD DSS: USS Availability Synchronization</a></td>
</tr>
<tr>
<td><a href="../../../requirements/astm/f3548/v21.md">DSS0100,1</a></td>
Expand Down
2 changes: 1 addition & 1 deletion monitoring/uss_qualifier/suites/astm/utm/f3548_21.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
<tr>
<td><a href="../../../requirements/astm/f3548/v21.md">DSS0020</a></td>
<td>Implemented</td>
<td><a href="../../../scenarios/astm/utm/dss/synchronization/constraint_ref_synchronization.md">ASTM SCD DSS: Constraint Reference Synchronization</a><br><a href="../../../scenarios/astm/utm/dss/synchronization/op_intent_ref_synchronization.md">ASTM SCD DSS: Operational Intent Reference Synchronization</a><br><a href="../../../scenarios/astm/utm/dss/synchronization/subscription_synchronization.md">ASTM SCD DSS: Subscription Synchronization</a><br><a href="../../../scenarios/astm/utm/dss/synchronization/uss_availability_synchronization.md">ASTM SCD DSS: USS Availability Synchronization</a></td>
<td><a href="../../../scenarios/astm/utm/dss/synchronization/constraint_ref_synchronization.md">ASTM SCD DSS: Constraint Reference Synchronization</a><br><a href="../../../scenarios/astm/utm/dss/synchronization/op_intent_ref_synchronization.md">ASTM SCD DSS: Operational Intent Reference Synchronization</a><br><a href="../../../scenarios/astm/utm/dss/synchronization/subscription_synchronization.md">ASTM SCD DSS: Subscription Synchronization</a><br><a href="../../../scenarios/astm/utm/dss/subscription_interactions.md">ASTM SCD DSS: Subscription and entity interaction</a><br><a href="../../../scenarios/astm/utm/dss/synchronization/uss_availability_synchronization.md">ASTM SCD DSS: USS Availability Synchronization</a></td>
</tr>
<tr>
<td><a href="../../../requirements/astm/f3548/v21.md">DSS0100,1</a></td>
Expand Down
2 changes: 1 addition & 1 deletion monitoring/uss_qualifier/suites/astm/utm/prod_probe.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
<tr>
<td><a href="../../../requirements/astm/f3548/v21.md">DSS0020</a></td>
<td>Implemented</td>
<td><a href="../../../scenarios/astm/utm/dss/synchronization/constraint_ref_synchronization.md">ASTM SCD DSS: Constraint Reference Synchronization</a><br><a href="../../../scenarios/astm/utm/dss/synchronization/op_intent_ref_synchronization.md">ASTM SCD DSS: Operational Intent Reference Synchronization</a><br><a href="../../../scenarios/astm/utm/dss/synchronization/subscription_synchronization.md">ASTM SCD DSS: Subscription Synchronization</a><br><a href="../../../scenarios/astm/utm/dss/synchronization/uss_availability_synchronization.md">ASTM SCD DSS: USS Availability Synchronization</a></td>
<td><a href="../../../scenarios/astm/utm/dss/synchronization/constraint_ref_synchronization.md">ASTM SCD DSS: Constraint Reference Synchronization</a><br><a href="../../../scenarios/astm/utm/dss/synchronization/op_intent_ref_synchronization.md">ASTM SCD DSS: Operational Intent Reference Synchronization</a><br><a href="../../../scenarios/astm/utm/dss/synchronization/subscription_synchronization.md">ASTM SCD DSS: Subscription Synchronization</a><br><a href="../../../scenarios/astm/utm/dss/subscription_interactions.md">ASTM SCD DSS: Subscription and entity interaction</a><br><a href="../../../scenarios/astm/utm/dss/synchronization/uss_availability_synchronization.md">ASTM SCD DSS: USS Availability Synchronization</a></td>
</tr>
<tr>
<td><a href="../../../requirements/astm/f3548/v21.md">DSS0100,1</a></td>
Expand Down
Loading
Loading