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

[mock_uss] Add user notifications for missing fields in injected flights #911

Merged
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions monitoring/mock_uss/ridsp/routes_injection.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ def ridsp_create_test(test_id: str) -> Tuple[str, int]:

with db as tx:
tx.tests[test_id] = record
tx.notifications.create_notifications_if_needed(record)
return flask.jsonify(
ChangeTestResponse(version=record.version, injected_flights=record.flights)
)
Expand Down
34 changes: 33 additions & 1 deletion monitoring/mock_uss/ridsp/user_notifications.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Optional
from typing import Optional, List

import datetime
import arrow
Expand All @@ -9,6 +9,9 @@
UserNotification,
Time,
)
from monitoring.monitorlib.rid_automated_testing.injection_api import TestFlight

from . import database


class ServiceProviderUserNotifications(ImplicitDict):
Expand All @@ -29,3 +32,32 @@ def record_notification(
self.user_notifications.append(
UserNotification(observed_at=observed_at_time, message=message)
)

def create_notifications_if_needed(self, record: "database.TestRecord"):

for notif in check_and_generate_missing_fields_notifications(record.flights):
the-glu marked this conversation as resolved.
Show resolved Hide resolved
self.record_notification(notif)


def check_and_generate_missing_fields_notifications(
injected_flights: List[TestFlight],
) -> List[str]:

missing_fields_notifications = []

for flight in injected_flights:
for tpos, telemetry in enumerate(flight.raw_telemetry):
for mandatory_field in flight.MANDATORY_TELEMETRY_FIELDS:
if telemetry.get(mandatory_field, None) is None:
missing_fields_notifications.append(
f"Flight #{flight.injection_id}, Telemetry #{tpos}, missing field {mandatory_field}"
)

if telemetry.get("position", None):
for mandatory_field in flight.MANDATORY_POSITION_FIELDS:
if telemetry["position"].get(mandatory_field, None) is None:
missing_fields_notifications.append(
f"Flight #{flight.injection_id}, Telemetry #{tpos}, missing field position.{mandatory_field}"
)

return missing_fields_notifications
59 changes: 59 additions & 0 deletions monitoring/monitorlib/rid_automated_testing/injection_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,65 @@


class TestFlight(injection.TestFlight):

MANDATORY_TELEMETRY_FIELDS = [
"timestamp",
"timestamp_accuracy",
"position",
"track",
"speed",
"speed_accuracy",
"vertical_speed",
]

# TODO: Handle accuracy_h and accuracy_v
MANDATORY_POSITION_FIELDS = ["lat", "lng", "alt"]
mickmis marked this conversation as resolved.
Show resolved Hide resolved

raw_telemetry: Optional[List[RIDAircraftState]]
"""Copy of original telemetry with potential invalid data"""

def __init__(self, *args, **kwargs):
"""Build a new test flight instance

Args:
filter_invalid_telemetry: If enabled, the constructor will filter out any invalid telemetry data. A copy of initial data is kept in the raw_telemetry field. Default to true.
Any other argument is passed to the parent injection.TestFlight class.
"""

super().__init__(*args, **kwargs)

# We filter out bad telemetry but keep a copy in raw_telemetry
self.raw_telemetry = self.telemetry

filter_invalid_telemetry = kwargs.pop("filter_invalid_telemetry", True)
the-glu marked this conversation as resolved.
Show resolved Hide resolved

if filter_invalid_telemetry:
filtered_telemetry = []

for telemetry in self.telemetry:

is_ok = True

for mandatory_field in self.MANDATORY_TELEMETRY_FIELDS:
if telemetry.get(mandatory_field, None) is None:
is_ok = False
break

if not is_ok:
continue

for mandatory_field in self.MANDATORY_POSITION_FIELDS:
if telemetry.position.get(mandatory_field, None) is None:
is_ok = False
break

if not is_ok:
continue

filtered_telemetry.append(telemetry)

self.telemetry = filtered_telemetry

def get_span(
self,
) -> Tuple[Optional[datetime.datetime], Optional[datetime.datetime]]:
Expand Down
Loading