diff --git a/NEXT_RELEASE_NOTES.md b/NEXT_RELEASE_NOTES.md index 31520ba97c..c694aacb88 100644 --- a/NEXT_RELEASE_NOTES.md +++ b/NEXT_RELEASE_NOTES.md @@ -39,6 +39,7 @@ The release notes should contain at least the following sections: * For any uss_qualifier test configurations using any of the test suites `suites.astm.utm.f3548_21`, `suites.faa.uft.message_signing`, `suites.uspace.flight_auth`, or `suites.uspace.required_services`, the following resources must be changed: * A new required resource named `conflicting_flights_provider` must be provided. It must be a `resources.resource.ResourceProvidingResource` providing `resources.flight_planning.FlightIntentsResource` instances with spatially separated flight intents for each planner combination used by `ConflictEqualPriorityNotPermitted`. One suitable implementation is `resources.geospatial.TriangularCascadeSoutheastResource` with `conflicting_flights` as its `base_resource`; see [f3548_self_contained](./monitoring/uss_qualifier/configurations/dev/f3548_self_contained.yaml) for an example. + * A new required resource named `planning_area_provider` must be provided to replace `planning_area`. It must be a `resources.resource.ResourceProvidingResource` providing `resources.planning_area.PlanningAreaResource` instances with spatially separated planning areas for each DSS instance used in the `dss_probing` test suite. One suitable implementation is `resources.geospatial.TriangularCascadeSoutheastResource` with `planning_area` as its `base_resource`; see [f3548_self_contained](./monitoring/uss_qualifier/configurations/dev/f3548_self_contained.yaml) for an example. The existing `planning_area` suite input is no longer used except by `suites.uspace.required_services`, which still requires it for NetRID tests. Keep any underlying planning area resource used as the provider's `base_resource`. ## Optional migration tasks diff --git a/monitoring/uss_qualifier/configurations/dev/f3548_self_contained.yaml b/monitoring/uss_qualifier/configurations/dev/f3548_self_contained.yaml index 55ada1fe85..83344ed5d1 100644 --- a/monitoring/uss_qualifier/configurations/dev/f3548_self_contained.yaml +++ b/monitoring/uss_qualifier/configurations/dev/f3548_self_contained.yaml @@ -29,7 +29,7 @@ v1: mock_uss: mock_uss utm_auth: utm_auth second_utm_auth: second_utm_auth - planning_area: planning_area + planning_area_provider: planning_area_provider problematically_big_area: problematically_big_area # When a test run is executed, a "baseline signature" is computed uniquely identifying the "baseline" of the test, @@ -219,6 +219,15 @@ v1: specification: base_url: https://testdummy.interuss.org/interuss/monitoring/uss_qualifier/configurations/dev/f3548_self_contained/planning_area + # Provide variants of the planning_area base resource by shifting them geographically + planning_area_provider: + resource_type: resources.geospatial.TriangularCascadeSoutheastResource + dependencies: + base_resource: planning_area + specification: + meters_east_margin: 10000 + meters_north_margin: 10000 + # An area designed to be soo big as to be refused by systems queries with it. problematically_big_area: $content_schema: monitoring/uss_qualifier/resources/definitions/ResourceDeclaration.json @@ -298,6 +307,16 @@ v1: # Allow certain actions to execute their sub-actions in parallel. parallelism_rules: + # The DSS probing generator (action 3 in f3548_21) isn't ready to run its actions in parallel yet + - max_parallelism: 1 + conditions: + - is_action_generator: + types: + - action_generators.resource_environments.ResourceEnvironmentsActionGenerator + defined_at: + # TODO: add ability to condition on potential actions + - test_suite.actions[3].action_generator + # ...but other ResourceEnvironmentsActionGenerators can have their actions run in parallel - max_parallelism: 2 conditions: - is_action_generator: diff --git a/monitoring/uss_qualifier/configurations/dev/library/resources.yaml b/monitoring/uss_qualifier/configurations/dev/library/resources.yaml index 37ff530059..dfed009280 100644 --- a/monitoring/uss_qualifier/configurations/dev/library/resources.yaml +++ b/monitoring/uss_qualifier/configurations/dev/library/resources.yaml @@ -212,6 +212,15 @@ zurich_planning_area: specification: base_url: https://testdummy.interuss.org/interuss/monitoring/uss_qualifier/configurations/dev/library/resources/zurich_planning_area +zurich_planning_area_provider: + $content_schema: monitoring/uss_qualifier/resources/definitions/ResourceDeclaration.json + resource_type: resources.geospatial.TriangularCascadeSoutheastResource + dependencies: + base_resource: zurich_planning_area + specification: + meters_east_margin: 10000 + meters_north_margin: 10000 + zurich_problematically_big_area: # A huge (as in "too big") area for checks around area sizes $content_schema: monitoring/uss_qualifier/resources/definitions/ResourceDeclaration.json resource_type: resources.VolumeResource @@ -316,6 +325,15 @@ che_planning_area: specification: base_url: https://testdummy.interuss.org/interuss/monitoring/uss_qualifier/configurations/dev/library/resources/che_planning_area +che_planning_area_provider: + $content_schema: monitoring/uss_qualifier/resources/definitions/ResourceDeclaration.json + resource_type: resources.geospatial.TriangularCascadeSoutheastResource + dependencies: + base_resource: che_planning_area + specification: + meters_east_margin: 10000 + meters_north_margin: 10000 + che_problematically_big_area: resource_type: resources.VolumeResource specification: diff --git a/monitoring/uss_qualifier/configurations/dev/message_signing.yaml b/monitoring/uss_qualifier/configurations/dev/message_signing.yaml index 57ca9b2b5e..728b3a4f12 100644 --- a/monitoring/uss_qualifier/configurations/dev/message_signing.yaml +++ b/monitoring/uss_qualifier/configurations/dev/message_signing.yaml @@ -9,6 +9,7 @@ v1: che_problematically_big_area: {$ref: 'library/resources.yaml#/che_problematically_big_area'} che_planning_area_volume: {$ref: 'library/resources.yaml#/che_planning_area_volume'} che_planning_area: {$ref: 'library/resources.yaml#/che_planning_area'} + che_planning_area_provider: {$ref: 'library/resources.yaml#/che_planning_area_provider'} combination_selector: resource_type: resources.flight_planning.FlightPlannerCombinationSelectorResource specification: @@ -61,7 +62,7 @@ v1: id_generator: id_generator utm_client_identity: utm_client_identity second_utm_auth: second_utm_auth - planning_area: che_planning_area + planning_area_provider: che_planning_area_provider problematically_big_area: che_problematically_big_area test_exclusions: test_exclusions execution: diff --git a/monitoring/uss_qualifier/configurations/dev/uspace.yaml b/monitoring/uss_qualifier/configurations/dev/uspace.yaml index 73bcc2dc27..d6b02b9643 100644 --- a/monitoring/uss_qualifier/configurations/dev/uspace.yaml +++ b/monitoring/uss_qualifier/configurations/dev/uspace.yaml @@ -18,6 +18,7 @@ v1: zurich_service_area: {$ref: 'library/resources.yaml#/zurich_service_area'} zurich_planning_area_volume: {$ref: 'library/resources.yaml#/zurich_planning_area_volume'} zurich_planning_area: {$ref: 'library/resources.yaml#/zurich_planning_area'} + zurich_planning_area_provider: {$ref: 'library/resources.yaml#/zurich_planning_area_provider'} zurich_problematically_big_area: {$ref: 'library/resources.yaml#/zurich_problematically_big_area'} zurich_flights_data: {$ref: 'library/resources.yaml#/zurich_flights_data'} utm_auth: {$ref: 'library/environment.yaml#/utm_auth'} @@ -82,6 +83,7 @@ v1: id_generator: id_generator service_area: zurich_service_area planning_area: zurich_planning_area + planning_area_provider: zurich_planning_area_provider problematically_big_area: zurich_problematically_big_area test_exclusions: test_exclusions @@ -119,6 +121,7 @@ v1: id_generator: id_generator service_area: service_area planning_area: planning_area + planning_area_provider: planning_area_provider problematically_big_area: problematically_big_area test_exclusions: test_exclusions diff --git a/monitoring/uss_qualifier/configurations/dev/utm_implementation_us/definitions/baseline_a.libsonnet b/monitoring/uss_qualifier/configurations/dev/utm_implementation_us/definitions/baseline_a.libsonnet index c537e4071c..46ead55cb6 100644 --- a/monitoring/uss_qualifier/configurations/dev/utm_implementation_us/definitions/baseline_a.libsonnet +++ b/monitoring/uss_qualifier/configurations/dev/utm_implementation_us/definitions/baseline_a.libsonnet @@ -32,7 +32,7 @@ function(env) { mock_uss: 'mock_uss', utm_auth: 'utm_auth', second_utm_auth: 'second_utm_auth', - planning_area: 'planning_area', + planning_area_provider: 'planning_area_provider', problematically_big_area: 'problematically_big_area', system_identity: 'system_identity', // dss_datastore_cluster: dss_datastore_cluster # TODO: Provide once local DSS uses a multi-node cluster @@ -153,6 +153,18 @@ function(env) { }, }, + // Provide variants of the planning_area base resource by shifting them geographically + planning_area_provider: { + resource_type: 'resources.geospatial.TriangularCascadeSoutheastResource', + dependencies: { + base_resource: 'planning_area', + }, + specification: { + meters_east_margin: 10000, + meters_north_margin: 10000, + }, + }, + // An area designed to be soo big as to be refused by systems queries with it. problematically_big_area: { resource_type: 'resources.VolumeResource', diff --git a/monitoring/uss_qualifier/resources/astm/f3548/v21/dss.py b/monitoring/uss_qualifier/resources/astm/f3548/v21/dss.py index 484d198fed..864fdec533 100644 --- a/monitoring/uss_qualifier/resources/astm/f3548/v21/dss.py +++ b/monitoring/uss_qualifier/resources/astm/f3548/v21/dss.py @@ -53,6 +53,7 @@ from monitoring.monitorlib.mutate.scd import MutatedSubscription from monitoring.uss_qualifier.resources.astm.dss import NotificationIndexImplementation from monitoring.uss_qualifier.resources.communications import AuthAdapterResource +from monitoring.uss_qualifier.resources.plural import PluralResource from monitoring.uss_qualifier.resources.resource import Resource @@ -817,7 +818,9 @@ class DSSInstancesSpecification(ImplicitDict): dss_instances: list[DSSInstanceSpecification] -class DSSInstancesResource(Resource[DSSInstancesSpecification]): +class DSSInstancesResource( + PluralResource[DSSInstanceResource], Resource[DSSInstancesSpecification] +): dss_instances: list[DSSInstanceResource] def __init__( @@ -835,3 +838,9 @@ def __init__( ) for i, s in enumerate(specification.dss_instances) ] + + def get_resource_instances_count(self) -> int: + return len(self.dss_instances) + + def get_resource_instance(self, index: int) -> DSSInstanceResource: + return self.dss_instances[index] diff --git a/monitoring/uss_qualifier/resources/combinations.py b/monitoring/uss_qualifier/resources/combinations.py index c5c60ccb77..a809677893 100644 --- a/monitoring/uss_qualifier/resources/combinations.py +++ b/monitoring/uss_qualifier/resources/combinations.py @@ -33,6 +33,9 @@ class ResourceCombinationsResource( For example, with a pre-existing dependent `flight_planners` FlightPlannersResource, a ResourceCombinationsResource(tested_uss=flight_planners, control_uss=flight_planners) will produce each combination of tested_uss=FP1, control_uss=FP2 for all FP1, FP2 combinations in flight_planners. + + A single dependent PluralResource enumerates its instances under the assigned resource ID. + If any dependent PluralResource is empty, no combinations are produced. """ _resource_sources: dict[ResourceID, PluralResource] @@ -53,13 +56,16 @@ def __init__( raise ValueError( f"Dependent resources for ResourceCombinationsResource must be PluralResources; dependent resource '{k}' was instead a {fullname(v.__class__)}" ) - if v.get_resource_instances_count() == 0: - # Can't fill this role because there are no resources to fill it with. - continue self._resource_sources[ResourceID(k)] = v def get_environments(self) -> Iterator[dict[ResourceID, Resource]]: """Get the combinations of resources fulfilling each specified role.""" + if any( + resource.get_resource_instances_count() == 0 + for resource in self._resource_sources.values() + ): + return + roles = [ _RoleCombination(role=k, resources=v, index=0) for k, v in self._resource_sources.items() diff --git a/monitoring/uss_qualifier/resources/planning_area.py b/monitoring/uss_qualifier/resources/planning_area.py index fd486c0d14..eba04c2e54 100644 --- a/monitoring/uss_qualifier/resources/planning_area.py +++ b/monitoring/uss_qualifier/resources/planning_area.py @@ -1,4 +1,5 @@ import datetime +from copy import deepcopy from implicitdict import ImplicitDict, Optional from uas_standards.astm.f3548.v21.api import ( @@ -11,11 +12,17 @@ UssBaseURL, ) -from monitoring.monitorlib.geo import make_latlng_rect +from monitoring.monitorlib.geo import ( + LatLngBoundingBox, + RelativeTranslation, + Transformation, + make_latlng_rect, +) from monitoring.monitorlib.geotemporal import Volume4D from monitoring.monitorlib.subscription_params import SubscriptionParams from monitoring.monitorlib.temporal import TestTimeContext, Time from monitoring.monitorlib.testing import make_fake_url +from monitoring.uss_qualifier.resources.geospatial import GeospatialResource from monitoring.uss_qualifier.resources.resource import Resource from monitoring.uss_qualifier.resources.volume import VolumeResource @@ -42,7 +49,7 @@ def get_base_url(self, frames_above: int = 1): return make_fake_url(frames_above=frames_above + 1) -class PlanningAreaResource(Resource[PlanningAreaSpecification]): +class PlanningAreaResource(GeospatialResource, Resource[PlanningAreaSpecification]): specification: PlanningAreaSpecification _volume: VolumeResource @@ -56,6 +63,29 @@ def __init__( self.specification = specification self._volume = volume + def get_extents(self) -> LatLngBoundingBox: + return LatLngBoundingBox.from_latlng_rect( + self.resolved_volume4d_with_times(None, None).rect_bounds + ) + + def move(self, meters_east: float, meters_north: float) -> "PlanningAreaResource": + volume_spec = deepcopy(self._volume.specification) + volume_spec.template.transformations = ( + volume_spec.template.transformations or [] + ) + [ + Transformation( + relative_translation=RelativeTranslation( + meters_east=meters_east, + meters_north=meters_north, + ) + ) + ] + return PlanningAreaResource( + specification=deepcopy(self.specification), + resource_origin=self.resource_origin, + volume=VolumeResource(volume_spec, self._volume.resource_origin), + ) + def resolved_volume4d(self, context: TestTimeContext) -> Volume4D: return self._volume.specification.template.resolve(context) diff --git a/monitoring/uss_qualifier/suites/astm/utm/f3548_21.md b/monitoring/uss_qualifier/suites/astm/utm/f3548_21.md index 239119a9dc..fddc07c0f9 100644 --- a/monitoring/uss_qualifier/suites/astm/utm/f3548_21.md +++ b/monitoring/uss_qualifier/suites/astm/utm/f3548_21.md @@ -7,7 +7,7 @@ 1. Scenario: [Get system versions](../../../scenarios/versioning/get_system_versions.md) ([`scenarios.versioning.GetSystemVersions`](../../../scenarios/versioning/get_system_versions.py)) 2. Scenario: [DSS pool information](../../../scenarios/astm/utm/dss/pool_info.md) ([`scenarios.astm.utm.dss.pool_info.PoolInfo`](../../../scenarios/astm/utm/dss/pool_info.py)) 3. Scenario: [ASTM F3548 flight planners preparation](../../../scenarios/astm/utm/prep_planners.md) ([`scenarios.astm.utm.PrepareFlightPlanners`](../../../scenarios/astm/utm/prep_planners.py)) -4. Action generator: [`action_generators.astm.f3548.ForEachDSS`](../../../action_generators/astm/f3548/for_each_dss.py) +4. Action generator: [`action_generators.resource_environments.ResourceEnvironmentsActionGenerator`](../../../action_generators/resource_environments.py) 1. Suite: [DSS testing for ASTM F3548-21](dss_probing.md) ([`suites.astm.utm.dss_probing`](dss_probing.yaml)) 5. Action generator: [`action_generators.flight_planning.FlightPlannerCombinations`](../../../action_generators/flight_planning/planner_combinations.py) 1. Scenario: [Validation of operational intents](../../../scenarios/astm/utm/flight_intent_validation/flight_intent_validation.md) ([`scenarios.astm.utm.FlightIntentValidation`](../../../scenarios/astm/utm/flight_intent_validation/flight_intent_validation.py)) diff --git a/monitoring/uss_qualifier/suites/astm/utm/f3548_21.yaml b/monitoring/uss_qualifier/suites/astm/utm/f3548_21.yaml index 114ec4a0d4..b3141e7692 100644 --- a/monitoring/uss_qualifier/suites/astm/utm/f3548_21.yaml +++ b/monitoring/uss_qualifier/suites/astm/utm/f3548_21.yaml @@ -25,7 +25,7 @@ resources: utm_client_identity: resources.communications.ClientIdentityResource mock_uss: resources.interuss.mock_uss.client.MockUSSResource? id_generator: resources.interuss.IDGeneratorResource - planning_area: resources.PlanningAreaResource + planning_area_provider: resources.resource.ResourceProvidingResource[resources.planning_area.PlanningAreaResource] problematically_big_area: resources.VolumeResource system_identity: resources.versioning.SystemIdentityResource? test_exclusions: resources.dev.TestExclusionsResource? @@ -40,6 +40,18 @@ local_resources: resource_type: resources.versioning.SystemIdentityResource specification: system_identity: astm.f3548.v21 + dss_environments: + resource_type: resources.combinations.ResourceCombinationsResource + dependencies: + dss: dss_instances? + specification: {} + dss_probing_environments: + resource_type: resources.environments.EnvironmentAugmentationResource + dependencies: + environments: dss_environments + planning_area: planning_area_provider + # TODO: populate flight_intents from non_conflicting_flights_provider + specification: {} priority_preemption_combinations: resource_type: resources.combinations.ResourceCombinationsResource dependencies: @@ -92,18 +104,19 @@ actions: flight_intents2: non_conflicting_flights? flight_intents_environments: flight_intents_environments? - action_generator: - generator_type: action_generators.astm.f3548.ForEachDSS + generator_type: action_generators.resource_environments.ResourceEnvironmentsActionGenerator resources: + dss_probing_environments: dss_probing_environments dss_instances: dss_instances dss_datastore_cluster: dss_datastore_cluster? second_utm_auth: second_utm_auth? utm_client_identity: utm_client_identity flight_intents: non_conflicting_flights id_generator: id_generator - planning_area: planning_area problematically_big_area: problematically_big_area test_exclusions: test_exclusions? specification: + resource_environments_source: dss_probing_environments action_to_repeat: test_suite: suite_type: suites.astm.utm.dss_probing @@ -118,8 +131,6 @@ actions: planning_area: planning_area problematically_big_area: problematically_big_area test_exclusions: test_exclusions? - dss_instances_source: dss_instances - dss_instance_id: dss - action_generator: generator_type: action_generators.flight_planning.FlightPlannerCombinations resources: diff --git a/monitoring/uss_qualifier/suites/faa/uft/message_signing.yaml b/monitoring/uss_qualifier/suites/faa/uft/message_signing.yaml index 189e29f8d8..345bf0288d 100644 --- a/monitoring/uss_qualifier/suites/faa/uft/message_signing.yaml +++ b/monitoring/uss_qualifier/suites/faa/uft/message_signing.yaml @@ -20,7 +20,7 @@ resources: id_generator: resources.interuss.IDGeneratorResource utm_client_identity: resources.communications.ClientIdentityResource second_utm_auth: resources.communications.AuthAdapterResource? - planning_area: resources.PlanningAreaResource + planning_area_provider: resources.resource.ResourceProvidingResource[resources.planning_area.PlanningAreaResource] problematically_big_area: resources.VolumeResource test_exclusions: resources.dev.TestExclusionsResource? actions: @@ -47,7 +47,7 @@ actions: id_generator: id_generator utm_client_identity: utm_client_identity second_utm_auth: second_utm_auth - planning_area: planning_area + planning_area_provider: planning_area_provider problematically_big_area: problematically_big_area test_exclusions: test_exclusions? - test_scenario: diff --git a/monitoring/uss_qualifier/suites/uspace/flight_auth.yaml b/monitoring/uss_qualifier/suites/uspace/flight_auth.yaml index 2e5916cdc9..bf78a6739d 100644 --- a/monitoring/uss_qualifier/suites/uspace/flight_auth.yaml +++ b/monitoring/uss_qualifier/suites/uspace/flight_auth.yaml @@ -22,7 +22,7 @@ resources: utm_client_identity: resources.communications.ClientIdentityResource utm_auth: resources.communications.AuthAdapterResource? second_utm_auth: resources.communications.AuthAdapterResource? - planning_area: resources.PlanningAreaResource + planning_area_provider: resources.resource.ResourceProvidingResource[resources.planning_area.PlanningAreaResource] problematically_big_area: resources.VolumeResource system_identity: resources.versioning.SystemIdentityResource? test_exclusions: resources.dev.TestExclusionsResource? @@ -47,7 +47,7 @@ actions: utm_client_identity: utm_client_identity utm_auth: utm_auth? second_utm_auth: second_utm_auth? - planning_area: planning_area + planning_area_provider: planning_area_provider problematically_big_area: problematically_big_area system_identity: system_identity? test_exclusions: test_exclusions? diff --git a/monitoring/uss_qualifier/suites/uspace/required_services.yaml b/monitoring/uss_qualifier/suites/uspace/required_services.yaml index e03e5f2337..f01b954a89 100644 --- a/monitoring/uss_qualifier/suites/uspace/required_services.yaml +++ b/monitoring/uss_qualifier/suites/uspace/required_services.yaml @@ -32,6 +32,7 @@ resources: id_generator: resources.interuss.IDGeneratorResource service_area: resources.netrid.ServiceAreaResource planning_area: resources.PlanningAreaResource + planning_area_provider: resources.resource.ResourceProvidingResource[resources.planning_area.PlanningAreaResource] problematically_big_area: resources.VolumeResource test_exclusions: resources.dev.TestExclusionsResource? @@ -67,7 +68,7 @@ actions: utm_auth: utm_auth? second_utm_auth: second_utm_auth? utm_client_identity: utm_client_identity - planning_area: planning_area + planning_area_provider: planning_area_provider problematically_big_area: problematically_big_area system_identity: system_identity test_exclusions: test_exclusions?