Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[uss_qualifier/netrid/dss/isa_simple] Refactor and complete create case #204

Merged
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion interfaces/rid/v1
Submodule v1 updated 1 files
+1 −1 remoteid/augmented.yaml
4 changes: 3 additions & 1 deletion monitoring/mock_uss/riddp/routes_observation.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ def riddp_display_data() -> Tuple[str, int]:

# Get ISAs in the DSS
t = arrow.utcnow().datetime
isa_list: FetchedISAs = fetch.isas(view, t, t, rid_version, utm_client)
isa_list: FetchedISAs = fetch.isas(
geo.get_latlngrect_vertices(view), t, t, rid_version, utm_client
)
if not isa_list.success:
msg = f"Error fetching ISAs from DSS: {isa_list.errors}"
logger.error(msg)
Expand Down
4 changes: 2 additions & 2 deletions monitoring/mock_uss/tracer/tracer_poll.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from monitoring.mock_uss.tracer import context
from monitoring.monitorlib.fetch.rid import FetchedISAs
from monitoring.monitorlib.fetch.scd import FetchedEntities
from monitoring.monitorlib.geo import make_latlng_rect
from monitoring.monitorlib.geo import make_latlng_rect, get_latlngrect_vertices
from monitoring.monitorlib.infrastructure import UTMClientSession
from monitoring.monitorlib.multiprocessing import SynchronizedValue

Expand Down Expand Up @@ -97,7 +97,7 @@ def poll_observation_areas() -> None:

def poll_isas(area: ObservationArea, logger: tracerlog.Logger) -> None:
rid_client = context.get_client(area.f3411.auth_spec, area.f3411.dss_base_url)
box = make_latlng_rect(area.area.volume)
box = get_latlngrect_vertices(make_latlng_rect(area.area.volume))

log_name = "poll_isas"
t0 = datetime.datetime.utcnow()
Expand Down
16 changes: 12 additions & 4 deletions monitoring/monitorlib/fetch/rid.py
Original file line number Diff line number Diff line change
Expand Up @@ -669,7 +669,7 @@ def has_different_content_than(self, other: Any) -> bool:


