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] Adding the interactions and invalid op checks steps #376

Merged
Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
e2e55c8
Adding the interactions and invalid op checks steps
punamverma Nov 29, 2023
84c59cc
Added mock_uss to prep_planners doc
punamverma Nov 29, 2023
83e1e08
fix format
punamverma Nov 29, 2023
2ddb964
Fix doc
punamverma Nov 29, 2023
1a6622f
Adding missing code
punamverma Nov 29, 2023
ce4488e
Adding missing mock_uss resource to PrepareFlightPlanners
punamverma Nov 30, 2023
2aa5f05
Merge branch 'main' into interactions_and_invalid_op_checks
punamverma Nov 30, 2023
a44b49e
Fix per PR comments
punamverma Dec 1, 2023
907cbfe
Merge branch 'main' into interactions_and_invalid_op_checks
punamverma Dec 1, 2023
c2e8bf6
Merge branch 'main' into interactions_and_invalid_op_checks
punamverma Dec 1, 2023
9687ac2
Removing post check for a particular url
punamverma Dec 1, 2023
83a40d8
Fixing check details
punamverma Dec 1, 2023
3a8bdc4
Adding 5 s back, removing url check no post interactions
punamverma Dec 1, 2023
3df884c
Merge branch 'main' into interactions_and_invalid_op_checks
punamverma Dec 2, 2023
42cceda
Wait only for checking POST notifications
punamverma Dec 2, 2023
8fdcb69
Fix per PR comments
punamverma Dec 4, 2023
8797056
Fix per PR review
punamverma Dec 4, 2023
9abdf23
Fix format
punamverma Dec 4, 2023
fbae1b1
Refactoring code, removed wait time for other than post interactions …
punamverma Dec 6, 2023
40bc79c
querying for interactions optimistically
punamverma Dec 7, 2023
22931da
Merge branch 'main' into interactions_and_invalid_op_checks
punamverma Dec 7, 2023
d282151
Fix passing ref id
punamverma Dec 7, 2023
f892e01
Merge branch 'main' into interactions_and_invalid_op_checks
punamverma Dec 7, 2023
2c7dba1
Update monitoring/uss_qualifier/scenarios/astm/utm/data_exchange_vali…
punamverma Dec 8, 2023
b330dff
Fix per review comments
punamverma Dec 8, 2023
1fcbafa
Fix per review
punamverma Dec 8, 2023
fca841f
Adding missing code for Query
punamverma Dec 8, 2023
688dd4c
Fixed documentation for wait time as per PR comments
punamverma Dec 11, 2023
e9b0566
Merge branch 'main' into interactions_and_invalid_op_checks
punamverma Dec 11, 2023
1405f0e
Adding subscription check with GET request check
punamverma Dec 12, 2023
694ff22
Fixed per PR comments
punamverma Dec 13, 2023
4bcb865
Merge branch 'main' into interactions_and_invalid_op_checks
punamverma Dec 13, 2023
1f588ec
Fix per review
punamverma Dec 14, 2023
75d57b1
Merge branch 'main' into interactions_and_invalid_op_checks
punamverma Dec 14, 2023
62f1155
Removing args from comments
punamverma Dec 14, 2023
844fb4b
Conditional call of GET request based on notification
punamverma Dec 14, 2023
7999f53
Refining check message
punamverma Dec 14, 2023
aa89491
Removing else condition, and renaming test step and check as discussed
punamverma Dec 15, 2023
ee8d6cb
Merge branch 'main' into interactions_and_invalid_op_checks
punamverma Dec 15, 2023
2e4d228
Changing method name per review
punamverma Dec 16, 2023
d09dab5
fixing the condition for GET request check
punamverma Dec 16, 2023
2ce1399
Want to trigger CI run that failed on netrid test
punamverma Dec 16, 2023
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
9 changes: 9 additions & 0 deletions monitoring/monitorlib/clients/flight_planning/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,12 @@ def clear_area(self, area: Volume4D) -> TestPreparationActivityResponse:
* PlanningActivityError
"""
raise NotImplementedError()

@abstractmethod
def get_base_url(self) -> str:
"""
Get the base_url associated with this FlightPlannerClient
Returns:

