diff --git a/monitoring/monitorlib/clients/flight_planning/flight_info_template.py b/monitoring/monitorlib/clients/flight_planning/flight_info_template.py index e34a4de77d..b18f936a80 100644 --- a/monitoring/monitorlib/clients/flight_planning/flight_info_template.py +++ b/monitoring/monitorlib/clients/flight_planning/flight_info_template.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Optional, Dict from implicitdict import ImplicitDict @@ -15,7 +15,7 @@ Volume4DTemplateCollection, Volume4DCollection, ) -from monitoring.monitorlib.temporal import Time +from monitoring.monitorlib.temporal import Time, TimeDuringTest from uas_standards.interuss.automated_testing.scd.v1 import api as scd_api @@ -31,11 +31,9 @@ class BasicFlightPlanInformationTemplate(ImplicitDict): area: Volume4DTemplateCollection """User intends to or may fly anywhere in this entire area.""" - def resolve(self, start_of_test: Time) -> BasicFlightPlanInformation: + def resolve(self, times: Dict[TimeDuringTest, Time]) -> BasicFlightPlanInformation: kwargs = {k: v for k, v in self.items()} - kwargs["area"] = Volume4DCollection( - [t.resolve(start_of_test) for t in self.area] - ) + kwargs["area"] = Volume4DCollection([t.resolve(times) for t in self.area]) return ImplicitDict.parse(kwargs, BasicFlightPlanInformation) @@ -53,15 +51,17 @@ class FlightInfoTemplate(ImplicitDict): additional_information: Optional[dict] """Any information relevant to a particular jurisdiction or use case not described in the standard schema. The keys and values must be agreed upon between the test designers and USSs under test.""" - def resolve(self, start_of_test: Time) -> FlightInfo: + def resolve(self, times: Dict[TimeDuringTest, Time]) -> FlightInfo: kwargs = {k: v for k, v in self.items()} - kwargs["basic_information"] = self.basic_information.resolve(start_of_test) + kwargs["basic_information"] = self.basic_information.resolve(times) return ImplicitDict.parse(kwargs, FlightInfo) - def to_scd_inject_request(self, start_of_test: Time) -> scd_api.InjectFlightRequest: + def to_scd_inject_request( + self, times: Dict[TimeDuringTest, Time] + ) -> scd_api.InjectFlightRequest: """Render a legacy SCD injection API request object from this object.""" - info = self.resolve(start_of_test) + info = self.resolve(times) if "astm_f3548_21" not in info or not info.astm_f3548_21: raise ValueError( f"Legacy SCD injection API requires astm_f3548_21 operational intent priority to be specified in FlightInfo" diff --git a/monitoring/monitorlib/geotemporal.py b/monitoring/monitorlib/geotemporal.py index 166c66f539..10a553d1fe 100644 --- a/monitoring/monitorlib/geotemporal.py +++ b/monitoring/monitorlib/geotemporal.py @@ -2,7 +2,7 @@ import math from datetime import datetime, timedelta -from typing import Optional, List, Tuple, Iterator +from typing import Optional, List, Tuple, Dict import arrow from implicitdict import ImplicitDict, StringBasedTimeDelta @@ -13,7 +13,7 @@ from monitoring.monitorlib import geo from monitoring.monitorlib.geo import LatLngPoint, Circle, Altitude, Volume3D, Polygon -from monitoring.monitorlib.temporal import TestTime, Time +from monitoring.monitorlib.temporal import TestTime, Time, TimeDuringTest class Volume4DTemplate(ImplicitDict): @@ -38,7 +38,7 @@ class Volume4DTemplate(ImplicitDict): altitude_upper: Optional[Altitude] = None """The maximum altitude at which the virtual user will fly while using this volume for their flight.""" - def resolve(self, start_of_test: Time) -> Volume4D: + def resolve(self, times: Dict[TimeDuringTest, Time]) -> Volume4D: """Resolve Volume4DTemplate into concrete Volume4D.""" # Make 3D volume kwargs = {} @@ -56,12 +56,12 @@ def resolve(self, start_of_test: Time) -> Volume4D: kwargs = {"volume": volume} if self.start_time is not None: - time_start = self.start_time.resolve(start_of_test) + time_start = self.start_time.resolve(times) else: time_start = None if self.end_time is not None: - time_end = self.end_time.resolve(start_of_test) + time_end = self.end_time.resolve(times) else: time_end = None diff --git a/monitoring/monitorlib/temporal.py b/monitoring/monitorlib/temporal.py index f86c384f6e..01b3a9f34c 100644 --- a/monitoring/monitorlib/temporal.py +++ b/monitoring/monitorlib/temporal.py @@ -1,7 +1,7 @@ from __future__ import annotations from datetime import datetime, timedelta from enum import Enum -from typing import Optional, List +from typing import Optional, List, Dict import arrow from implicitdict import ImplicitDict, StringBasedTimeDelta, StringBasedDateTime @@ -62,6 +62,17 @@ class NextDay(ImplicitDict): """Acceptable days of the week. Omit to indicate that any day of the week is acceptable.""" +class TimeDuringTest(str, Enum): + StartOfTestRun = "StartOfTestRun" + """The time at which the test run started.""" + + StartOfScenario = "StartOfScenario" + """The time at which the current scenario started.""" + + TimeOfEvaluation = "TimeOfEvaluation" + """The time at which a TestTime was resolved to an absolute time; generally close to 'now'.""" + + class TestTime(ImplicitDict): """Exactly one of the time option fields of this object must be specified.""" @@ -71,8 +82,8 @@ class TestTime(ImplicitDict): The value of absolute_time is limited given that the specific time a test will be started is unknown, and the jurisdictions usually impose a limit on how far in the future an operation can be planned. """ - start_of_test: Optional[dict] = None - """Time option field to, if specified, use the timestamp at which the current test run started.""" + time_during_test: Optional[TimeDuringTest] = None + """Time option field to, if specified, use a timestamp relating to the current test run.""" next_day: Optional[NextDay] = None """Time option field to use a timestamp equal to midnight beginning the next occurrence of any matching day following the specified reference timestamp.""" @@ -90,16 +101,20 @@ class TestTime(ImplicitDict): * "-08:00" (ISO time zone) * "US/Pacific" (IANA time zone)""" - def resolve(self: TestTime, start_of_test: Time) -> Time: + def resolve(self, times: Dict[TimeDuringTest, Time]) -> Time: """Resolve TestTime into specific Time.""" result = None if self.absolute_time is not None: result = self.absolute_time.datetime - elif self.start_of_test is not None: - result = start_of_test.datetime + elif self.time_during_test is not None: + if self.time_during_test not in times: + raise ValueError( + f"Specified {self.time_during_test} time during test was not provided when resolving TestTime" + ) + result = times[self.time_during_test].datetime elif self.next_day is not None: t0 = ( - arrow.get(self.next_day.starting_from.resolve(start_of_test).datetime) + arrow.get(self.next_day.starting_from.resolve(times).datetime) .to(self.next_day.time_zone) .datetime ) @@ -115,11 +130,11 @@ def resolve(self: TestTime, start_of_test: Time) -> Time: result = t elif self.offset_from is not None: result = ( - self.offset_from.starting_from.resolve(start_of_test).datetime + self.offset_from.starting_from.resolve(times).datetime + self.offset_from.offset.timedelta ) elif self.next_sun_position is not None: - t0 = self.next_sun_position.starting_from.resolve(start_of_test).datetime + t0 = self.next_sun_position.starting_from.resolve(times).datetime dt = timedelta(minutes=5) lat = self.next_sun_position.observed_from.lat diff --git a/monitoring/uss_qualifier/configurations/dev/library/resources.yaml b/monitoring/uss_qualifier/configurations/dev/library/resources.yaml index a67c1aa591..ffd6b0ca0f 100644 --- a/monitoring/uss_qualifier/configurations/dev/library/resources.yaml +++ b/monitoring/uss_qualifier/configurations/dev/library/resources.yaml @@ -127,7 +127,7 @@ che_conflicting_flights: file: path: file://./test_data/che/flight_intents/conflicting_flights.yaml # Note that this hash_sha512 field can be safely deleted if the content changes - hash_sha512: 381b6a75e66f2f4ead4cc637744a3c6594d0cdcabf80e13acef087acf3d9195a8dfb521b1f997824b5c0f9dd83167263695b99bdb4fd3e604ac6ac513dad54ab + hash_sha512: ac109b89c95381ba4685d6db5f7064dac64875a8875e58989aad19d91d2e7b10e568d5091749b5ea2b0892191a84486971d999b63ac8c73fd4249131111a6c58 che_invalid_flight_intents: $content_schema: monitoring/uss_qualifier/resources/definitions/ResourceDeclaration.json @@ -211,14 +211,14 @@ example_feature_check_table: units: M reference: SFC start_time: - start_of_test: { } + time_during_test: StartOfTestRun end_time: offset_from: starting_from: next_day: time_zone: Europe/Zurich starting_from: - start_of_test: { } + time_during_test: StartOfTestRun days_of_the_week: [ "Mo", "Fr" ] offset: 12h expected_result: Block @@ -252,7 +252,7 @@ example_feature_check_table: starting_from: offset_from: starting_from: - start_of_test: { } + time_during_test: StartOfTestRun offset: 12h use_timezone: +01:00 duration: 5m @@ -289,7 +289,7 @@ example_feature_check_table: next_day: time_zone: Europe/Zurich starting_from: - start_of_test: { } + time_during_test: StartOfTestRun offset: 12h duration: 5m expected_result: Advise diff --git a/monitoring/uss_qualifier/resources/flight_planning/flight_intent.py b/monitoring/uss_qualifier/resources/flight_planning/flight_intent.py index 7256ad8239..03fe381d3a 100644 --- a/monitoring/uss_qualifier/resources/flight_planning/flight_intent.py +++ b/monitoring/uss_qualifier/resources/flight_planning/flight_intent.py @@ -9,7 +9,7 @@ from monitoring.monitorlib.clients.flight_planning.flight_info_template import ( FlightInfoTemplate, ) -from monitoring.monitorlib.temporal import Time +from monitoring.monitorlib.temporal import Time, TimeDuringTest from monitoring.uss_qualifier.resources.files import ExternalFile from monitoring.uss_qualifier.resources.overrides import apply_overrides @@ -27,9 +27,14 @@ class FlightIntent(ImplicitDict): @staticmethod def from_flight_info_template(info_template: FlightInfoTemplate) -> FlightIntent: - t = Time(arrow.utcnow().datetime) - request = info_template.to_scd_inject_request(t) - return FlightIntent(reference_time=StringBasedDateTime(t), request=request) + t_now = Time(arrow.utcnow().datetime) + times = { + TimeDuringTest.StartOfTestRun: t_now, + TimeDuringTest.StartOfScenario: t_now, + TimeDuringTest.TimeOfEvaluation: t_now, + } # Not strictly correct, but this class is deprecated + request = info_template.to_scd_inject_request(times) + return FlightIntent(reference_time=StringBasedDateTime(t_now), request=request) FlightIntentID = str diff --git a/monitoring/uss_qualifier/scenarios/astm/utm/data_exchange_validation/get_op_data_validation.py b/monitoring/uss_qualifier/scenarios/astm/utm/data_exchange_validation/get_op_data_validation.py index 14536879b0..65f7e485eb 100644 --- a/monitoring/uss_qualifier/scenarios/astm/utm/data_exchange_validation/get_op_data_validation.py +++ b/monitoring/uss_qualifier/scenarios/astm/utm/data_exchange_validation/get_op_data_validation.py @@ -1,5 +1,9 @@ -from typing import Optional -from monitoring.monitorlib.temporal import Time +from typing import Optional, Dict + +from monitoring.monitorlib.clients.flight_planning.flight_info_template import ( + FlightInfoTemplate, +) +from monitoring.monitorlib.temporal import TimeDuringTest, Time import arrow from monitoring.monitorlib.clients.flight_planning.client import FlightPlannerClient @@ -12,7 +16,6 @@ FlightPlannerResource, ) from monitoring.monitorlib.geotemporal import Volume4DCollection -from monitoring.monitorlib.clients.flight_planning.flight_info import FlightInfo from monitoring.uss_qualifier.resources.interuss.mock_uss.client import ( MockUSSClient, @@ -35,11 +38,12 @@ plan_flight, delete_flight, ) +from monitoring.uss_qualifier.suites.suite import ExecutionContext class GetOpResponseDataValidationByUSS(TestScenario): - flight_1: FlightInfo - flight_2: FlightInfo + flight_1: FlightInfoTemplate + flight_2: FlightInfoTemplate tested_uss_client: FlightPlannerClient control_uss: MockUSSClient @@ -60,21 +64,24 @@ def __init__( self.dss = dss.dss if not flight_intents: - msg = f"No FlightIntentsResource was provided as input to this test, it is assumed that the jurisdiction of the tested USS ({self.tested_uss.config.participant_id}) does not allow any same priority conflicts, execution of the scenario was stopped without failure" + msg = f"No FlightIntentsResource was provided as input to this test, it is assumed that the jurisdiction does not allow any same priority conflicts, execution of the scenario was stopped without failure" self.record_note( "Jurisdiction of tested USS does not allow any same priority conflicts", msg, ) raise ScenarioCannotContinueError(msg) - t = Time(arrow.utcnow().datetime) - _flight_intents = { - k: v.resolve(t) for k, v in flight_intents.get_flight_intents().items() - } + _flight_intents = flight_intents.get_flight_intents() + t_now = Time(arrow.utcnow().datetime) + times = { + TimeDuringTest.StartOfTestRun: t_now, + TimeDuringTest.StartOfScenario: t_now, + TimeDuringTest.TimeOfEvaluation: t_now, + } extents = [] for intent in _flight_intents.values(): - extents.append(intent.basic_information.area.bounding_volume) + extents.append(intent.resolve(times).basic_information.area.bounding_volume) self._intents_extent = Volume4DCollection(extents).bounding_volume.to_f3548v21() try: @@ -83,8 +90,10 @@ def __init__( _flight_intents["flight_2"], ) - assert not self.flight_1.basic_information.area.intersects_vol4s( - self.flight_2.basic_information.area + assert not self.flight_1.resolve( + times + ).basic_information.area.intersects_vol4s( + self.flight_2.resolve(times).basic_information.area ), "flight_1 and flight_2 must not intersect" except KeyError as e: @@ -96,7 +105,11 @@ def __init__( f"`{self.me()}` TestScenario requirements for flight_intents not met: {e}" ) - def run(self, context): + def run(self, context: ExecutionContext): + times = { + TimeDuringTest.StartOfTestRun: Time(context.start_time), + TimeDuringTest.StartOfScenario: Time(arrow.utcnow().datetime), + } self.begin_test_scenario(context) self.record_note( @@ -109,17 +122,22 @@ def run(self, context): ) self.begin_test_case("Successfully plan flight near an existing flight") - self._tested_uss_plans_deconflicted_flight_near_existing_flight() + self._tested_uss_plans_deconflicted_flight_near_existing_flight(times) self.end_test_case() self.begin_test_case("Flight planning prevented due to invalid data sharing") - self._tested_uss_unable_to_plan_flight_near_invalid_shared_existing_flight() + self._tested_uss_unable_to_plan_flight_near_invalid_shared_existing_flight( + times + ) self.end_test_case() self.end_test_scenario() - def _tested_uss_plans_deconflicted_flight_near_existing_flight(self): - + def _tested_uss_plans_deconflicted_flight_near_existing_flight( + self, times: Dict[TimeDuringTest, Time] + ): + times[TimeDuringTest.TimeOfEvaluation] = Time(arrow.utcnow().datetime) + flight_2 = self.flight_2.resolve(times) with OpIntentValidator( self, self.control_uss_client, @@ -131,10 +149,10 @@ def _tested_uss_plans_deconflicted_flight_near_existing_flight(self): self, "Control_uss plans flight 2", self.control_uss_client, - self.flight_2, + flight_2, ) - validator.expect_shared(self.flight_2) + validator.expect_shared(flight_2) self.begin_test_step( "Precondition - check tested_uss has no subscription in flight 2 area" @@ -142,6 +160,9 @@ def _tested_uss_plans_deconflicted_flight_near_existing_flight(self): # ToDo - Add the test step details self.end_test_step() + times[TimeDuringTest.TimeOfEvaluation] = Time(arrow.utcnow().datetime) + flight_1 = self.flight_1.resolve(times) + with OpIntentValidator( self, self.tested_uss_client, @@ -153,11 +174,11 @@ def _tested_uss_plans_deconflicted_flight_near_existing_flight(self): self, "Tested_uss plans flight 1", self.tested_uss_client, - self.flight_1, + flight_1, ) validator.expect_shared( - self.flight_1, + flight_1, ) self.begin_test_step("Validate flight2 GET interaction") @@ -175,8 +196,12 @@ def _tested_uss_plans_deconflicted_flight_near_existing_flight(self): self, "Delete control_uss flight", self.control_uss_client, self.flight_2_id ) - def _tested_uss_unable_to_plan_flight_near_invalid_shared_existing_flight(self): - flight_info = self.flight_2 + def _tested_uss_unable_to_plan_flight_near_invalid_shared_existing_flight( + self, times: Dict[TimeDuringTest, Time] + ): + times[TimeDuringTest.TimeOfEvaluation] = Time(arrow.utcnow().datetime) + flight_info = self.flight_2.resolve(times) + # Modifying the request with invalid data behavior = MockUssFlightBehavior( modify_sharing_methods=["GET", "POST"], @@ -208,11 +233,14 @@ def _tested_uss_unable_to_plan_flight_near_invalid_shared_existing_flight(self): # ToDo - Add the test step details self.end_test_step() + times[TimeDuringTest.TimeOfEvaluation] = Time(arrow.utcnow().datetime) + flight_1 = self.flight_1.resolve(times) + _, self.flight_1_id = plan_flight_intent_expect_failed( self, "Tested_uss attempts to plan flight 1, expect failure", self.tested_uss_client, - self.flight_1, + flight_1, ) self.begin_test_step("Validate flight 1 not shared by tested_uss") diff --git a/monitoring/uss_qualifier/scenarios/flight_planning/prep_planners.py b/monitoring/uss_qualifier/scenarios/flight_planning/prep_planners.py index 6d3c82d43c..d7dac87e2b 100644 --- a/monitoring/uss_qualifier/scenarios/flight_planning/prep_planners.py +++ b/monitoring/uss_qualifier/scenarios/flight_planning/prep_planners.py @@ -8,7 +8,7 @@ PlanningActivityError, ) from monitoring.monitorlib.geotemporal import Volume4DCollection, Volume4D -from monitoring.monitorlib.temporal import Time +from monitoring.monitorlib.temporal import Time, TimeDuringTest from monitoring.uss_qualifier.common_data_definitions import Severity from monitoring.uss_qualifier.configurations.configuration import ParticipantID from monitoring.uss_qualifier.resources.flight_planning import ( @@ -35,7 +35,9 @@ def __init__( ): super().__init__() now = Time(arrow.utcnow().datetime) + times_now = {t: now for t in TimeDuringTest} later = now.offset(MAX_TEST_DURATION) + times_later = {t: later for t in TimeDuringTest} self.areas = [] for intents in ( flight_intents, @@ -48,14 +50,10 @@ def __init__( v4c = Volume4DCollection([]) for flight_info_template in intents.get_flight_intents().values(): v4c.extend( - flight_info_template.resolve( - start_of_test=now - ).basic_information.area + flight_info_template.resolve(times_now).basic_information.area ) v4c.extend( - flight_info_template.resolve( - start_of_test=later - ).basic_information.area + flight_info_template.resolve(times_later).basic_information.area ) self.areas.append(v4c.bounding_volume) self.flight_planners = { diff --git a/monitoring/uss_qualifier/scenarios/interuss/flight_authorization/general_flight_authorization.py b/monitoring/uss_qualifier/scenarios/interuss/flight_authorization/general_flight_authorization.py index 3f1cc24646..daee543e8c 100644 --- a/monitoring/uss_qualifier/scenarios/interuss/flight_authorization/general_flight_authorization.py +++ b/monitoring/uss_qualifier/scenarios/interuss/flight_authorization/general_flight_authorization.py @@ -1,3 +1,6 @@ +from datetime import datetime +from typing import Dict + import arrow from loguru import logger @@ -11,7 +14,7 @@ FlightPlanStatus, AdvisoryInclusion, ) -from monitoring.monitorlib.temporal import Time +from monitoring.monitorlib.temporal import Time, TimeDuringTest from monitoring.uss_qualifier.common_data_definitions import Severity from monitoring.uss_qualifier.configurations.configuration import ParticipantID from monitoring.uss_qualifier.resources.flight_planning import ( @@ -67,15 +70,18 @@ def __init__( def run(self, context: ExecutionContext): self.begin_test_scenario(context) + times = { + TimeDuringTest.StartOfTestRun: Time(context.start_time), + TimeDuringTest.StartOfScenario: Time(arrow.utcnow().datetime), + } self.begin_test_case("Flight planning") - self._plan_flights() + self._plan_flights(times) self.end_test_case() self.end_test_scenario() - def _plan_flights(self): - start_time = Time(arrow.utcnow().datetime) + def _plan_flights(self, times: Dict[TimeDuringTest, Time]): for row in self.table.rows: # Collect checks applicable to this row/test step checks = [ @@ -138,7 +144,8 @@ def _plan_flights(self): self.begin_dynamic_test_step(doc) # Attempt planning action - info = self.flight_intents[row.flight_intent].resolve(start_time) + times[TimeDuringTest.TimeOfEvaluation] = Time(arrow.utcnow().datetime) + info = self.flight_intents[row.flight_intent].resolve(times) with self.check(_VALID_API_RESPONSE_NAME, [self.participant_id]) as check: try: resp = self.flight_planner.try_plan_flight( diff --git a/monitoring/uss_qualifier/scenarios/interuss/geospatial_map/geospatial_feature_comprehension.py b/monitoring/uss_qualifier/scenarios/interuss/geospatial_map/geospatial_feature_comprehension.py index 5effd0ce75..92941590a7 100644 --- a/monitoring/uss_qualifier/scenarios/interuss/geospatial_map/geospatial_feature_comprehension.py +++ b/monitoring/uss_qualifier/scenarios/interuss/geospatial_map/geospatial_feature_comprehension.py @@ -1,6 +1,9 @@ +from datetime import datetime +from typing import Dict + import arrow -from monitoring.monitorlib.temporal import Time +from monitoring.monitorlib.temporal import Time, TimeDuringTest from monitoring.uss_qualifier.resources.interuss.geospatial_map import ( FeatureCheckTableResource, ) @@ -37,15 +40,18 @@ def __init__( def run(self, context: ExecutionContext): self.begin_test_scenario(context) + times = { + TimeDuringTest.StartOfTestRun: Time(context.start_time), + TimeDuringTest.StartOfScenario: Time(arrow.utcnow().datetime), + } self.begin_test_case("Map query") - self._map_query() + self._map_query(times) self.end_test_case() self.end_test_scenario() - def _map_query(self): - start_time = arrow.utcnow().datetime + def _map_query(self, times: Dict[TimeDuringTest, Time]): for row in self.table.rows: if row.expected_result not in _CHECK_NAMES: raise NotImplementedError( @@ -73,13 +79,14 @@ def _map_query(self): self.begin_dynamic_test_step(doc) if row.volumes: - concrete_volumes = [v.resolve(Time(start_time)) for v in row.volumes] + times[TimeDuringTest.TimeOfEvaluation] = Time(arrow.utcnow().datetime) + concrete_volumes = [v.resolve(times) for v in row.volumes] - # TODO: Query USSs under test - self.record_note( - "map_query", - f"TODO: Query USSs for features from {row.restriction_source} for {row.operation_rule_set} that cause {row.expected_result} from {concrete_volumes[0].time_start} to {concrete_volumes[0].time_end}", - ) + # TODO: Query USSs under test + self.record_note( + "map_query", + f"TODO: Query USSs for features from {row.restriction_source} for {row.operation_rule_set} that cause {row.expected_result} from {concrete_volumes[0].time_start} to {concrete_volumes[0].time_end}", + ) with self.check( _CHECK_NAMES[row.expected_result], [] diff --git a/monitoring/uss_qualifier/suites/suite.py b/monitoring/uss_qualifier/suites/suite.py index f5e27578bb..f8a11bf13b 100644 --- a/monitoring/uss_qualifier/suites/suite.py +++ b/monitoring/uss_qualifier/suites/suite.py @@ -379,6 +379,7 @@ def address(self) -> JSONAddress: class ExecutionContext(object): + start_time: datetime config: Optional[ExecutionConfiguration] top_frame: Optional[ActionStackFrame] current_frame: Optional[ActionStackFrame] @@ -387,6 +388,7 @@ def __init__(self, config: Optional[ExecutionConfiguration]): self.config = config self.top_frame = None self.current_frame = None + self.start_time = arrow.utcnow().datetime def sibling_queries(self) -> Iterator[Query]: if self.current_frame.parent is None: diff --git a/monitoring/uss_qualifier/test_data/che/flight_intents/conflicting_flights.yaml b/monitoring/uss_qualifier/test_data/che/flight_intents/conflicting_flights.yaml index 7eea1c46f2..cb79f2b1df 100644 --- a/monitoring/uss_qualifier/test_data/che/flight_intents/conflicting_flights.yaml +++ b/monitoring/uss_qualifier/test_data/che/flight_intents/conflicting_flights.yaml @@ -27,12 +27,12 @@ intents: start_time: offset_from: starting_from: - start_of_test: {} + time_during_test: StartOfTestRun offset: -1s end_time: offset_from: starting_from: - start_of_test: {} + time_during_test: StartOfTestRun offset: 8m astm_f3548_21: @@ -131,12 +131,12 @@ intents: start_time: offset_from: starting_from: - start_of_test: {} + time_during_test: StartOfTestRun offset: -1s end_time: offset_from: starting_from: - start_of_test: {} + time_during_test: StartOfTestRun offset: 8m astm_f3548_21: diff --git a/monitoring/uss_qualifier/test_data/che/flight_intents/general_flight_auth_flights.yaml b/monitoring/uss_qualifier/test_data/che/flight_intents/general_flight_auth_flights.yaml index 5add222026..28ceb36983 100644 --- a/monitoring/uss_qualifier/test_data/che/flight_intents/general_flight_auth_flights.yaml +++ b/monitoring/uss_qualifier/test_data/che/flight_intents/general_flight_auth_flights.yaml @@ -24,7 +24,7 @@ intents: # TODO: Change to SFC once mock_uss can process that datum reference: W84 start_time: - start_of_test: {} + time_during_test: StartOfTestRun use_timezone: Europe/Berlin end_time: offset_from: @@ -32,7 +32,7 @@ intents: next_day: time_zone: Europe/Zurich starting_from: - start_of_test: {} + time_during_test: StartOfTestRun days_of_the_week: ["Tu", "Th"] offset: 12h additional_information: @@ -81,7 +81,7 @@ intents: starting_from: offset_from: starting_from: - start_of_test: {} + time_during_test: StartOfTestRun offset: 12h duration: 5m additional_information: diff --git a/monitoring/uss_qualifier/test_data/che/flight_intents/invalid_flight_auths.yaml b/monitoring/uss_qualifier/test_data/che/flight_intents/invalid_flight_auths.yaml index ed476ecad2..8011174983 100644 --- a/monitoring/uss_qualifier/test_data/che/flight_intents/invalid_flight_auths.yaml +++ b/monitoring/uss_qualifier/test_data/che/flight_intents/invalid_flight_auths.yaml @@ -25,7 +25,7 @@ intents: start_time: offset_from: starting_from: - start_of_test: {} + time_during_test: StartOfTestRun offset: -1s duration: 5m diff --git a/monitoring/uss_qualifier/test_data/che/flight_intents/invalid_flight_intents.yaml b/monitoring/uss_qualifier/test_data/che/flight_intents/invalid_flight_intents.yaml index 487d7b8757..8325959d2d 100644 --- a/monitoring/uss_qualifier/test_data/che/flight_intents/invalid_flight_intents.yaml +++ b/monitoring/uss_qualifier/test_data/che/flight_intents/invalid_flight_intents.yaml @@ -25,7 +25,7 @@ intents: start_time: offset_from: starting_from: - start_of_test: {} + time_during_test: StartOfTestRun offset: -1s duration: 5m @@ -62,7 +62,7 @@ intents: - start_time: offset_from: starting_from: - start_of_test: { } + time_during_test: StartOfTestRun offset: 32d valid_conflict_tiny_overlap: diff --git a/monitoring/uss_qualifier/test_data/che/flight_intents/non_conflicting.yaml b/monitoring/uss_qualifier/test_data/che/flight_intents/non_conflicting.yaml index 9f544d76d0..e2f50c972a 100644 --- a/monitoring/uss_qualifier/test_data/che/flight_intents/non_conflicting.yaml +++ b/monitoring/uss_qualifier/test_data/che/flight_intents/non_conflicting.yaml @@ -26,7 +26,7 @@ intents: start_time: offset_from: starting_from: - start_of_test: { } + time_during_test: StartOfTestRun offset: -1s duration: 5m @@ -78,7 +78,7 @@ intents: start_time: offset_from: starting_from: - start_of_test: { } + time_during_test: StartOfTestRun offset: -1s duration: 5m diff --git a/monitoring/uss_qualifier/test_data/make_flight_intent_kml.py b/monitoring/uss_qualifier/test_data/make_flight_intent_kml.py index eb240ef495..f3b5795cf7 100644 --- a/monitoring/uss_qualifier/test_data/make_flight_intent_kml.py +++ b/monitoring/uss_qualifier/test_data/make_flight_intent_kml.py @@ -14,7 +14,7 @@ from implicitdict import ImplicitDict from monitoring.monitorlib.geo import AltitudeDatum, Altitude, DistanceUnits -from monitoring.monitorlib.temporal import Time +from monitoring.monitorlib.temporal import Time, TimeDuringTest from monitoring.uss_qualifier.fileio import load_dict_with_references, resolve_filename from monitoring.uss_qualifier.resources.flight_planning.flight_intent import ( FlightIntentCollection, @@ -32,9 +32,9 @@ def parse_args() -> argparse.Namespace: ) parser.add_argument( - "--start_of_test", + "--start_of_test_run", default=None, - help="When start_of_test should be. Defaults to now.", + help="When start_of_test_run should be. Defaults to now.", ) parser.add_argument( @@ -68,7 +68,12 @@ def main() -> int: path = args.flight_intent_collection output_path = os.path.splitext(resolve_filename(path))[0] + ".kml" - start_of_test = Time(args.start_of_test or arrow.utcnow().datetime) + start_of_test_run = Time(args.start_of_test_run or arrow.utcnow().datetime) + times = { + TimeDuringTest.StartOfTestRun: start_of_test_run, + TimeDuringTest.StartOfScenario: start_of_test_run, + TimeDuringTest.TimeOfEvaluation: start_of_test_run, + } if args.geoid_offset is None: logger.warning( "geoid_offset was not provided. Assuming 0 offset, and this may cause altitude errors of up to tens of meters." @@ -83,7 +88,7 @@ def main() -> int: folders = [] for name, template in flight_intents.items(): - flight_intent = template.resolve(start_of_test) + flight_intent = template.resolve(times) non_basic_info = json.loads( json.dumps( {k: v for k, v in flight_intent.items() if k != "basic_information"} diff --git a/monitoring/uss_qualifier/test_data/usa/kentland/flight_intents/non_conflicting.yaml b/monitoring/uss_qualifier/test_data/usa/kentland/flight_intents/non_conflicting.yaml index 336dace2ee..aa4952594e 100644 --- a/monitoring/uss_qualifier/test_data/usa/kentland/flight_intents/non_conflicting.yaml +++ b/monitoring/uss_qualifier/test_data/usa/kentland/flight_intents/non_conflicting.yaml @@ -26,7 +26,7 @@ intents: start_time: offset_from: starting_from: - start_of_test: { } + time_during_test: StartOfTestRun offset: -1s duration: 5m @@ -79,7 +79,7 @@ intents: start_time: offset_from: starting_from: - start_of_test: { } + time_during_test: StartOfTestRun offset: -1s duration: 5m @@ -101,8 +101,3 @@ intents: operator_id: CHEo5kut30e0mt01-qwe uas_id: '' uas_type_certificate: '' - - - - - diff --git a/schemas/monitoring/monitorlib/temporal/TestTime.json b/schemas/monitoring/monitorlib/temporal/TestTime.json index c46d8ed5a1..9c2d533009 100644 --- a/schemas/monitoring/monitorlib/temporal/TestTime.json +++ b/schemas/monitoring/monitorlib/temporal/TestTime.json @@ -48,10 +48,15 @@ } ] }, - "start_of_test": { - "description": "Time option field to, if specified, use the timestamp at which the current test run started.", + "time_during_test": { + "description": "Time option field to, if specified, use a timestamp relating to the current test run.", + "enum": [ + "StartOfTestRun", + "StartOfScenario", + "TimeOfEvaluation" + ], "type": [ - "object", + "string", "null" ] }, diff --git a/schemas/monitoring/uss_qualifier/resources/interuss/mock_uss/client/MockUSSSpecification.json b/schemas/monitoring/uss_qualifier/resources/interuss/mock_uss/client/MockUSSSpecification.json index 30f7b4cc0c..c50bf11445 100644 --- a/schemas/monitoring/uss_qualifier/resources/interuss/mock_uss/client/MockUSSSpecification.json +++ b/schemas/monitoring/uss_qualifier/resources/interuss/mock_uss/client/MockUSSSpecification.json @@ -14,6 +14,13 @@ "participant_id": { "description": "Test participant responsible for this mock USS.", "type": "string" + }, + "timeout_seconds": { + "description": "Number of seconds to allow for requests to this mock_uss instance. If None, use default.", + "type": [ + "number", + "null" + ] } }, "required": [