def isas(
box: s2sphere.LatLngRect,
area: List[s2sphere.LatLng],
start_time: datetime.datetime,
end_time: datetime.datetime,
rid_version: RIDVersion,
Expand All @@ -681,7 +681,7 @@ def isas(
t1 = rid_version.format_time(end_time)
if rid_version == RIDVersion.f3411_19:
op = v19.api.OPERATIONS[v19.api.OperationID.SearchIdentificationServiceAreas]
area = rid_v1.geo_polygon_string_from_s2(geo.get_latlngrect_vertices(box))
area = rid_v1.geo_polygon_string_from_s2(area)
url = f"{dss_base_url}{op.path}?area={area}&earliest_time={t0}&latest_time={t1}"
return FetchedISAs(
v19_query=fetch.query_and_describe(
Expand All @@ -694,7 +694,7 @@ def isas(
)
elif rid_version == RIDVersion.f3411_22a:
op = v22a.api.OPERATIONS[v22a.api.OperationID.SearchIdentificationServiceAreas]
area = rid_v2.geo_polygon_string_from_s2(geo.get_latlngrect_vertices(box))
area = rid_v2.geo_polygon_string_from_s2(area)
url = f"{dss_base_url}{op.path}?area={area}&earliest_time={t0}&latest_time={t1}"
return FetchedISAs(
v22a_query=fetch.query_and_describe(
Expand Down Expand Up @@ -981,7 +981,15 @@ def all_flights(
server_id: Optional[str] = None,
) -> FetchedFlights:
t = datetime.datetime.utcnow()
isa_list = isas(area, t, t, rid_version, session, dss_base_url, server_id=server_id)
isa_list = isas(
geo.get_latlngrect_vertices(area),
t,
t,
rid_version,
session,
dss_base_url,
server_id=server_id,
)

uss_flight_queries: Dict[str, FetchedUSSFlights] = {}
uss_flight_details_queries: Dict[str, FetchedUSSFlightDetails] = {}
Expand Down
8 changes: 8 additions & 0 deletions monitoring/monitorlib/geo.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,16 @@ class DistanceUnits(str, Enum):


class LatLngPoint(ImplicitDict):
"""Vertex in latitude and longitude"""

lat: float
"""Latitude (degrees)"""

lng: float
"""Longitude (degrees)"""

def as_s2sphere(self) -> s2sphere.LatLng:
return s2sphere.LatLng.from_degrees(self.lat, self.lng)


class Radius(ImplicitDict):
Expand Down
29 changes: 27 additions & 2 deletions monitoring/monitorlib/mutate/rid.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@
import yaml
from yaml.representer import Representer

from monitoring.monitorlib import fetch, infrastructure, rid_v1, rid_v2
from monitoring.monitorlib import (
fetch,
infrastructure,
rid_v1,
rid_v2,
schema_validation,
)


class ChangedSubscription(RIDQuery):
Expand Down Expand Up @@ -61,6 +67,8 @@ def errors(self) -> List[str]:
f"Error parsing F3411-22a USS PutSubscriptionResponse: {str(e)}"
]

# TODO: add schema validation (like ChangedISA)

return []

@property
Expand Down Expand Up @@ -327,7 +335,11 @@ def _v22a_response(

@property
def errors(self) -> List[str]:
if self.status_code != 200:
# Tolerate reasonable-but-technically-incorrect code 201
if not (
self.status_code == 200
or (self.mutation == "create" and self.status_code == 201)
):
return ["Failed to mutate ISA ({})".format(self.status_code)]
if self.query.response.json is None:
return ["ISA response did not include valid JSON"]
Expand Down Expand Up @@ -356,6 +368,19 @@ def errors(self) -> List[str]:
f"Error parsing F3411-22a USS PutIdentificationServiceAreaResponse: {str(e)}"
]

validation_errors = schema_validation.validate(
openapi_path=self.rid_version.openapi_path,
object_path=self.rid_version.openapi_delete_isa_response_path
if self.mutation == "delete"
else self.rid_version.openapi_put_isa_response_path,
instance=self.query.response.json,
)
if validation_errors:
return [
f"PUT ISA response JSON validation error: [{e.json_path}] {e.message}"
for e in validation_errors
]

return []

@property
Expand Down
13 changes: 12 additions & 1 deletion monitoring/monitorlib/rid.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from monitoring.monitorlib import schema_validation
from uas_standards.astm.f3411 import v19, v22a
import uas_standards.astm.f3411.v19.api
import uas_standards.astm.f3411.v19.constants
import uas_standards.astm.f3411.v22a.api
import uas_standards.astm.f3411.v22a.constants
Expand Down Expand Up @@ -56,6 +57,15 @@ def openapi_put_isa_response_path(self) -> str:
else:
raise ValueError(f"Unsupported RID version '{self}'")

@property
def openapi_delete_isa_response_path(self) -> str:
if self == RIDVersion.f3411_19:
return schema_validation.F3411_19.DeleteIdentificationServiceAreaResponse
elif self == RIDVersion.f3411_22a:
return schema_validation.F3411_22a.DeleteIdentificationServiceAreaResponse
else:
raise ValueError(f"Unsupported RID version '{self}'")

@property
def realtime_period(self) -> timedelta:
if self == RIDVersion.f3411_19:
Expand Down Expand Up @@ -202,7 +212,8 @@ def dss_max_subscriptions_per_area(self) -> int:

def flights_url_of(self, base_url: str) -> str:
if self == RIDVersion.f3411_19:
return base_url
flights_path = v19.api.OPERATIONS[v19.api.OperationID.SearchFlights].path
return base_url + flights_path
elif self == RIDVersion.f3411_22a:
flights_path = v22a.api.OPERATIONS[v22a.api.OperationID.SearchFlights].path
return base_url + flights_path
Expand Down
6 changes: 6 additions & 0 deletions monitoring/monitorlib/schema_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ class F3411_19(str, Enum):
PutIdentificationServiceAreaResponse = (
"components.schemas.PutIdentificationServiceAreaResponse"
)
DeleteIdentificationServiceAreaResponse = (
"components.schemas.DeleteIdentificationServiceAreaResponse"
)


class F3411_22a(str, Enum):
Expand All @@ -28,6 +31,9 @@ class F3411_22a(str, Enum):
PutIdentificationServiceAreaResponse = (
"components.schemas.PutIdentificationServiceAreaResponse"
)
DeleteIdentificationServiceAreaResponse = (
"components.schemas.DeleteIdentificationServiceAreaResponse"
)


class F3548_21(str, Enum):
Expand Down
15 changes: 11 additions & 4 deletions monitoring/uss_qualifier/configurations/dev/library/resources.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,19 @@ net_rid:
specification:
base_url: https://uss_qualifier.test.utm/dummy_base_url
footprint:
lat_min: 37.1853
lng_min: -80.6140
lat_max: 37.2148
lng_max: -80.5440
- lat: 37.1853
lng: -80.6140
- lat: 37.2148
lng: -80.6140
- lat: 37.2148
lng: -80.5440
- lat: 37.1853
lng: -80.5440
Comment on lines +35 to +42
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a particular benefit to using a polygon rather than a bounding box?

(I can think of a few: I was just wondering what the benefit is regarding to the tests we do)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes my implementation life easier, and the resource more flexible (notably it would be nice to use it in the DSS interoperability scenario, where specifying the polygon would be needed)

altitude_min: 0
altitude_max: 3048
reference_time: '2023-01-10T00:00:00.123456+00:00'
time_start: '2023-01-10T00:00:01.123456+00:00'
time_end: '2023-01-10T01:00:01.123456+00:00'

net_rid_sims:
adjacent_circular_flights_data:
Expand Down
30 changes: 27 additions & 3 deletions monitoring/uss_qualifier/resources/netrid/service_area.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
from implicitdict import ImplicitDict
from monitoring.monitorlib.geo import LatLngBoundingBox
import datetime
from typing import List

from implicitdict import ImplicitDict, StringBasedDateTime
from monitoring.monitorlib.geo import LatLngPoint

from monitoring.uss_qualifier.resources.resource import Resource

Expand All @@ -12,7 +15,7 @@ class ServiceAreaSpecification(ImplicitDict):

This URL will probably not identify a real resource in tests."""

footprint: LatLngBoundingBox
footprint: List[LatLngPoint]
"""2D outline of service area"""

altitude_min: float = 0
Expand All @@ -21,6 +24,27 @@ class ServiceAreaSpecification(ImplicitDict):
altitude_max: float = 3048
"""Upper altitude bound of service area, meters above WGS84 ellipsoid"""

reference_time: StringBasedDateTime
"""Reference time used to adjust start and end times at runtime"""

time_start: StringBasedDateTime
"""Start time of service area (relative to reference_time)"""

time_end: StringBasedDateTime
"""End time of service area (relative to reference_time)"""

def shifted_time_start(
self, new_reference_time: datetime.datetime
) -> datetime.datetime:
dt = new_reference_time - self.reference_time.datetime
return self.time_start.datetime + dt

def shifted_time_end(
self, new_reference_time: datetime.datetime
) -> datetime.datetime:
dt = new_reference_time - self.reference_time.datetime
return self.time_end.datetime + dt


class ServiceAreaResource(Resource[ServiceAreaSpecification]):
specification: ServiceAreaSpecification
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,17 +154,10 @@ def _verify_https_everywhere(self):
if query.get("server_id") is None
]
if len(unattr_queries) > 0:
# TODO clean this up: this is an internal requirement and not a check,
# leaving as-is during development to make sure the test-suite runs but we know about unattributed queries
# ultimately this check could go into the constructor and blow things up early

with self.check(
"No unattributed queries",
[],
) as check:
check.record_failed(
f"found unattributed queries: {unattr_queries}", Severity.Medium
)
self.record_note(
"unattributed-queries",
f"found unattributed queries: {unattr_queries}",
)

def _inspect_participant_queries(
self, participant_id: str, participant_queries: List[fetch.Query]
Expand Down
Loading