Skip to content

Commit

Permalink
[uss_qualifier/utm/off_nominal_planning] Add 'down USS with equal pri…
Browse files Browse the repository at this point in the history
…ority conflicts not permitted' scenario validating SCD0010 (#383)

* [uss_qualifier/utm/off_nominal_planning] Add 'down USS with equal priority conflicts not permitted' scenario validating SCD0010

* set resource as optional to enable skipping test

* [mock_uss/f3548] add check for priority allowed in locality; use CHE locality in CI

* revert default mock USS locality

* setup f3548 suite for optional preemption flight intents

* revert mistake

* revert 2nd mistake

* update resource configuration

* revisit naming of flight intents
  • Loading branch information
mickmis authored Dec 11, 2023
1 parent 2b53922 commit 44be7a7
Show file tree
Hide file tree
Showing 10 changed files with 554 additions and 106 deletions.
3 changes: 3 additions & 0 deletions monitoring/uss_qualifier/scenarios/astm/utm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@
from .aggregate_checks import AggregateChecks
from .prep_planners import PrepareFlightPlanners
from .off_nominal_planning.down_uss import DownUSS
from .off_nominal_planning.down_uss_equal_priority_not_permitted import (
DownUSSEqualPriorityNotPermitted,
)
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# Off-Nominal planning: down USS test scenario

## Description
This test aims to test the strategic coordination requirements that relate to the down USS mechanism:
This test aims to test the strategic coordination requirements that relate to the down USS mechanism in the general case:
- **[astm.f3548.v21.SCD0005](../../../../requirements/astm/f3548/v21.md)**
- **[astm.f3548.v21.SCD0010](../../../../requirements/astm/f3548/v21.md)**

It involves a single tested USS. The USS qualifier acts as a virtual USS that may have its availability set to down.

Expand All @@ -17,30 +16,18 @@ FlightIntentsResource that provides the following flight intents:
<th>Flight name</th>
<th>Priority</th>
<th>State</th><!-- TODO: Update with usage_state and uas_state when new flight planning API is adopted -->
<th>Must conflict with</th>
<th>Must not conflict with</th>
</tr>
<tr>
<td><code>flight1_planned</code></td>
<td rowspan="2">Flight 1</td>
<td rowspan="5">Any</td>
<td>Flight 1</td>
<td>Any</td>
<td>Accepted</td>
<td rowspan="2">Flight 2</td>
<td rowspan="2">Flight 2m</td>
</tr>
<tr>
<td><code>flight2_planned</code></td>
<td rowspan="2">Flight 2</td>
<td rowspan="3">Higher than Flight 1*</td>
<td>Accepted</td>
<td rowspan="2">Flight 1</td>
<td rowspan="2">N/A</td>
</tr>
</table>


### tested_uss
FlightPlannerResource that is under test and will manage flight 1.
FlightPlannerResource that is under test and will manage Flight 1.

### dss
DSSInstanceResource that provides access to a DSS instance where:
Expand All @@ -62,55 +49,56 @@ Delete any leftover operational intents created at DSS by virtual USS.
#### Successful operational intents cleanup check
If the search for own operational intents or their deletion fail, this check fails per **[astm.f3548.v21.DSS0005](../../../../requirements/astm/f3548/v21.md)**.

## Plan flight in conflict with planned flight managed by down USS test case

## Plan Flight 1 in conflict with accepted operational intent managed by down USS test case
This test case aims at testing requirement **[astm.f3548.v21.SCD0005](../../../../requirements/astm/f3548/v21.md)**.

### Virtual USS plans high-priority flight 2 test step
The USS qualifier, acting as a virtual USS, creates an operational intent at the DSS with a high priority and a non-working base URL.
### Virtual USS creates conflicting operational intent test step
The USS qualifier, acting as a virtual USS, creates an operational intent at the DSS with a non-working base URL.
The objective is to make the later request by the tested USS to retrieve operational intent details to fail.

#### Operational intent successfully created check
If the creation of the operational intent reference at the DSS fails, this check fails per **[astm.f3548.v21.DSS0005](../../../../requirements/astm/f3548/v21.md)**.

### [Declare virtual USS as down at DSS test step](../set_uss_down.md)

### Tested USS attempts to plan low-priority flight 1 test step
The low-priority flight 1 of the tested USS conflicts with high-priority flight 2 of the virtual USS.
### Tested USS attempts to plan low-priority Flight 1 test step
The low-priority Flight 1 of the tested USS conflicts with the operational intent of the virtual USS.
However, since:
- the virtual USS is declared as down at the DSS,
- it does not respond for operational intent details, and
- the operational intent for flight 2 is in 'Planned' state,
The tested USS should evaluate the operational intent of flight 2 as having the lowest bound priority status, i.e. a priority strictly lower than the lowest priority allowed by the local regulation.
- the conflicting operational intent is in the 'Accepted' state,
The tested USS should evaluate the conflicting operational intent as having the lowest bound priority status, i.e. a priority strictly lower than the lowest priority allowed by the local regulation.