"""
raise NotImplementedError
3 changes: 3 additions & 0 deletions monitoring/monitorlib/clients/flight_planning/client_scd.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,3 +260,6 @@ def clear_area(self, area: Volume4D) -> TestPreparationActivityResponse:
errors = [f"[{resp.outcome.timestamp}]: {resp.outcome.message}"]

return TestPreparationActivityResponse(errors=errors, queries=[query])

def get_base_url(self):
return self._session.get_prefix_url()
3 changes: 3 additions & 0 deletions monitoring/monitorlib/clients/flight_planning/client_v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,6 @@ def clear_area(self, area: Volume4D) -> TestPreparationActivityResponse:
errors = [resp.outcome.message]

return TestPreparationActivityResponse(errors=errors, queries=[query])

def get_base_url(self):
return self._session.get_prefix_url()
10 changes: 10 additions & 0 deletions monitoring/monitorlib/fetch/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import os
import traceback
import uuid
import jwt
from typing import Dict, Optional, List, Union

from enum import Enum
Expand Down Expand Up @@ -290,6 +291,15 @@ def error_message(self) -> Optional[str]:
else None
)

def get_client_sub(self):
headers = self.request.headers
if "Authorization" in headers:
token = headers.get("Authorization").split(" ")[1]
payload = jwt.decode(
token, algorithms="RS256", options={"verify_signature": False}
)
return payload["sub"]


class QueryError(RuntimeError):
"""Error encountered when interacting with a server in the UTM ecosystem."""
Expand Down
38 changes: 29 additions & 9 deletions monitoring/uss_qualifier/resources/astm/f3548/v21/dss.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
from __future__ import annotations

import uuid
from typing import Tuple, List, Optional
from urllib.parse import urlparse
from typing import Tuple, List, Dict, Optional

from urllib.parse import urlparse
from implicitdict import ImplicitDict

from monitoring.monitorlib import infrastructure, fetch
Expand Down Expand Up @@ -127,6 +126,29 @@ def get_full_op_intent(
op_intent_ref: OperationalIntentReference,
uss_participant_id: Optional[str] = None,
) -> Tuple[OperationalIntent, fetch.Query]:
result, query = self.get_full_op_intent_without_validation(
op_intent_ref,
uss_participant_id,
)
if query.status_code != 200:
result = None
else:
result = ImplicitDict.parse(
query.response.json, GetOperationalIntentDetailsResponse
).operational_intent
return result, query

def get_full_op_intent_without_validation(
BenjaminPelletier marked this conversation as resolved.
Show resolved Hide resolved
self,
op_intent_ref: OperationalIntentReference,
uss_participant_id: Optional[str] = None,
) -> Tuple[Dict, fetch.Query]:
"""
GET OperationalIntent without validating, as invalid data expected for negative tests

