Skip to content
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
2 changes: 1 addition & 1 deletion monitoring/mock_uss/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ services:
- MOCK_USS_PUBLIC_KEY=/var/test-certs/auth2.pem
- MOCK_USS_TOKEN_AUDIENCE=scdsc.log.uss6.localutm,localhost,host.docker.internal
- MOCK_USS_BASE_URL=http://scdsc.log.uss6.localutm
- MOCK_USS_SERVICES=scdsc,interaction_logging
- MOCK_USS_SERVICES=scdsc,interaction_logging,flight_planning
- MOCK_USS_INTERACTIONS_LOG_DIR=output/scdsc_interaction_logs
- MOCK_USS_PORT=80
expose:
Expand Down
1 change: 1 addition & 0 deletions monitoring/mock_uss/start_all_local_mocks.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ monitoring/mock_uss/wait_for_mock_uss.sh mock_uss_riddp_v19
monitoring/mock_uss/wait_for_mock_uss.sh mock_uss_ridsp
monitoring/mock_uss/wait_for_mock_uss.sh mock_uss_riddp
monitoring/mock_uss/wait_for_mock_uss.sh mock_uss_tracer
monitoring/mock_uss/wait_for_mock_uss.sh mock_uss_scdsc_interaction_log
10 changes: 9 additions & 1 deletion monitoring/monitorlib/clients/flight_planning/client.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from abc import ABC, abstractmethod
from typing import List, Optional, Union
from typing import Optional, Set

from monitoring.monitorlib.clients.flight_planning.test_preparation import (
TestPreparationActivityResponse,
Expand All @@ -15,6 +15,7 @@
)
from monitoring.monitorlib.fetch import QueryError
from monitoring.monitorlib.geotemporal import Volume4D
from monitoring.uss_qualifier.configurations.configuration import ParticipantID


class PlanningActivityError(QueryError):
Expand All @@ -24,6 +25,13 @@ class PlanningActivityError(QueryError):
class FlightPlannerClient(ABC):
"""Client to interact with a USS as a user performing flight planning activities and as the test director preparing for tests involving flight planning activities."""

participant_id: ParticipantID
created_flight_ids: Set[FlightID]

def __init__(self, participant_id: ParticipantID):
self.participant_id = participant_id
self.created_flight_ids: Set[FlightID] = set()

# ===== Emulation of user actions =====

@abstractmethod
Expand Down
16 changes: 15 additions & 1 deletion monitoring/monitorlib/clients/flight_planning/client_scd.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,16 @@
from monitoring.monitorlib.fetch import query_and_describe
from monitoring.monitorlib.geotemporal import Volume4D
from monitoring.monitorlib.infrastructure import UTMClientSession
from monitoring.uss_qualifier.configurations.configuration import ParticipantID


class SCDFlightPlannerClient(FlightPlannerClient):
SCD_SCOPE = scd_api_constants.Scope.Inject
_session: UTMClientSession
_plan_statuses: Dict[FlightID, FlightPlanStatus]

def __init__(self, session: UTMClientSession):
def __init__(self, session: UTMClientSession, participant_id: ParticipantID):
super(SCDFlightPlannerClient, self).__init__(participant_id=participant_id)
self._session = session
self._plan_statuses = {}

Expand Down Expand Up @@ -120,6 +122,16 @@ def _inject(
scd_api.InjectFlightResponseResult.NotSupported: old_state,
}[resp.result],
)

created_status = [
FlightPlanStatus.Planned,
FlightPlanStatus.OkToFly,
FlightPlanStatus.OffNominal,
]
if response.activity_result == PlanningActivityResult.Completed:
if response.flight_plan_status in created_status:
self.created_flight_ids.add(flight_id)

self._plan_statuses[flight_id] = response.flight_plan_status
return response

Expand Down Expand Up @@ -183,6 +195,8 @@ def try_end_flight(
)
if resp.result == scd_api.DeleteFlightResponseResult.Closed:
del self._plan_statuses[flight_id]
self.created_flight_ids.discard(flight_id)

else:
self._plan_statuses[flight_id] = response.flight_plan_status
return response
Expand Down
33 changes: 20 additions & 13 deletions monitoring/monitorlib/clients/flight_planning/client_v1.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
import json
import uuid
from typing import Optional

from implicitdict import ImplicitDict
from monitoring.monitorlib.clients.flight_planning.client import (
FlightPlannerClient,
PlanningActivityError,
)
from monitoring.monitorlib.clients.flight_planning.test_preparation import (
TestPreparationActivityResponse,
)