As such, the tested USS may either:
- Successfully plan flight 1 over the higher-priority flight 2, or
- Decide to be more conservative and reject the planning of flight 1.
- Successfully plan Flight 1 over the conflicting operational intent, or
- Decide to be more conservative and reject the planning of Flight 1.

#### Successful planning check
All flight intent data provided is correct and the USS should have either successfully planned the flight per **[astm.f3548.v21.SCD0005](../../../../requirements/astm/f3548/v21.md)**,
All flight intent data provided is correct and the USS should have either successfully planned Flight 1 per **[astm.f3548.v21.SCD0005](../../../../requirements/astm/f3548/v21.md)**,
or rejected properly the planning if it decided to be more conservative with such conflicts.
If the USS indicates that the injection attempt failed, this check will fail.

Do take note that if the USS rejects the planning, this check will not fail, but the following *Rejected planning check*
will. Refer to this check for more information.

#### Rejected planning check
All flight intent data provided is correct and the USS should have either successfully planned the flight or rejected
All flight intent data provided is correct and the USS should have either successfully planned Flight 1 or rejected
properly the planning if it decided to be more conservative with such conflicts.
If the USS rejects the planning, this check will fail with a low severity per **[astm.f3548.v21.SCD0005](../../../../requirements/astm/f3548/v21.md)**.
This won't actually fail the test but will serve as a warning.

#### Failure check
All flight intent data provided was complete and correct. It should have been processed successfully, allowing the USS
to reject or accept the flight. If the USS indicates that the injection attempt failed, this check will fail per
to reject or accept Flight 1. If the USS indicates that the injection attempt failed, this check will fail per
**[interuss.automated_testing.flight_planning.ExpectedBehavior](../../../../requirements/interuss/automated_testing/flight_planning.md)**.

### [Validate low-priority flight 1 status test step](../validate_shared_operational_intent.md)
### [Validate low-priority Flight 1 status test step](../validate_shared_operational_intent.md)
This step validates that the response of the USS is consistent with the flight shared, i.e. either it was properly
planned, or the USS rejected the planning.

If the planning was accepted, flight 1 should have been shared.
If the planning was rejected, flight 1 should not have been shared, thus should not exist.
If the planning was accepted, Flight 1 should have been shared.
If the planning was rejected, Flight 1 should not have been shared, thus should not exist.

## Cleanup
### Availability of virtual USS restored check
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
from typing import Optional, List
from typing import Dict, Optional

import arrow

from monitoring.monitorlib.geotemporal import Volume4DCollection
from monitoring.uss_qualifier.common_data_definitions import Severity
from uas_standards.astm.f3548.v21.api import OperationalIntentState
from uas_standards.astm.f3548.v21.api import (
OperationalIntentState,
OperationalIntentReference,
)
from uas_standards.interuss.automated_testing.scd.v1.api import (
InjectFlightResponseResult,
)
Expand Down Expand Up @@ -37,11 +40,8 @@


class DownUSS(TestScenario):
flight_1_id: Optional[str] = None
flight1_planned: FlightIntent

flight2_planned: FlightIntent

uss_qualifier_sub: str