Returns:
returns the response json when query is successful
"""
op = OPERATIONS[OperationID.GetOperationalIntentDetails]
query = fetch.query_and_describe(
BenjaminPelletier marked this conversation as resolved.
Show resolved Hide resolved
self.client,
Expand All @@ -136,12 +158,10 @@ def get_full_op_intent(
uss_participant_id,
scope=SCOPE_SC,
)
if query.status_code != 200:
result = None
else:
result = ImplicitDict.parse(
query.response.json, GetOperationalIntentDetailsResponse
).operational_intent
result = None
if query.status_code == 200:
result = query.response.json

return result, query

def put_op_intent(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,14 @@ Flight 2 should be successfully planned by the control USS.
### [Validate flight 2 sharing test step](../validate_shared_operational_intent.md)
Validate that flight 2 is planned

### Precondition - check tested_uss has no subscription in flight 2 area test step
### Check for notification to tested_uss due to subscription in flight 2 area test step
In order to run this test scenario, we need tested_uss to trigger GET operational intent request to mock_uss.
So we need to make sure that there is no subscription of tested_uss, that would trigger notification of flight 2 to tested_uss.
No notification pushed by control_uss to tested_uss, will ensure that tested_uss will make a GET request to control_uss for flight 2 details,
while planning a nearby flight.
If a notification is sent to tested_uss, the precondition for running this scenario will not be satisfied.
But, if there is a subscription by tested_uss, that would trigger notification of flight 2 to tested_uss.
Some USSes will not make a GET request to control_uss for flight 2 details, while planning a nearby flight,
if they got a notification for flight2. Hence, if a USS didn't make a GET request, we will only fail it if didn't get
a notification, or else, a precondition for the test will not be met. Some USSes might make a GET request despite getting
a notification, but as it would not be clear whether invalid information through notification or GET request was used for planning,
the test will be not be continued.

### [Tested_uss plans flight 1 test step](../../../flight_planning/plan_flight_intent.md)
The test driver attempts to plan flight 1 via the tested USS. It checks if any conflicts with flight 2
Expand All @@ -49,7 +51,7 @@ which is of equal priority and came first.
### [Validate flight 1 sharing test step](../validate_shared_operational_intent.md)
Validate flight 1 is planned.

### [Validate flight2 GET interaction test step](test_steps/validate_get_operational_intent.md)
### [Validate flight2 GET interaction, if no notification test step](test_steps/validate_get_operational_intent.md)
Validate that tested_uss makes a GET request for obtaining details of flight 2 from control_uss.
In a previous step (Precondition - check tested_uss has no subscription in flight 2 area), we ensured that no notification of flight 2 was sent to tested_uss.
Hence, tested_uss will need to make a GET request to obtain flight 2 details.
Expand All @@ -71,12 +73,14 @@ The control_uss, which is mock_uss is instructed to share invalid data with othe
### [Validate flight 2 shared operational intent with invalid data test step](test_steps/validate_sharing_operational_intent_but_with_invalid_interuss_data.md)
Validate that flight 2 is shared with invalid data as a modified behavior is injected by uss_qualifier for a negative test.

### Precondition - check tested_uss has no subscription in flight 2 area test step
### Check for notification to tested_uss due to subscription in flight 2 area test step
In order to run this test scenario, we need tested_uss to trigger GET operational intent request to mock_uss.
So we need to make sure that there is no subscription of tested_uss, that would trigger notification of flight 2 to tested_uss.
No notification pushed by control_uss to tested_uss, will ensure that tested_uss will make a GET request to control_uss for flight 2 details,
while planning a nearby flight.
If a notification is sent to tested_uss, the precondition for running this scenario will not be satisfied.
But, if there is a subscription by tested_uss, that would trigger notification of flight 2 to tested_uss.
Some USSes will not make a GET request to control_uss for flight 2 details, while planning a nearby flight,
if they got a notification for flight2. Hence, if a USS didn't make a GET request, we will only fail it if didn't get
a notification, or else, a precondition for the test will not be met. Some USSes might make a GET request despite getting
a notification, but as it would not be clear whether invalid information through notification or GET request was used for planning,
the test will be not be continued.

### [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
Expand All @@ -85,7 +89,7 @@ which is of equal priority and came first.
### [Validate flight 1 not shared by tested_uss test step](../validate_not_shared_operational_intent.md)
Validate flight 1 is not shared with DSS, as plan failed.

### [Validate flight 2 GET interaction test step](test_steps/validate_get_operational_intent.md)
### [Validate flight2 GET interaction, if no notification test step](test_steps/validate_get_operational_intent.md)
Validate that tested_uss makes a GET request for obtaining details of flight 2 from control_uss.
In a previous step (Precondition - check tested_uss has no subscription in flight 2 area), we ensured that no notification of flight 2 was sent to tested_uss.
Hence, tested_uss will need to make a GET request to obtain flight 2 details.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from typing import Optional, Dict

from monitoring.monitorlib.clients.flight_planning.flight_info_template import (
FlightInfoTemplate,
)
from monitoring.monitorlib.temporal import TimeDuringTest, Time
from monitoring.monitorlib.temporal import TimeDuringTest
import arrow
from implicitdict import StringBasedDateTime

from monitoring.monitorlib.temporal import Time
from monitoring.monitorlib.clients.flight_planning.client import FlightPlannerClient
from monitoring.uss_qualifier.resources.astm.f3548.v21 import DSSInstanceResource
from monitoring.uss_qualifier.resources.astm.f3548.v21.dss import DSSInstance
Expand All @@ -24,8 +25,16 @@
from monitoring.uss_qualifier.scenarios.astm.utm.data_exchange_validation.test_steps.invalid_op_test_steps import (
plan_flight_intent_expect_failed,
)
from monitoring.uss_qualifier.scenarios.astm.utm.test_steps import OpIntentValidator

from monitoring.uss_qualifier.scenarios.astm.utm.test_steps import (
OpIntentValidator,
OpIntentValidationFailureType,
)
from monitoring.uss_qualifier.scenarios.astm.utm.data_exchange_validation.test_steps.expected_interactions_test_steps import (
expect_interuss_post_interactions,
expect_get_requests_to_mock_uss,
expect_no_interuss_post_interactions,
check_any_notification,
)
from monitoring.monitorlib.clients.mock_uss.mock_uss_scd_injection_api import (
MockUssFlightBehavior,
)
Expand Down Expand Up @@ -138,26 +147,32 @@ def _tested_uss_plans_deconflicted_flight_near_existing_flight(
):
times[TimeDuringTest.TimeOfEvaluation] = Time(arrow.utcnow().datetime)
flight_2 = self.flight_2.resolve(times)

with OpIntentValidator(
self,
self.control_uss_client,
self.dss,
"Validate flight 2 sharing",
self._intents_extent,
) as validator:
planning_time = Time(arrow.utcnow().datetime)
_, self.flight_2_id = plan_flight(
self,
"Control_uss plans flight 2",
self.control_uss_client,
flight_2,
)

validator.expect_shared(flight_2)
flight_2_oi_ref = validator.expect_shared(flight_2)

self.begin_test_step(
"Precondition - check tested_uss has no subscription in flight 2 area"
"Check for notification to tested_uss due to subscription in flight 2 area"
)
tested_uss_notified = check_any_notification(
self,
self.control_uss,
planning_time,
)
# ToDo - Add the test step details
self.end_test_step()

times[TimeDuringTest.TimeOfEvaluation] = Time(arrow.utcnow().datetime)
Expand All @@ -170,24 +185,37 @@ def _tested_uss_plans_deconflicted_flight_near_existing_flight(
"Validate flight 1 sharing",
self._intents_extent,
) as validator:
_, self.flight_1_id = plan_flight(
planning_time = Time(arrow.utcnow().datetime)
plan_res, self.flight_1_id = plan_flight(
self,
"Tested_uss plans flight 1",
self.tested_uss_client,
flight_1,
)

validator.expect_shared(
flight_1,
)

self.begin_test_step("Validate flight2 GET interaction")
# ToDo - Add the test step details
self.end_test_step()
if tested_uss_notified:
Copy link
Member

Choose a reason for hiding this comment

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

A useful tool to check the correctness/behavior of uss_qualifier functionality is to inspect the various artifacts produced from a test run. The CI runs most of the configurations in configurations/dev with output going to uss_qualifier/output -- this output is available as a downloadable artifact when the CI is run on GitHub, or it will be on your local machine if run locally. Here is a portion of the tested requirements artifact for the f3548_self_contained test configuration:

Screenshot 2023-12-15 at 3 55 05 PM

It seems like we would want to make sure that check happened.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks. Fixed the condition.
But, I see that there are some subscriptions that are not getting cleaned up, and causing notifications to happen.

expect_get_requests_to_mock_uss(
self,
self.control_uss,
planning_time,
self.control_uss.base_url,
flight_2_oi_ref.id,
self.tested_uss_client.participant_id,
"Validate flight2 GET interaction, if no notification",
)

self.begin_test_step("Validate flight1 Notification sent to Control_uss")
# ToDo - Add the test step details
self.end_test_step()
expect_interuss_post_interactions(
self,
self.control_uss,
planning_time,
self.control_uss.base_url,
self.tested_uss_client.participant_id,
plan_res.queries[0].request.timestamp,
"Validate flight1 Notification sent to Control_uss",
)

delete_flight(
self, "Delete tested_uss flight", self.tested_uss_client, self.flight_1_id
Expand All @@ -202,58 +230,85 @@ def _tested_uss_unable_to_plan_flight_near_invalid_shared_existing_flight(
times[TimeDuringTest.TimeOfEvaluation] = Time(arrow.utcnow().datetime)
flight_info = self.flight_2.resolve(times)

modify_field1 = "state"
modify_field2 = "priority"
# Modifying the request with invalid data
behavior = MockUssFlightBehavior(
modify_sharing_methods=["GET", "POST"],
modify_fields={
"reference": {"state": "Flying"},
"details": {"priority": -1},
"reference": {modify_field1: "Flying"},
"details": {modify_field2: 1.2},
},
)

additional_fields = {"behavior": behavior}

_, self.flight_2_id = plan_flight(
with OpIntentValidator(
self,
"Control_uss plans flight 2, sharing invalid operational intent data",
self.control_uss_client,
flight_info,
additional_fields,
)
self.dss,
"Validate flight 2 shared operational intent with invalid data",
self._intents_extent,
) as validator:
planning_time = Time(arrow.utcnow().datetime)
_, self.flight_2_id = plan_flight(
self,
"Control_uss plans flight 2, sharing invalid operational intent data",
self.control_uss_client,
flight_info,
additional_fields,
)
flight_2_oi_ref = validator.expect_shared_with_invalid_data(
flight_info,
validation_failure_type=OpIntentValidationFailureType.DataFormat,
invalid_fields=[modify_field1, modify_field2],
)

self.begin_test_step(
"Validate flight 2 shared operational intent with invalid data"
"Check for notification to tested_uss due to subscription in flight 2 area"
)
# ToDo - Add the test step details
self.end_test_step()

self.begin_test_step(
"Precondition - check tested_uss has no subscription in flight 2 area"
tested_uss_notified = check_any_notification(
self,
self.control_uss,
planning_time,
)
# ToDo - Add the test step details
self.end_test_step()

times[TimeDuringTest.TimeOfEvaluation] = Time(arrow.utcnow().datetime)
flight_1 = self.flight_1.resolve(times)

_, self.flight_1_id = plan_flight_intent_expect_failed(
with OpIntentValidator(
self,
"Tested_uss attempts to plan flight 1, expect failure",
self.tested_uss_client,
flight_1,
)

self.begin_test_step("Validate flight 1 not shared by tested_uss")
# ToDo - Add the test step details
self.end_test_step()
self.dss,
"Validate flight 1 not shared by tested_uss",
self._intents_extent,
) as validator:
planning_time = Time(arrow.utcnow().datetime)
_, self.flight_1_id = plan_flight_intent_expect_failed(
self,
"Tested_uss attempts to plan flight 1, expect failure",
self.tested_uss_client,
flight_1,
)
validator.expect_not_shared()

self.begin_test_step("Validate flight 2 GET interaction")
# ToDo - Add the test step details
self.end_test_step()
if tested_uss_notified:
expect_get_requests_to_mock_uss(
self,
self.control_uss,
planning_time,
self.control_uss.base_url,
flight_2_oi_ref.id,
self.tested_uss_client.participant_id,
"Validate flight2 GET interaction, if no notification",
)

self.begin_test_step("Validate flight 1 Notification not sent to Control_uss")
# ToDo - Add the test step details
self.end_test_step()
expect_no_interuss_post_interactions(
self,
self.control_uss,
planning_time,
self.tested_uss_client.participant_id,
"Validate flight 1 Notification not sent to Control_uss",
)

delete_flight(
self, "Delete Control_uss flight", self.control_uss_client, self.flight_2_id
Expand Down
Loading
Loading