Skip to content

Commit e1492d3

Browse files
committed
[uss_qualifier/scenarios/utm/OpIntentValidator/expect_shared()] Check that USS op intent reference matches the DSS-published one (fix #1378)
1 parent 2ad7d98 commit e1492d3

File tree

4 files changed

+90
-9
lines changed

4 files changed

+90
-9
lines changed

.basedpyright/baseline.json

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19721,14 +19721,6 @@
1972119721
"lineCount": 1
1972219722
}
1972319723
},
19724-
{
19725-
"code": "reportPossiblyUnboundVariable",
19726-
"range": {
19727-
"startColumn": 16,
19728-
"endColumn": 23,
19729-
"lineCount": 1
19730-
}
19731-
},
1973219724
{
1973319725
"code": "reportArgumentType",
1973419726
"range": {

monitoring/uss_qualifier/scenarios/astm/utm/evaluation.py

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,81 @@
11
from datetime import timedelta
2+
from urllib.parse import urlparse
23

3-
from uas_standards.astm.f3548.v21.api import OperationalIntentDetails, Volume4D
4+
from uas_standards.astm.f3548.v21.api import (
5+
OperationalIntentDetails,
6+
OperationalIntentReference,
7+
UssAvailabilityState,
8+
Volume4D,
9+
)
410

511
from monitoring.monitorlib.geotemporal import Volume4DCollection
612
from monitoring.monitorlib.scd import priority_of
713

814
NUMERIC_PRECISION = 0.001
915

1016

17+
def validate_op_intent_reference(
18+
uss_oi: OperationalIntentReference,
19+
dss_oi: OperationalIntentReference,
20+
) -> str | None:
21+
# this function assumes all fields required by the OpenAPI definition are present as the format validation
22+
# should have been performed by OpIntentValidator._evaluate_op_intent_validation before
23+
errors_text: list[str] = []
24+
25+
def append_err(name: str, uss_value: str, dss_value: str):
26+
errors_text.append(
27+
f"{name} reported by USS ({uss_value}) does not match the one published to the DSS ({dss_value})"
28+
)
29+
return
30+
31+
if uss_oi.version != dss_oi.version:
32+
append_err("Version", str(uss_oi.version), str(dss_oi.version))
33+
34+
# use str.lower() to tolerate case mismatch for string values
35+
if uss_oi.id.lower() != dss_oi.id.lower():
36+
append_err("ID", uss_oi.id, dss_oi.id)
37+
if uss_oi.manager.lower() != dss_oi.manager.lower():
38+
append_err("Manager", uss_oi.manager, dss_oi.manager)
39+
if uss_oi.state.lower() != dss_oi.state.lower():
40+
append_err("State", uss_oi.state, dss_oi.state)
41+
if uss_oi.subscription_id.lower() != dss_oi.subscription_id.lower():
42+
append_err("Subscription ID", uss_oi.subscription_id, dss_oi.subscription_id)
43+
if uss_oi.uss_availability.lower() != dss_oi.uss_availability.lower():
44+
# tolerate empty value if unknown
45+
if (
46+
len(uss_oi.uss_availability) != 0
47+
or dss_oi.uss_availability != UssAvailabilityState.Unknown
48+
):
49+
append_err(
50+
"USS availability", uss_oi.uss_availability, dss_oi.uss_availability
51+
)
52+
53+
if uss_oi.uss_base_url != dss_oi.uss_base_url:
54+
# tolerate differences in URL that have no impact
55+
uss_url = urlparse(uss_oi.uss_base_url)
56+
dss_url = urlparse(dss_oi.uss_base_url)
57+
if (
58+
uss_url.scheme != dss_url.scheme
59+
or uss_url.netloc != dss_url.netloc
60+
or uss_url.path != dss_url.path
61+
):
62+
append_err("USS base URL", uss_oi.uss_base_url, dss_oi.uss_base_url)
63+
64+
# tolerate USS starting later than published on DSS
65+
if uss_oi.time_start.value.datetime < dss_oi.time_start.value.datetime - timedelta(
66+
seconds=NUMERIC_PRECISION
67+
):
68+
append_err("Start time", uss_oi.time_start.value, dss_oi.time_start.value)
69+
70+
# tolerate USS ending sooner than published on DSS
71+
if uss_oi.time_end.value.datetime > dss_oi.time_end.value.datetime + timedelta(
72+
seconds=NUMERIC_PRECISION
73+
):
74+
append_err("End time", uss_oi.time_start.value, dss_oi.time_start.value)
75+
76+
return "; ".join(errors_text) if errors_text else None
77+
78+
1179
def validate_op_intent_details(
1280
op_intent_details: OperationalIntentDetails,
1381
expected_priority: int,

monitoring/uss_qualifier/scenarios/astm/utm/test_steps.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
)
3030
from monitoring.uss_qualifier.scenarios.astm.utm.evaluation import (
3131
validate_op_intent_details,
32+
validate_op_intent_reference,
3233
)
3334
from monitoring.uss_qualifier.scenarios.scenario import (
3435
ScenarioDidNotStopError,
@@ -420,6 +421,7 @@ def _check_op_intent_details(
420421
details=f"Received status code {oi_full_query.status_code} from {self._flight_planner.participant_id} when querying for details of operational intent {oi_ref.id}; {e}",
421422
query_timestamps=[oi_full_query.request.timestamp],
422423
)
424+
return
423425

424426
validation_failures = self._evaluate_op_intent_validation(oi_full_query)
425427
with self._scenario.check(
@@ -444,6 +446,21 @@ def _check_op_intent_details(
444446
query_timestamps=[oi_full_query.request.timestamp],
445447
)
446448

449+
with self._scenario.check(
450+
"Operational intent reference reported by USS match the one published to the DSS",
451+
[self._flight_planner.participant_id],
452+
) as check:
453+
error_text = validate_op_intent_reference(
454+
oi_full.reference,
455+
oi_ref,
456+
)
457+
if error_text:
458+
check.record_failed(
459+
summary="Operational intent reference reported by USS does not match the one published to the DSS",
460+
details=error_text,
461+
query_timestamps=[oi_full_query.request.timestamp],
462+
)
463+
447464
with self._scenario.check(
448465
"Correct operational intent details", [self._flight_planner.participant_id]
449466
) as check:

monitoring/uss_qualifier/scenarios/astm/utm/validate_shared_operational_intent.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ If the operational intent details for the flight cannot be retrieved from the US
2929

3030
If the operational intent details response does not validate against [the GetOperationalIntentDetailsResponse schema of the OpenAPI specification](https://github.com/astm-utm/Protocol/blob/v1.0.0/utm.yaml#L1120), this check fill fail per **[astm.f3548.v21.USS0105,1](../../../requirements/astm/f3548/v21.md)**.
3131

32+
## 🛑 Operational intent reference reported by USS match the one published to the DSS check
33+
34+
If the operational intent reference reported by the USS do not match the operational intent reference published to the DSS, save for the OVN, this check will fail per **[astm.f3548.v21.USS0005](../../../requirements/astm/f3548/v21.md)**.
35+
3236
## 🛑 Correct operational intent details check
3337

3438
If the operational intent details reported by the USS do not match the user's flight intent, this check will fail per **[interuss.automated_testing.flight_planning.ExpectedBehavior](../../../requirements/interuss/automated_testing/flight_planning.md)** and **[astm.f3548.v21.OPIN0025](../../../requirements/astm/f3548/v21.md)**.

0 commit comments

Comments
 (0)