Skip to content

Commit

Permalink
[uss_qualifier] DSS0030 slight overlap subscription interactions
Browse files Browse the repository at this point in the history
  • Loading branch information
Shastick committed Nov 30, 2023
1 parent d00bc7c commit 4a3b372
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 0 deletions.
36 changes: 36 additions & 0 deletions monitoring/monitorlib/geo.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from implicitdict import ImplicitDict
import numpy as np
import s2sphere
from s2sphere import LatLng
from scipy.interpolate import RectBivariateSpline as Spline
import shapely.geometry
from uas_standards.astm.f3548.v21 import api as f3548v21
Expand Down Expand Up @@ -501,3 +502,38 @@ def egm96_geoid_offset(p: s2sphere.LatLng) -> float:
# listed -90 to 90. Since latitude data are symmetric, we can simply
# convert "-90 to 90" to "90 to -90" by inverting the requested latitude.
return _egm96.ev(-lat, lng)


def generate_slight_overlap_area(in_points: List[LatLng]) -> List[LatLng]:
"""
Takes a list of LatLng points and returns a list of LatLng points that represents
a polygon only slightly overlapping with the input, and that is roughly half the diameter of the input.
The returned polygon is built from the first point of the input, from which a square
is drawn in the direction opposite of the center of the input polygon.
"""
overlap_corner = in_points[0] # the spot that will have a tiny overlap

# Compute the center of mass of the input polygon
center = LatLng.from_degrees(
sum([point.lat().degrees for point in in_points]) / len(in_points),
sum([point.lng().degrees for point in in_points]) / len(in_points),
)

delta_lat = center.lat().degrees - overlap_corner.lat().degrees
delta_lng = center.lng().degrees - overlap_corner.lng().degrees

same_lat_point = LatLng.from_degrees(
overlap_corner.lat().degrees, overlap_corner.lng().degrees - delta_lng
)
same_lng_point = LatLng.from_degrees(
overlap_corner.lat().degrees - delta_lat, overlap_corner.lng().degrees
)

opposite_corner = LatLng.from_degrees(
overlap_corner.lat().degrees - delta_lat,
overlap_corner.lng().degrees - delta_lng,
)

return [overlap_corner, same_lat_point, opposite_corner, same_lng_point]
36 changes: 36 additions & 0 deletions monitoring/monitorlib/geo_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from typing import List, Tuple

from s2sphere import LatLng

from monitoring.monitorlib.geo import generate_slight_overlap_area


def _points(in_points: List[Tuple[float, float]]) -> List[LatLng]:
return [LatLng.from_degrees(*p) for p in in_points]


def test_generate_slight_overlap_area():
# Square around 0,0 of edge length 2 -> first corner at 1,1 -> expect a square with overlapping corner at 1,1
assert generate_slight_overlap_area(
_points([(1, 1), (1, -1), (-1, -1), (-1, 1)])
) == _points([(1, 1), (1, 2), (2, 2), (2, 1)])

# Square with diagonal from 0,0 to 1,1 -> first corner at 1,1 -> expect a square with overlapping corner at 1,1
assert generate_slight_overlap_area(
_points([(1, 1), (0, 1), (0, 0), (1, 0)])
) == _points([(1, 1), (1, 1.5), (1.5, 1.5), (1.5, 1)])

# Square with diagonal from 0,0 to -1,-1 -> first corner at -1,-1 -> expect a square with overlapping corner at -1,-1
assert generate_slight_overlap_area(
_points([(-1, -1), (0, -1), (0, 0), (-1, 0)])
) == _points([(-1, -1), (-1, -1.5), (-1.5, -1.5), (-1.5, -1)])

# Square with diagonal from 0,0 to -1,1 -> first corner at -1,1 -> expect a square with overlapping corner at -1,0
assert generate_slight_overlap_area(
_points([(-1, 1), (-1, 0), (0, 0), (0, 1)])
) == _points([(-1, 1), (-1, 1.5), (-1.5, 1.5), (-1.5, 1)])

# Square with diagonal from 0,0 to 1,-1 -> first corner at 1,-1 -> expect a square with overlapping corner at 1,-1
assert generate_slight_overlap_area(
_points([(1, -1), (1, 0), (0, 0), (0, -1)])
) == _points([(1, -1), (1, -1.5), (1.5, -1.5), (1.5, -1)])
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import arrow

