Skip to content

Commit

Permalink
Swagger client parser fixes (#451)
Browse files Browse the repository at this point in the history
- Check for content type application/json before trying to parse.
- Storying the modified `http_path` in `_http_path` to avoid corrupting of path url when making requests.
  • Loading branch information
Bento007 committed Sep 27, 2019
1 parent 4d82efc commit 4d844f3
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 6 deletions.
11 changes: 8 additions & 3 deletions hca/util/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -493,15 +493,20 @@ def _parse_properties(properties, schema):
choices=parameter.get("enum"), required=parameter.get("required"))
return body_props, method_args

def _build_client_method(self, http_method, http_path, method_data):
method_name_parts = [http_method] + [p for p in http_path.split("/")[1:] if not p.startswith("{")]
@staticmethod
def _build_method_name(http_method, http_path):
method_name = http_path.replace('/.well-known', '').replace('-', '_')
method_name_parts = [http_method] + [p for p in method_name.split("/")[1:] if not p.startswith("{")]
method_name = "_".join(method_name_parts)
if method_name.endswith("s") and (http_method.upper() in {"POST", "PUT"} or http_path.endswith("/{uuid}")):
method_name = method_name[:-1]
return method_name

def _build_client_method(self, http_method, http_path, method_data):
method_name = self._build_method_name(http_method, http_path)
parameters = {p["name"]: p for p in method_data.get("parameters", [])}
body_json_schema = {"properties": {}}
if "requestBody" in method_data:
if "requestBody" in method_data and "application/json" in method_data["requestBody"]["content"]:
body_json_schema = method_data["requestBody"]["content"]["application/json"]["schema"]
else:
for p in parameters:
Expand Down
60 changes: 57 additions & 3 deletions test/integration/util/test_swagger_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ class TestSwaggerClient(unittest.TestCase):
"head_with_optional_param",
"put_with_invalid_enum_param",
"get_with_allOf_in_body_param",
"test_get_with_allOf_multiple_in_body_param"
"get_with_allOf_multiple_in_body_param",
"get_with_something_in_path",
"get_with_header_parameter",
"get_with_request_body_application_json"
]

@classmethod
Expand Down Expand Up @@ -91,8 +94,9 @@ def setUp(self):

def test_client_methods_exist(self):
for method_name in self.generated_method_names:
self.assertTrue(hasattr(self.client.__class__, method_name) and
callable(getattr(self.client.__class__, method_name)))
with self.subTest(method_name):
self.assertTrue(hasattr(self.client.__class__, method_name) and
callable(getattr(self.client.__class__, method_name)))

def test_get_with_path_query_params(self):
http_method = "get"
Expand Down Expand Up @@ -401,6 +405,56 @@ def test_put_with_invalid_enum_param(self):
'--query-param', query_param_invalid])
self.assertEqual(e.exception.code, 2)

def test_get_with_something_in_path(self):
self._test("/with/something/.well-known/in/path", "get")

def test_get_with_header_parameter(self):
self._test("/with/header/parameter",
"get",
headers={"some_header": "foo"},
command_args=["--some-header", "foo"])

def test_get_with_request_body_application_json(self):
self._test("/with/request_body/not_application/json",
"get",
json={"foo": "bar"},
command_args=["--foo", "bar"])

def _test(self,
path: str,
http_method: str,
json: dict = None,
stream: bool = False,
params: dict = None,
headers: dict = None,
timeout=mock.ANY,
command_args: list = None):

params = params or {}
headers = headers or {}
command_args = command_args or []

command = self.get_command(http_method, path)
url = self.url_base + path

with mock.patch('requests.Session.request') as mock_request, \
mock.patch('hca.util._ClientMethodFactory._consume_response') as mock_consume_response:
mock_request.return_value = self.dummy_response

args = self.parser.parse_args([command] + command_args)
args.entry_point(args)
mock_consume_response.assert_called_once_with(mock.ANY)
mock_request.assert_called_once_with(http_method,
url,
json=json,
stream=stream,
params=params,
headers=headers,
timeout=timeout)

def get_command(self, http_method, path):
return self.client._build_method_name(http_method, path).replace('_', '-')


if __name__ == "__main__":
unittest.main()
81 changes: 81 additions & 0 deletions test/res/test_swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,87 @@
}
}
}
},
"/with/something/.well-known/in/path": {
"get": {
"description": "GET method with /.well-known in path.",
"summary": "",
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/with/header/parameter": {
"get": {
"description": "GET a method a header parameter.",
"summary": "",
"parameters": [
{
"name": "some_header",
"description": "A required header parameter.",
"in": "header",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/with/request_body/application/json": {
"get": {
"description": "GET a method a header parameter.",
"summary": "",
"requestBody":{
"content": {
"application/json":{
"schema": {
"type": "object",
"properties": {
"foo": {
"type": "string"
}
}
}
}
}
},
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/with/request_body/not_application/json": {
"get": {
"description": "GET a method a header parameter.",
"summary": "",
"requestBody":{
"content": {
"application/json":{
"schema": {
"type": "object",
"properties": {
"foo": {
"type": "string"
}
}
}
}
}
},
"responses": {
"200": {
"description": "OK"
}
}
}
}
}
}

0 comments on commit 4d844f3

Please sign in to comment.