-
Notifications
You must be signed in to change notification settings - Fork 20
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] Modify sharing behavior in mock_uss on injection #269
[mock_uss] Modify sharing behavior in mock_uss on injection #269
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have to get to bed; more comments tomorrow, but here's what I have so far.
class MockUssFlightBehavior(ImplicitDict): | ||
modify_sharing_methods: List[str] | ||
modify_fields: dict |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are very important to document as we're essentially establishing a new interface for mock_uss. Also, remember that flight planning is used for many testing activities, not just F3548-21, so we should be more specific about what sharing and field modifications we're making.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added documentation.
@@ -92,7 +97,7 @@ def plan_flight_intent( | |||
scenario: TestScenarioType, | |||
test_step: str, | |||
flight_planner: FlightPlanner, | |||
flight_intent: InjectFlightRequest, | |||
flight_intent: MockUssInjectFlightRequest, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are test steps that are performed mostly with USSs that are not mock_uss instances so callers of this function often will not have an augmented request. The type of this variable should remain InjectFlightRequest, and a MockUssInjectFlightRequest can still be provided for this variable since it is an InjectFlightRequest.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed.
import time | ||
from datetime import datetime |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These imports appear unnecessary
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed.
@@ -45,6 +49,7 @@ def _inject( | |||
flight_id: FlightID, | |||
flight_info: FlightInfo, | |||
execution_style: ExecutionStyle, | |||
mod_flight_behavior: Optional[MockUssFlightBehavior] = None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This client is a particular implementation of the generic client -- we shouldn't change method signatures as that will prevent the use of other implementations of the generic client. Instead, it seems reasonable to add an additional_fields: Optional[dict] = None
argument to this function in FlightPlannerClient (and therefore here as well) whose fields get added to the request body just before it's dispatched to the remote server. Doing it this way will allow easy adaptation for other implementations of FlightPlannerClient of which there will soon be one more (for flight_planner interface).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added additional_fields.
Thanks for the comments. Sorry, didn't mean to disturb you. |
Oh, no, not at all -- I only review when I'm willing to work. Please feel free to push/comment/update/message/etc at any time regardless of time of day. I just usually like providing a complete set of comments, so wanted to explain why this set was not complete (seemed useful to get these out sooner rather than waiting for a complete set) |
@BenjaminPelletier I have made changes using additional_fields. Could you please check. Thanks. |
I can help with the merge on this one -- I'll make a PR to your branch |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR both merges main and addresses these comments
@@ -16,6 +20,7 @@ class FlightRecord(ImplicitDict): | |||
op_intent_injection: scd_injection_api.OperationalIntentTestInjection | |||
flight_authorisation: scd_injection_api.FlightAuthorisationData | |||
op_intent_reference: OperationalIntentReference | |||
mod_op_sharing_behavior: Optional[MockUssFlightBehavior] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need to retain the capability to omit this field in an output, so we should default this field to None so we can be sure it's always present.
except ValueError as e: | ||
msg = "Create flight {} unable to parse JSON: {}".format(flight_id, e) | ||
return msg, 400 | ||
json, code = inject_flight(flight_id, req_body) | ||
return flask.jsonify(json), code | ||
|
||
|
||
def op_to_share( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is nearly identical to op_intent_from_flightrecord; let's delete this one and just use op_intent_from_flightrecord (we can compute the FlightRecord just a little earlier when this function is currently being used).
response = GetOperationalIntentDetailsResponse( | ||
operational_intent=op_intent_from_flightrecord(flight), | ||
) | ||
response = {"operational_intent": op_intent_from_flightrecord(flight)} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no reason to drop typing here -- let's keep this how it was
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I had tried that. But, that lead to validation of the operational_intent as per GetOperationalIntentDetailsResponse. Whereas, we want to have invalid data in our test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Types are validated upon parsing, but not upon construction -- an invalid value can be provided upon construction.
op_intent = OperationalIntent(reference=ref, details=details) | ||
method = "GET" | ||
if "mod_op_sharing_behavior" in flight: | ||
mod_op_sharing_behavior = ImplicitDict.parse( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no need to parse here; the FlightRecord is already typed such that flight.mod_op_sharing_behavior is a MockUssFlightBehavior
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, thanks. I think I hadn't defaulted to None, as you suggested in an earlier comment, that's why my tests had failed and I put this check.
if method not in mod_op_sharing_behavior.modify_sharing_methods: | ||
return OperationalIntent(reference=ref, details=details) | ||
if mod_op_sharing_behavior.modify_fields is not None: | ||
if "operational_intent_reference" in mod_op_sharing_behavior.modify_fields: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of looking for these fields specifically by name, let's just have modify_fields apply to the entire OperationalIntent -- that's simpler and less brittle.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that leads to validation of the contents for OperationalIntent. We want to have invalid data there. I ll check it with your PR as well. Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why would having modify_fields apply directly to OperationalIntent cause validation versus applying to the two member separately?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me pull and check, as earlier I tried it, and while running my tests, I had come across validation errors. But, let me pull your PR and check. Could have been some issue with my code. Will check and let you know if I see any issues. Thanks
@@ -0,0 +1,30 @@ | |||
from implicitdict import ImplicitDict |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file relates to client behavior of mock_uss; let's put it in monitorlib/clients/mock_uss
return self._inject(str(uuid.uuid4()), flight_info, execution_style) | ||
return self._inject( | ||
str(uuid.uuid4()), flight_info, execution_style, additional_fields | ||
) | ||
|
||
def try_update_flight( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems surprising that we would be able to add fields when planning a flight, but not when updating -- let's add additional_fields here.
return op_intent | ||
|
||
|
||
def mock_uss_flight_behavior_in_req( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Functions that are not document and not intended to be used outside the current file should be prefixed with an underscore
|
||
def mock_uss_flight_behavior_in_req( | ||
req_body: InjectFlightRequest, | ||
) -> MockUssFlightBehavior: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because this function can also return None, the type annotation should be Optional[MockUssFlightBehavior]
if datetime.utcnow() > deadline: | ||
logger.debug(f"Now {datetime.utcnow} Deadline {deadline} ") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
utcnow
is a function; it seems like you want to invoke it here (and below). Also, there is a log message immediately below; let's add the content there instead of making a new message.
…ion_to_mock_uss Modified behavior injection to mock uss
* Modify sharing behavior in mock_uss on injection * Added additional_fields to InjectFlightRequest * Fix format * Added documentation for MockUssFlightBehavior * Fix format * Implement PR suggestions --------- Co-authored-by: Benjamin Pelletier <[email protected]> 0b6beea
This PR adds the ability to modify sharing behavior of mock_uss on injection, as would be needed by negative tests for data validation of SUT.