tested_uss: FlightPlanner
Expand All @@ -57,7 +57,7 @@ def __init__(
self.tested_uss = tested_uss.flight_planner
self.dss = dss.dss

_flight_intents = {
_flight_intents: Dict[str, FlightIntent] = {
k: FlightIntent.from_flight_info_template(v)
for k, v in flight_intents.get_flight_intents().items()
}
Expand All @@ -70,47 +70,31 @@ def __init__(
extents
).bounding_volume.to_f3548v21()

try:
(self.flight1_planned, self.flight2_planned,) = (
_flight_intents["flight1_planned"],
_flight_intents["flight2_planned"],
)
now = arrow.utcnow().datetime
for intent_name, intent in _flight_intents.items():
if (
intent.request.operational_intent.state
== OperationalIntentState.Activated
):
if not Volume4DCollection.from_interuss_scd_api(
intent.request.operational_intent.volumes
+ intent.request.operational_intent.off_nominal_volumes
).has_active_volume(now):
err_msg = f"at least one volume of activated intent {intent_name} must be active now (now is {now})"
raise ValueError(
f"`{self.me()}` TestScenario requirements for flight_intents not met: {err_msg}"
)

now = arrow.utcnow().datetime
for intent_name, intent in _flight_intents.items():
if (
intent.request.operational_intent.state
== OperationalIntentState.Activated
):
assert Volume4DCollection.from_interuss_scd_api(
intent.request.operational_intent.volumes
+ intent.request.operational_intent.off_nominal_volumes
).has_active_volume(
now
), f"at least one volume of activated intent {intent_name} must be active now (now is {now})"
self._parse_flight_intents(_flight_intents)

def _parse_flight_intents(self, flight_intents: Dict[str, FlightIntent]) -> None:
try:
self.flight1_planned = flight_intents["flight1_planned"]

assert (
self.flight1_planned.request.operational_intent.state
== OperationalIntentState.Accepted
), "flight1_planned must have state Accepted"
assert (
self.flight2_planned.request.operational_intent.state
== OperationalIntentState.Accepted
), "flight2_planned must have state Accepted"

# TODO: check that flight data is the same across the different versions of the flight

assert (
self.flight2_planned.request.operational_intent.priority
> self.flight1_planned.request.operational_intent.priority
), "flight_2 must have higher priority than flight_1"
assert Volume4DCollection.from_interuss_scd_api(
self.flight1_planned.request.operational_intent.volumes
).intersects_vol4s(
Volume4DCollection.from_interuss_scd_api(
self.flight2_planned.request.operational_intent.volumes
)
), "flight1_planned and flight2_planned must intersect"

except KeyError as e:
raise ValueError(
Expand All @@ -134,7 +118,7 @@ def run(self, context: ExecutionContext):
self.end_test_case()

self.begin_test_case(
"Plan flight in conflict with planned flight managed by down USS"
"Plan Flight 1 in conflict with accepted operational intent managed by down USS"
)
self._plan_flight_conflict_planned()
self.end_test_case()
Expand Down Expand Up @@ -168,30 +152,68 @@ def _setup(self):
self._clear_op_intents()
self.end_test_step()

def _plan_flight_conflict_planned(self):

# Virtual USS plans high-priority flight 2 test step
self.begin_test_step("Virtual USS plans high-priority flight 2")
def _put_conflicting_op_intent_step(
self,
conflicting_intent: FlightIntent,
target_state: OperationalIntentState,
old_op_intent: Optional[OperationalIntentReference] = None,
) -> OperationalIntentReference:
if old_op_intent is not None:
key = [old_op_intent.ovn]
oi_id = old_op_intent.id
oi_ovn = old_op_intent.ovn
else:
key = None
oi_id = None
oi_ovn = None

if target_state == OperationalIntentState.Accepted:
msg_action = "creates"
msg_action_past = "created"
elif target_state == OperationalIntentState.Activated:
msg_action = "activates"
msg_action_past = "activated"
elif target_state == OperationalIntentState.Nonconforming:
msg_action = "transitions to Nonconforming"
msg_action_past = "transitioned to Nonconforming"
elif target_state == OperationalIntentState.Contingent:
msg_action = "transitions to Contingent"
msg_action_past = "transitioned to Contingent"
else:
raise ValueError(f"Invalid state {target_state}")

self.begin_test_step(f"Virtual USS {msg_action} conflicting operational intent")
oi_ref, _, query = self.dss.put_op_intent(
Volume4DCollection.from_interuss_scd_api(
self.flight2_planned.request.operational_intent.volumes
conflicting_intent.request.operational_intent.volumes
).to_f3548v21(),
[], # we assume there is no other operational intent in that area
OperationalIntentState.Accepted,
key,
target_state,
"https://fake.uss/down",
oi_id,
oi_ovn,
)
self.record_query(query)
with self.check(
"Operational intent successfully created", [self.dss.participant_id]
f"Operational intent successfully {msg_action_past}",
[self.dss.participant_id],
) as check:
if oi_ref is None:
check.record_failed(
"Operational intent not successfully created",
f"Operational intent not successfully {msg_action_past}",
Severity.High,
f"DSS responded code {query.status_code}; error message: {query.error_message}",
query_timestamps=[query.request.timestamp],
)
self.end_test_step()
return oi_ref

def _plan_flight_conflict_planned(self):

# Virtual USS creates conflicting operational intent test step
self._put_conflicting_op_intent_step(
self.flight1_planned, OperationalIntentState.Accepted
)

# Declare virtual USS as down at DSS test step
set_uss_down(
Expand All @@ -203,7 +225,7 @@ def _plan_flight_conflict_planned(self):
self,
self.tested_uss,
self.dss,
"Validate low-priority flight 1 status",
"Validate low-priority Flight 1 status",
self._intents_extent,
) as validator:
expected_results = {
Expand All @@ -226,7 +248,7 @@ def _plan_flight_conflict_planned(self):

resp, flight_id = submit_flight_intent(
self,
"Tested USS attempts to plan low-priority flight 1",
"Tested USS attempts to plan low-priority Flight 1",
"Successful planning",
expected_results,
failed_checks,
Expand Down
Loading

0 comments on commit 44be7a7

Please sign in to comment.