from monitoring.monitorlib import geo
from monitoring.prober.infrastructure import register_resource_type
from monitoring.uss_qualifier.common_data_definitions import Severity
from monitoring.uss_qualifier.resources.astm.f3411.dss import DSSInstanceResource
Expand Down Expand Up @@ -35,13 +36,15 @@ def __init__(
# sub id is isa_id with last character replaced with '1'
# (the generated isa_id ends with a few '0's)
self._sub_id = self._isa_id[:-1] + "1"
self._slight_overlap_sub_id = self._isa_id[:-1] + "2"
self._isa_version: Optional[str] = None
self._isa = isa.specification

now = arrow.utcnow().datetime
self._isa_start_time = self._isa.shifted_time_start(now)
self._isa_end_time = self._isa.shifted_time_end(now)
self._isa_area = [vertex.as_s2sphere() for vertex in self._isa.footprint]
self._slight_overlap_area = geo.generate_slight_overlap_area(self._isa_area)

def run(self, context: ExecutionContext):
self.begin_test_scenario(context)
Expand Down Expand Up @@ -191,6 +194,41 @@ def _check_subscription_behaviors(self):
query_timestamps=[created_subscription.query.request.timestamp],
)

# Create a subscription to the ISA that only barely overlaps with it:
with self.check(
"Create a subscription within the ISA footprint", [self._dss.participant_id]
) as check:
slight_overlap_subscription = self._dss_wrapper.put_sub(
check=check,
area_vertices=self._slight_overlap_area,
alt_lo=self._isa.altitude_min,
alt_hi=self._isa.altitude_max,
start_time=self._isa_start_time,
end_time=self._isa_end_time,
uss_base_url=self._isa.base_url,
sub_id=self._slight_overlap_sub_id,
sub_version=None,
)

# Check the subscription
with self.check(
"Subscription that only barely overlaps the ISA contains the ISA",
[self._dss.participant_id],
) as check:
if created_isa.dss_query.isa.id not in [
isa.id for isa in slight_overlap_subscription.isas
]:
check.record_failed(
summary="Subscription response does not include the freshly created ISA",
severity=Severity.High,
participants=[self._dss.participant_id],
details=f"The subscription created for the area {self._isa_area} is expected to contain the ISA created for this same area. The returned subscription did not mention it.",
query_timestamps=[
created_isa.dss_query.query.request.timestamp,
created_subscription.query.request.timestamp,
],
)

# Delete the ISA
with self.check(
"Delete the ISA",
Expand Down Expand Up @@ -305,6 +343,9 @@ def _delete_isa_if_exists(self):

def _clean_any_sub(self):
self._dss_wrapper.cleanup_subs_in_area(self._isa_area)
# Explicitly clean up in the separate area in case the DSS does
# not return that subscription when searching in the ISA's footpring
self._dss_wrapper.cleanup_subs_in_area(self._slight_overlap_area)

def cleanup(self):
self.begin_cleanup()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from typing import Optional

from s2sphere import LatLng

from monitoring.monitorlib.fetch import rid as fetch
from monitoring.monitorlib.infrastructure import UTMClientSession
from monitoring.monitorlib.mutate import rid as mutate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ and return the up-to-date subscription in the response to the query mutating the

Failure to do so means that the DSS is not properly implementing **[astm.f3411.v19.DSS0030,a](../../../../../requirements/astm/f3411/v19.md)**.

#### Subscription that only barely overlaps the ISA contains the ISA check

A subscription that is created for a volume that only barely overlaps with the previously created ISA should still
contain the ISA in the reply from the server, otherwise the DSS does not comply with **[astm.f3411.v19.DSS0030,c](../../../../../requirements/astm/f3411/v19.md)**

#### Delete the ISA check

If that ISA cannot be deleted, the **[astm.f3411.v19.DSS0030,d](../../../../../requirements/astm/f3411/v19.md)** requirement to implement the ISA deletion endpoint might not be met.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ and return the up-to-date subscription in the response to the query mutating the

Failure to do so means that the DSS is not properly implementing **[astm.f3411.v22a.DSS0030,a](../../../../../requirements/astm/f3411/v22a.md)**.

#### Subscription that only barely overlaps the ISA contains the ISA check

A subscription that is created for a volume that only barely overlaps with the previously created ISA should still
contain the ISA in the reply from the server, otherwise the DSS does not comply with **[astm.f3411.v22a.DSS0030,c](../../../../../requirements/astm/f3411/v22a.md)**

#### Delete the ISA check

If that ISA cannot be deleted, the **[astm.f3411.v22a.DSS0030,d](../../../../../requirements/astm/f3411/v22a.md)** requirement to implement the ISA deletion endpoint might not be met.
Expand Down

0 comments on commit 4a3b372

Please sign in to comment.