snok/drf-openapi-tester

Fail to parse a nested url route

Closed this issue · 0 comments

The Problem

I'm using the openapi-tester with a file schema.yml loader, when a test a nested router (drf-nested-routers), for example, /v1/matchs/1/maps/1/playerStats/ . I get a error of undocumented route. At the error message, we can see that the pks at the path was wrong position parsed.

The Error Message

======================================================================
ERROR: test_list_all_playerStats (game.tests.test_view_playerStats.PlayerStatsViewTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/opt/miniconda3/envs/hintclub-api/lib/python3.7/site-packages/openapi_tester/schema_tester.py", line 82, in get_key_value
    return schema[key]
KeyError: '/v1/matchs/{map_pk}/maps/{match_pk}/playerStats/'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/***********/Documents/vscode_workspace/***********/game/tests/test_view_playerStats.py", line 124, in test_list_all_playerStats
    self.assertResponse(response)
  File "/Users/***********/Documents/vscode_workspace/***********/common/tests.py", line 14, in assertResponse
    schema_tester.validate_response(response=response, **kwargs)
  File "/opt/miniconda3/envs/hintclub-api/lib/python3.7/site-packages/openapi_tester/schema_tester.py", line 349, in validate_response
    response_schema = self.get_response_schema_section(response)
  File "/opt/miniconda3/envs/hintclub-api/lib/python3.7/site-packages/openapi_tester/schema_tester.py", line 124, in get_response_schema_section
    f"\n\nUndocumented route {parameterized_path}.\n\nDocumented routes: " + "\n\t• ".join(paths_object.keys()),
  File "/opt/miniconda3/envs/hintclub-api/lib/python3.7/site-packages/openapi_tester/schema_tester.py", line 86, in get_key_value
    ) from e
openapi_tester.exceptions.UndocumentedSchemaSectionError: Error: Unsuccessfully tried to index the OpenAPI schema by `/v1/matchs/{map_pk}/maps/{match_pk}/playerStats/`. 

Undocumented route /v1/matchs/{map_pk}/maps/{match_pk}/playerStats/.

Documented routes:  /v1/matchs/{match_pk}/maps/{map_pk}/playerStats/

The Possible Solution

At line 137 is executed a right string search rfind, so the dictionary should be reversed like this reversed(list(resolved_route.kwargs.items()).

def resolve_path(self, endpoint_path: str, method: str) -> Tuple[str, ResolverMatch]:
"""
Resolves a Django path.
"""
url_object = urlparse(endpoint_path)
parsed_path = url_object.path if url_object.path.endswith("/") else url_object.path + "/"
if not parsed_path.startswith("/"):
parsed_path = "/" + parsed_path
for key, value in self.field_key_map.items():
if value != "pk" and key in parsed_path:
parsed_path = parsed_path.replace(f"{{{key}}}", value)
for path in [parsed_path, parsed_path[:-1]]:
try:
resolved_route = resolve(path)
except Resolver404:
continue
else:
for key, value in resolved_route.kwargs.items():
index = path.rfind(str(value))
path = f"{path[:index]}{{{key}}}{path[index + len(str(value)):]}"
if "{pk}" in path and api_settings.SCHEMA_COERCE_PATH_PK:
path, resolved_route = self.handle_pk_parameter(
resolved_route=resolved_route, path=path, method=method
)
return path, resolved_route
message = f"Could not resolve path `{endpoint_path}`."
close_matches = difflib.get_close_matches(endpoint_path, self.endpoints)
if close_matches:
message += "\n\nDid you mean one of these?" + "\n- ".join(close_matches)
raise ValueError(message)