Skip to content

Commit

Permalink
NET0460 query the details endpoint to collect perf stats
Browse files Browse the repository at this point in the history
  • Loading branch information
Shastick committed Sep 1, 2023
1 parent 145d461 commit b184a0f
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 6 deletions.
11 changes: 10 additions & 1 deletion monitoring/monitorlib/fetch/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

from implicitdict import ImplicitDict, StringBasedDateTime
from monitoring.monitorlib import infrastructure

from monitoring.monitorlib.rid import RIDVersion

TIMEOUTS = (5, 5) # Timeouts of `connect` and `read` in seconds
ATTEMPTS = (
Expand Down Expand Up @@ -145,6 +145,15 @@ class QueryType(str, Enum):
F3411v22aFlightDetails = "astm.f3411.v22a.sp.flight_details"
F3411v19aFlightDetails = "astm.f3411.v19.sp.flight_details"

@staticmethod
def flight_details(rid_version: RIDVersion):
if rid_version == RIDVersion.f3411_19:
return QueryType.F3411v19aFlightDetails
elif rid_version == RIDVersion.f3411_22a:
return QueryType.F3411v22aFlightDetails
else:
raise ValueError(f"Unsupported RID version: {rid_version}")


class Query(ImplicitDict):
request: RequestDescription
Expand Down
23 changes: 23 additions & 0 deletions monitoring/monitorlib/rid.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ def read_scope(self) -> str:
else:
raise ValueError("Unsupported RID version '{}'".format(self))

@property
def dss_read_isa_scope(self) -> str:
# Same regardless of ASTM RID version
return "dss.read.identification_service_areas"

@property
def realtime_period(self) -> timedelta:
if self == RIDVersion.f3411_19:
Expand Down Expand Up @@ -155,6 +160,24 @@ def dp_data_resp_percentile95_s(self) -> float:
else:
raise ValueError("Unsupported RID version '{}'".format(self))

@property
def dp_details_resp_percentile95_s(self) -> float:
if self == RIDVersion.f3411_19:
return v19.constants.NetDpDetailsResponse95thPercentileSeconds
elif self == RIDVersion.f3411_22a:
return v22a.constants.NetDpDetailsResponse95thPercentileSeconds
else:
raise ValueError("Unsupported RID version '{}'".format(self))

@property
def dp_details_resp_percentile99_s(self) -> float:
if self == RIDVersion.f3411_19:
return v19.constants.NetDpDetailsResponse99thPercentileSeconds
elif self == RIDVersion.f3411_22a:
return v22a.constants.NetDpDetailsResponse99thPercentileSeconds
else:
raise ValueError("Unsupported RID version '{}'".format(self))

@property
def dp_data_resp_percentile99_s(self) -> float:
if self == RIDVersion.f3411_19:
Expand Down
5 changes: 4 additions & 1 deletion monitoring/uss_qualifier/resources/netrid/observers.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ def observe_flight_details(
self, flight_id: str
) -> Tuple[Optional[observation_api.GetDetailsResponse], fetch.Query]:
query = fetch.query_and_describe(
self.session, "GET", f"/display_data/{flight_id}"
self.session,
"GET",
f"/display_data/{flight_id}",
scope=self.rid_version.dss_read_isa_scope,
)
try:
result = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ def run(self):
self._dp_display_data_times_step()

self.end_test_step()
self.begin_test_step("Performance of /display_data/<flight_id> requests")
self._dp_display_data_details_times_step()
self.end_test_step()

self.end_test_case()

# SP performance
Expand All @@ -105,6 +109,59 @@ def run(self):

self.end_test_scenario()

def _dp_display_data_details_times_step(self):
"""
Check performance of /display_data/<flight_id> requests and confirm they conform to
NetDpDetailsResponse95thPercentile (2s) and NetDpDetailsResponse99thPercentile (6s)
"""
for participant, all_queries in self._queries_by_participant.items():
relevant_queries: List[fetch.Query] = list()
for query in all_queries:

if (
query.status_code == 200
and query.has_field_with_value("query_type")
and (
query.query_type == QueryType.F3411v19aFlightDetails
or query.query_type == QueryType.F3411v22aFlightDetails
)
):
relevant_queries.append(query)

if len(relevant_queries) == 0:
# this may be a service provider
self.record_note(
f"{participant}/display_data/<flight_id>",
"skipped check: no relevant queries",
)
continue

# compute percentiles
durations = [query.response.elapsed_s for query in relevant_queries]
[p95, p99] = evaluation.compute_percentiles(durations, [95, 99])
with self.check(
"Performance of /display_data/<flight_id> requests", [participant]
) as check:
if p95 > self._rid_version.dp_details_resp_percentile95_s:
check.record_failed(
summary=f"95th percentile of durations for DP display_data details queries is higher than threshold",
severity=Severity.Medium,
participants=[participant],
details=f"threshold: {self._rid_version.dp_details_resp_percentile95_s}s, 95th percentile: {p95}s",
)
if p99 > self._rid_version.dp_details_resp_percentile99_s:
check.record_failed(
summary=f"99th percentile of durations for DP display_data details queries is higher than threshold",
severity=Severity.Medium,
participants=[participant],
details=f"threshold: {self._rid_version.dp_details_resp_percentile99_s}s, 99th percentile: {p99}s",
)

self.record_note(
f"{participant}/display_data/<flight_id> stats computed on {len(durations)} queries",
f"95th percentile: {p95}s, 99th percentile: {p99}s",
)

def _sp_flights_area_times_step(self):
for participant, all_queries in self._queries_by_participant.items():
# identify successful flights queries
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
RIDCommonDictionaryEvaluator,
)