from monitoring.monitorlib.clients.flight_planning.flight_info import (
FlightInfo,
FlightID,
Expand All @@ -23,18 +19,21 @@
from monitoring.monitorlib.geotemporal import Volume4D
from monitoring.monitorlib.infrastructure import UTMClientSession
from monitoring.uss_qualifier.configurations.configuration import ParticipantID

from monitoring.monitorlib.clients.flight_planning.client import PlanningActivityError
from monitoring.monitorlib.clients.flight_planning.planning import (
PlanningActivityResult,
FlightPlanStatus,
)
from uas_standards.interuss.automated_testing.flight_planning.v1 import api
from uas_standards.interuss.automated_testing.flight_planning.v1.constants import Scope


class V1FlightPlannerClient(FlightPlannerClient):
_session: UTMClientSession
_participant_id: ParticipantID

def __init__(self, session: UTMClientSession, participant_id: ParticipantID):
super(V1FlightPlannerClient, self).__init__(participant_id=participant_id)
self._session = session
self._participant_id = participant_id

def _inject(
self,
Expand All @@ -61,7 +60,7 @@ def _inject(
url,
json=req,
scope=Scope.Plan,
participant_id=self._participant_id,
participant_id=self.participant_id,
query_type=QueryType.InterUSSFlightPlanningV1UpsertFlightPlan,
)
if query.status_code != 200 and query.status_code != 201:
Expand All @@ -78,6 +77,15 @@ def _inject(
f"Response to plan flight could not be parsed: {str(e)}", query
)

created_status = [
FlightPlanStatus.Planned,
FlightPlanStatus.OkToFly,
FlightPlanStatus.OffNominal,
]
if resp.planning_result == PlanningActivityResult.Completed:
if resp.flight_plan_status in created_status:
self.created_flight_ids.add(flight_plan_id)

response = PlanningActivityResponse(
flight_id=flight_plan_id,
queries=[query],
Expand Down Expand Up @@ -122,7 +130,7 @@ def try_end_flight(
op.verb,
url,
scope=Scope.Plan,
participant_id=self._participant_id,
participant_id=self.participant_id,
query_type=QueryType.InterUSSFlightPlanningV1DeleteFlightPlan,
)
if query.status_code != 200:
Expand All @@ -138,7 +146,7 @@ def try_end_flight(
raise PlanningActivityError(
f"Response to delete flight plan could not be parsed: {str(e)}", query
)

self.created_flight_ids.discard(flight_id)
response = PlanningActivityResponse(
flight_id=flight_id,
queries=[query],
Expand All @@ -154,7 +162,7 @@ def report_readiness(self) -> TestPreparationActivityResponse:
op.verb,
op.path,
scope=Scope.DirectAutomatedTest,
participant_id=self._participant_id,
participant_id=self.participant_id,
query_type=QueryType.InterUSSFlightPlanningV1GetStatus,
)
if query.status_code != 200:
Expand Down Expand Up @@ -192,7 +200,7 @@ def clear_area(self, area: Volume4D) -> TestPreparationActivityResponse:
op.path,
json=req,
scope=Scope.DirectAutomatedTest,
participant_id=self._participant_id,
participant_id=self.participant_id,
query_type=QueryType.InterUSSFlightPlanningV1ClearArea,
)
if query.status_code != 200:
Expand All @@ -208,7 +216,6 @@ def clear_area(self, area: Volume4D) -> TestPreparationActivityResponse:
raise PlanningActivityError(
f"Response to clear area could not be parsed: {str(e)}", query
)

if resp.outcome.success:
errors = None
else:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import json
from typing import Dict

from implicitdict import ImplicitDict
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from typing import Tuple, Optional, Set
from urllib.parse import urlparse
from implicitdict import ImplicitDict

from monitoring.monitorlib import infrastructure, fetch
from monitoring.monitorlib.clients.flight_planning.client import (
PlanningActivityError,
Expand Down Expand Up @@ -79,7 +78,7 @@ def to_client(
session = infrastructure.UTMClientSession(
self.scd_injection_base_url, auth_adapter, self.timeout_seconds
)
return SCDFlightPlannerClient(session)
return SCDFlightPlannerClient(session, self.participant_id)
elif "v1_base_url" in self and self.v1_base_url:
session = infrastructure.UTMClientSession(
self.v1_base_url, auth_adapter, self.timeout_seconds
Expand Down Expand Up @@ -123,7 +122,6 @@ def request_flight(
self,
request: InjectFlightRequest,
flight_id: Optional[str] = None,
additional_fields: Optional[dict] = None,
) -> Tuple[InjectFlightResponse, fetch.Query, str]:
usage_states = {
OperationalIntentState.Accepted: AirspaceUsageState.Planned,
Expand Down Expand Up @@ -171,7 +169,7 @@ def request_flight(
if not flight_id:
try:
resp = self.client.try_plan_flight(
flight_info, ExecutionStyle.IfAllowed, additional_fields
flight_info, ExecutionStyle.IfAllowed
)
except PlanningActivityError as e:
raise QueryError(str(e), e.queries)
Expand Down
25 changes: 21 additions & 4 deletions monitoring/uss_qualifier/resources/interuss/mock_uss/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
from implicitdict import ImplicitDict

from monitoring.monitorlib import fetch
from monitoring.monitorlib.clients.flight_planning.client import FlightPlannerClient
from monitoring.monitorlib.clients.flight_planning.client_v1 import (
V1FlightPlannerClient,
)
from monitoring.monitorlib.clients.mock_uss.locality import (
GetLocalityResponse,
PutLocalityRequest,
Expand All @@ -24,22 +28,28 @@
from typing import Tuple, List
from implicitdict import StringBasedDateTime


MOCK_USS_CONFIG_SCOPE = "interuss.mock_uss.configure"


class MockUSSClient(object):
"""Means to communicate with an InterUSS mock_uss instance"""

flight_planner: FlightPlannerClient

def __init__(
self,
participant_id: str,
base_url: str,
auth_adapter: AuthAdapter,
timeout_seconds: Optional[float] = None,
):
self.base_url = base_url
self.session = UTMClientSession(base_url, auth_adapter)
self.session = UTMClientSession(base_url, auth_adapter, timeout_seconds)
self.participant_id = participant_id
v1_base_url = base_url + "/flight_planning/v1"
self.flight_planner = V1FlightPlannerClient(
UTMClientSession(v1_base_url, auth_adapter, timeout_seconds), participant_id
)

def get_status(self) -> fetch.Query:
return fetch.query_and_describe(
Expand Down Expand Up @@ -77,7 +87,9 @@ def set_locality(self, locality_code: LocalityCode) -> fetch.Query:

# TODO: Add other methods to interact with the mock USS in other ways (like starting/stopping message signing data collection)

def get_interactions(self, from_time: StringBasedDateTime) -> List[Interaction]:
def get_interactions(
self, from_time: StringBasedDateTime
) -> Tuple[List[Interaction], fetch.Query]:
"""
Requesting interuss interactions from mock_uss from a given time till now
Args:
Expand Down Expand Up @@ -108,7 +120,8 @@ def get_interactions(self, from_time: StringBasedDateTime) -> List[Interaction]:
msg=f"RecordedInteractionsResponse from mock_uss response contained invalid JSON: {str(e)}",
queries=[query],
)
return response.interactions

return response.interactions, query
Comment thread
BenjaminPelletier marked this conversation as resolved.


class MockUSSSpecification(ImplicitDict):
Expand All @@ -124,6 +137,9 @@ class MockUSSSpecification(ImplicitDict):
participant_id: ParticipantID
"""Test participant responsible for this mock USS."""

timeout_seconds: Optional[float] = None
"""Number of seconds to allow for requests to this mock_uss instance. If None, use default."""


class MockUSSResource(Resource[MockUSSSpecification]):
mock_uss: MockUSSClient
Expand All @@ -137,6 +153,7 @@ def __init__(
specification.participant_id,
specification.mock_uss_base_url,
auth_adapter.adapter,
specification.timeout_seconds,
)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ No notification pushed by control_uss to tested_uss, will ensure that tested_uss
while planning a nearby flight.
If a notification is sent to tested_uss, the precondition for running this scenario will not be satisfied.

### [Test_uss attempts to plan flight 1, expect failure test step](test_steps/plan_flight_intent_expect_failed.md)
### [Tested_uss attempts to plan flight 1, expect failure test step](test_steps/plan_flight_intent_expect_failed.md)
The test driver attempts to plan the flight 1 via the tested_uss. It checks if any conflicts with flight 2
which is of equal priority and came first.

Expand Down
Loading