Skip to content

Commit b4988e4

Browse files
committed
[uss_qualifier/scenarios/utm] Fix op intents cleanup by determining intents extents in run rather than __init__
1 parent f9f43e5 commit b4988e4

File tree

6 files changed

+104
-53
lines changed

6 files changed

+104
-53
lines changed

.basedpyright/baseline.json

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19223,14 +19223,6 @@
1922319223
"lineCount": 1
1922419224
}
1922519225
},
19226-
{
19227-
"code": "reportOptionalMemberAccess",
19228-
"range": {
19229-
"startColumn": 35,
19230-
"endColumn": 53,
19231-
"lineCount": 1
19232-
}
19233-
},
1923419226
{
1923519227
"code": "reportArgumentType",
1923619228
"range": {

monitoring/uss_qualifier/resources/flight_planning/flight_intent_validation.py

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@
2222

2323
FlightIntentName = str
2424

25-
MAX_TEST_RUN_DURATION = timedelta(minutes=45)
26-
"""The longest a test run might take (to estimate flight intent timestamps prior to scenario execution)"""
25+
MAX_SCENARIO_EXEC_DURATION = timedelta(minutes=45)
26+
"""The longest a scenario run might take (to estimate flight intent timestamps prior to scenario execution)"""
27+
28+
MAX_TEST_RUN_DURATION = timedelta(hours=6)
29+
"""The longest a test run might take (to estimate flight intent timestamps prior to test run)"""
2730

2831

2932
@dataclass
@@ -43,32 +46,69 @@ class ExpectedFlightIntent:
4346
valid_uspace_flight_auth: bool | None = None
4447

4548

46-
def validate_flight_intent_templates(
49+
def estimate_scenario_execution_max_extents(
50+
scenario_time_context: TestTimeContext,
4751
templates: dict[FlightIntentID, FlightInfoTemplate],
48-
expected_intents: list[ExpectedFlightIntent],
4952
) -> Volume4D:
50-
"""
51-
Returns: the bounding extents of the flight intent templates
52-
"""
5353
extents = Volume4DCollection([])
5454

55+
scenario_start = TestTimeContext(
56+
{
57+
TimeDuringTest.StartOfTestRun: scenario_time_context[
58+
TimeDuringTest.StartOfTestRun
59+
],
60+
TimeDuringTest.StartOfScenario: scenario_time_context[
61+
TimeDuringTest.StartOfScenario
62+
],
63+
TimeDuringTest.TimeOfEvaluation: scenario_time_context[
64+
TimeDuringTest.StartOfScenario
65+
],
66+
}
67+
)
68+
flight_intents = {k: v.resolve(scenario_start) for k, v in templates.items()}
69+
for flight_intent in flight_intents.values():
70+
extents.extend(flight_intent.basic_information.area)
71+
72+
scenario_estimated_end = TestTimeContext(
73+
{
74+
TimeDuringTest.StartOfTestRun: scenario_time_context[
75+
TimeDuringTest.StartOfTestRun
76+
],
77+
TimeDuringTest.StartOfScenario: scenario_time_context[
78+
TimeDuringTest.StartOfScenario
79+
],
80+
TimeDuringTest.TimeOfEvaluation: Time(
81+
scenario_time_context[TimeDuringTest.StartOfScenario].datetime
82+
+ MAX_SCENARIO_EXEC_DURATION
83+
),
84+
}
85+
)
86+
flight_intents = {
87+
k: v.resolve(scenario_estimated_end) for k, v in templates.items()
88+
}
89+
for flight_intent in flight_intents.values():
90+
extents.extend(flight_intent.basic_information.area)
91+
92+
return extents.bounding_volume
93+
94+
95+
def validate_flight_intent_templates(
96+
templates: dict[FlightIntentID, FlightInfoTemplate],
97+
expected_intents: list[ExpectedFlightIntent],
98+
):
99+
"""Validate that all intents templates meet the criteria from `expected_intents` over the estimated maximum duration of the test run."""
100+
55101
now = Time(arrow.utcnow().datetime)
56102
context = TestTimeContext.all_times_are(now)
57103
flight_intents = {k: v.resolve(context) for k, v in templates.items()}
58-
for flight_intent in flight_intents.values():
59-
extents.extend(flight_intent.basic_information.area)
60104
validate_flight_intents(flight_intents, expected_intents, now)
61105

62106
later = Time(now.datetime + MAX_TEST_RUN_DURATION)
63107
context = TestTimeContext.all_times_are(later)
64108
context[TimeDuringTest.StartOfTestRun] = now
65109
flight_intents = {k: v.resolve(context) for k, v in templates.items()}
66-
for flight_intent in flight_intents.values():
67-
extents.extend(flight_intent.basic_information.area)
68110
validate_flight_intents(flight_intents, expected_intents, later)
69111

70-
return extents.bounding_volume
71-
72112

73113
def validate_flight_intents(
74114
intents: dict[FlightIntentID, FlightInfo],

monitoring/uss_qualifier/scenarios/astm/utm/nominal_planning/conflict_equal_priority_not_permitted/conflict_equal_priority_not_permitted.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,12 @@
2121
from monitoring.uss_qualifier.resources.astm.f3548.v21 import DSSInstanceResource
2222
from monitoring.uss_qualifier.resources.astm.f3548.v21.dss import DSSInstance
2323
from monitoring.uss_qualifier.resources.flight_planning import FlightIntentsResource
24+
from monitoring.uss_qualifier.resources.flight_planning.flight_intent import (
25+
FlightIntentID,
26+
)
2427
from monitoring.uss_qualifier.resources.flight_planning.flight_intent_validation import (
2528
ExpectedFlightIntent,
29+
estimate_scenario_execution_max_extents,
2630
validate_flight_intent_templates,
2731
)
2832
from monitoring.uss_qualifier.resources.flight_planning.flight_planners import (
@@ -69,6 +73,7 @@ class ConflictEqualPriorityNotPermitted(TestScenario):
6973
tested_uss: FlightPlannerClient
7074
control_uss: FlightPlannerClient
7175
dss: DSSInstance
76+
flight_intents_templates: dict[FlightIntentID, FlightInfoTemplate]
7277

7378
def __init__(
7479
self,
@@ -159,10 +164,12 @@ def __init__(
159164
), # Note: this intent expected to produce Nonconforming state, but this is hard to verify without telemetry. UAS state is not actually off-nominal.
160165
]
161166

162-
templates = flight_intents.get_flight_intents()
167+
self.flight_intents_templates = (
168+
flight_intents.get_flight_intents() if flight_intents else {}
169+
)
163170
try:
164-
self._intents_extent = validate_flight_intent_templates(
165-
templates, expected_flight_intents
171+
validate_flight_intent_templates(
172+
self.flight_intents_templates, expected_flight_intents
166173
)
167174
except ValueError as e:
168175
raise ValueError(
@@ -171,7 +178,9 @@ def __init__(
171178

172179
for efi in expected_flight_intents:
173180
setattr(
174-
self, efi.intent_id.replace("equal_prio_", ""), templates[efi.intent_id]
181+
self,
182+
efi.intent_id.replace("equal_prio_", ""),
183+
self.flight_intents_templates[efi.intent_id],
175184
)
176185

177186
def resolve_flight(self, flight_template: FlightInfoTemplate) -> FlightInfo:
@@ -191,11 +200,14 @@ def run(self, context: ExecutionContext):
191200

192201
self.begin_test_case("Prerequisites check")
193202
self.begin_test_step("Verify area is clear")
203+
estimated_max_extents = estimate_scenario_execution_max_extents(
204+
self.time_context, self.flight_intents_templates
205+
)
194206
validate_clear_area(
195207
self,
196208
self.dss,
197-
[self._intents_extent],
198-
ignore_self=True,
209+
[estimated_max_extents],
210+
ignore_self=False,
199211
)
200212
self.end_test_step()
201213
self.end_test_case()

monitoring/uss_qualifier/scenarios/astm/utm/off_nominal_planning/down_uss.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,6 @@ Make a dummy request to the DSS in order to resolve the USS ID of the virtual US
4343

4444
### [Restore virtual USS availability test step](../set_uss_available.md)
4545

46-
### Clear operational intents created by virtual USS test step
47-
Delete any leftover operational intent references created at DSS by virtual USS.
48-
49-
#### 🛑 Successful operational intents cleanup check
50-
If the search for operational intent references or their deletion fail, this check fails per **[astm.f3548.v21.DSS0005,2](../../../../requirements/astm/f3548/v21.md)** or **[astm.f3548.v21.DSS0005,1](../../../../requirements/astm/f3548/v21.md)**, respectively.
51-
5246
### [Verify area is clear test step](../clear_area_validation.md)
5347

5448
This scenario requires the area to have been cleared of operational intents. If it has not, this test step will raise a failed check.

monitoring/uss_qualifier/scenarios/astm/utm/off_nominal_planning/down_uss.py

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,17 @@
1818
PlanningActivityResult,
1919
)
2020
from monitoring.monitorlib.fetch import QueryError
21+
from monitoring.monitorlib.geotemporal import Volume4D, Volume4DCollection
2122
from monitoring.monitorlib.testing import make_fake_url
2223
from monitoring.uss_qualifier.resources.astm.f3548.v21 import DSSInstanceResource
2324
from monitoring.uss_qualifier.resources.astm.f3548.v21.dss import DSSInstance
2425
from monitoring.uss_qualifier.resources.flight_planning import FlightIntentsResource
26+
from monitoring.uss_qualifier.resources.flight_planning.flight_intent import (
27+
FlightIntentID,
28+
)
2529
from monitoring.uss_qualifier.resources.flight_planning.flight_intent_validation import (
2630
ExpectedFlightIntent,
31+
estimate_scenario_execution_max_extents,
2732
validate_flight_intent_templates,
2833
)
2934
from monitoring.uss_qualifier.resources.flight_planning.flight_planners import (
@@ -49,10 +54,13 @@ class DownUSS(TestScenario):
4954
flight1_planned: FlightInfoTemplate
5055

5156
uss_qualifier_sub: str
57+
scenario_execution_max_extents: Volume4D | None = None
58+
"""Actual bounding extent of the flight intents created by the USS qualifier acting as a virtual USS during the scenario execution."""
5259

5360
tested_uss: FlightPlannerClient
5461
dss_resource: DSSInstanceResource
5562
dss: DSSInstance
63+
flight_intents_templates: dict[FlightIntentID, FlightInfoTemplate]
5664

5765
def __init__(
5866
self,
@@ -65,18 +73,18 @@ def __init__(
6573
self.tested_uss = tested_uss.client
6674
self.dss = dss.get_instance(self._dss_req_scopes)
6775

68-
templates = flight_intents.get_flight_intents()
76+
self.flight_intents_templates = flight_intents.get_flight_intents()
6977
try:
70-
self._intents_extent = validate_flight_intent_templates(
71-
templates, self._expected_flight_intents
78+
validate_flight_intent_templates(
79+
self.flight_intents_templates, self._expected_flight_intents
7280
)
7381
except ValueError as e:
7482
raise ValueError(
7583
f"`{self.me()}` TestScenario requirements for flight_intents not met: {e}"
7684
)
7785

7886
for efi in self._expected_flight_intents:
79-
setattr(self, efi.intent_id, templates[efi.intent_id])
87+
setattr(self, efi.intent_id, self.flight_intents_templates[efi.intent_id])
8088

8189
@property
8290
def _dss_req_scopes(self) -> dict[str, str]:
@@ -97,7 +105,15 @@ def _expected_flight_intents(self) -> list[ExpectedFlightIntent]:
97105
]
98106

99107
def resolve_flight(self, flight_template: FlightInfoTemplate) -> FlightInfo:
100-
return flight_template.resolve(self.time_context.evaluate_now())
108+
flight = flight_template.resolve(self.time_context.evaluate_now())
109+
110+
extents = Volume4DCollection([])
111+
if self.scenario_execution_max_extents is not None:
112+
extents.append(self.scenario_execution_max_extents)
113+
extents.extend(flight.basic_information.area)
114+
self.scenario_execution_max_extents = extents.bounding_volume
115+
116+
return flight
101117

102118
def run(self, context: ExecutionContext):
103119
self.begin_test_scenario(context)
@@ -120,11 +136,15 @@ def run(self, context: ExecutionContext):
120136
self.end_test_scenario()
121137

122138
def _setup(self):
139+
estimated_max_extents = estimate_scenario_execution_max_extents(
140+
self.time_context, self.flight_intents_templates
141+
)
142+
123143
self.begin_test_step("Resolve USS ID of virtual USS")
124144
with self.check("Successful dummy query", [self.dss.participant_id]) as check:
125145
try:
126146
_, dummy_query = self.dss.find_op_intent(
127-
self._intents_extent.to_f3548v21()
147+
estimated_max_extents.to_f3548v21()
128148
)
129149
self.record_query(dummy_query)
130150
except QueryError as e:
@@ -146,16 +166,12 @@ def _setup(self):
146166
set_uss_available(self, self.dss, self.uss_qualifier_sub)
147167
self.end_test_step()
148168

149-
self.begin_test_step("Clear operational intents created by virtual USS")
150-
self._clear_op_intents()
151-
self.end_test_step()
152-
153169
self.begin_test_step("Verify area is clear")
154170
validate_clear_area(
155171
self,
156172
self.dss,
157-
[self._intents_extent],
158-
ignore_self=True,
173+
[estimated_max_extents],
174+
ignore_self=False,
159175
)
160176
self.end_test_step()
161177

@@ -279,16 +295,19 @@ def _clear_op_intents(self):
279295
with self.check(
280296
"Successful operational intents cleanup", [self.dss.participant_id]
281297
) as check:
298+
if self.scenario_execution_max_extents is None:
299+
return
300+
282301
try:
283302
oi_refs, find_query = self.dss.find_op_intent(
284-
self._intents_extent.to_f3548v21()
303+
self.scenario_execution_max_extents.to_f3548v21()
285304
)
286305
self.record_query(find_query)
287306
except QueryError as e:
288307
self.record_queries(e.queries)
289308
find_query = e.queries[0]
290309
check.record_failed(
291-
summary=f"Failed to query operational intent references from DSS in {self._intents_extent} for cleanup",
310+
summary=f"Failed to query operational intent references from DSS in {self.scenario_execution_max_extents} for cleanup",
292311
details=f"DSS responded code {find_query.status_code}; {e}",
293312
query_timestamps=[find_query.request.timestamp],
294313
)

monitoring/uss_qualifier/scenarios/astm/utm/off_nominal_planning/down_uss_equal_priority_not_permitted.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,6 @@ Make a dummy request to the DSS in order to resolve the USS ID of the virtual US
4646

4747
### [Restore virtual USS availability test step](../set_uss_available.md)
4848

49-
### Clear operational intents created by virtual USS test step
50-
Delete any leftover operational intents created at DSS by virtual USS.
51-
52-
#### 🛑 Successful operational intents cleanup check
53-
If the search for operational intent references or their deletion fail, this check fails per **[astm.f3548.v21.DSS0005,2](../../../../requirements/astm/f3548/v21.md)** or **[astm.f3548.v21.DSS0005,1](../../../../requirements/astm/f3548/v21.md)**, respectively.
54-
5549
### [Verify area is clear test step](../clear_area_validation.md)
5650

5751
This scenario requires the area to have been cleared of operational intents. If it has not, this test step will raise a failed check.

0 commit comments

Comments
 (0)