from monitoring.monitorlib.fetch import Query
from monitoring.monitorlib.fetch import Query, QueryType
from monitoring.monitorlib.fetch.rid import (
all_flights,
FetchedFlights,
Expand Down Expand Up @@ -261,6 +261,21 @@ def evaluate_system_instantaneously(
query,
verified_sps,
)
# We also issue queries to the flight details endpoint in order to collect
# performance statistics, which are computed and checked at a later stage.
if query.status_code == 200:
# If there are multiple flights, we only issue a single details query for the first returned one,
# as we don't want to slow down the test we are piggy-backing on.
if len(observation.flights) > 0:
(_, detailQuery) = observer.observe_flight_details(
observation.flights[0].id
)
# Record query metadata for alter use in the aggregate checks
detailQuery.server_id = observer.participant_id
detailQuery.query_type = QueryType.flight_details(
self._rid_version
)
self._test_scenario.record_query(detailQuery)

# TODO: If bounding rect is smaller than cluster threshold, expand slightly above cluster threshold and re-observe
# TODO: If bounding rect is smaller than area-too-large threshold, expand slightly above area-too-large threshold and re-observe
Expand Down Expand Up @@ -617,14 +632,14 @@ def _evaluate_clusters_observation(
check.record_failed(
summary="Error while evaluating clustered area view. Missing flight",
severity=Severity.Medium,
details=f"{expected_count-clustered_flight_count} (~{uncertain_count}) missing flight(s)",
details=f"{expected_count - clustered_flight_count} (~{uncertain_count}) missing flight(s)",
)
elif clustered_flight_count > expected_count + uncertain_count:
# Unexpected flight
check.record_failed(
summary="Error while evaluating clustered area view. Unexpected flight",
severity=Severity.Medium,
details=f"{clustered_flight_count-expected_count} (~{uncertain_count}) unexpected flight(s)",
details=f"{clustered_flight_count - expected_count} (~{uncertain_count}) unexpected flight(s)",
)
elif clustered_flight_count == expected_count:
# evaluate cluster obfuscation distance
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ The observers to evaluate in the report.

## Performance of Display Providers requests test case

### Performance of /display_data/<flight_id> requests test step

#### Performance of /display_data/<flight_id> requests check

**[astm.f3411.v19.NET0460](../../../../requirements/astm/f3411/v19.md) Checks that the DP response times for the
Display Application's flight details requests have a p95 and p99 that are respectively below
`NetDpDetailsResponse95thPercentileSeconds` (2 seconds) and `NetDpDetailsResponse99thPercentileSeconds` (6 seconds).

### Performance of /display_data requests test step
In this step, all successful display data queries made during the execution of the previous scenarios are aggregated per
observer and per request (identified by their URLs). For each of those, and using the session length
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,16 @@ The observers to evaluate in the report.

## Performance of Display Providers requests test case

### Performance of /display_data requests test step
### Performance of /display_data/<flight_id> requests test step

#### Performance of /display_data/<flight_id> requests check

**[astm.f3411.v19.NET0460](../../../../requirements/astm/f3411/v22a.md) Checks that the DP response times for the
Display Application's flight details requests have a p95 and p99 that are respectively below
`NetDpDetailsResponse95thPercentileSeconds` (2 seconds) and `NetDpDetailsResponse99thPercentileSeconds` (6 seconds).

In this step, all successful display data queries made during the execution of the previous scenarios are aggregated per
### Performance of /display_data requests test step
observer and per request (identified by their URLs). For each of those, and using the session length
`NetMinSessionLength`, the queries are split between initial and subsequent ones.
The percentiles of both all the initial and all the subsequent queries are then computed to be checked.
Expand Down

0 comments on commit b184a0f

Please sign in to comment.