Skip to content

Commit

Permalink
Responses schema validation
Browse files Browse the repository at this point in the history
  • Loading branch information
p1c2u committed Sep 5, 2022
1 parent cab6dd4 commit 14ebd85
Show file tree
Hide file tree
Showing 3 changed files with 185 additions and 1 deletion.
33 changes: 33 additions & 0 deletions openapi_spec_validator/validation/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ def _iter_operation_errors(
)
self.operation_ids_registry.append(operation_id)

if "responses" in operation:
responses = operation / "responses"
yield from self._iter_responses_errors(responses)

names = []

parameters = None
Expand All @@ -161,6 +165,35 @@ def _iter_operation_errors(
)
return

def _iter_responses_errors(
self, responses: Spec
) -> Iterator[ValidationError]:
for response_code, response in responses.items():
yield from self._iter_response_errors(response_code, response)

def _iter_response_errors(
self, response_code: str, response: Spec
) -> Iterator[ValidationError]:
# openapi 2
if "schema" in response:
schema = response / "schema"
yield from self._iter_schema_errors(schema)
# openapi 3
if "content" in response:
content = response / "content"
yield from self._iter_content_errors(content)

def _iter_content_errors(self, content: Spec) -> Iterator[ValidationError]:
for mimetype, media_type in content.items():
yield from self._iter_media_type_errors(mimetype, media_type)

def _iter_media_type_errors(
self, mimetype: str, media_type: Spec
) -> Iterator[ValidationError]:
if "schema" in media_type:
schema = media_type / "schema"
yield from self._iter_schema_errors(schema)

def _get_path_param_names(self, params: Spec) -> Iterator[str]:
for param in params:
if param["in"] == "path":
Expand Down
101 changes: 101 additions & 0 deletions tests/integration/data/v2.0/missing-reference.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
swagger: "2.0"
info:
version: 1.0.0
title: Swagger Petstore
license:
name: MIT
host: petstore.swagger.io
basePath: /v1
schemes:
- http
consumes:
- application/json
produces:
- application/json
paths:
/pets:
get:
summary: List all pets
operationId: listPets
tags:
- pets
parameters:
- name: limit
in: query
description: How many items to return at one time (max 100)
required: false
type: integer
format: int32
responses:
200:
description: A paged array of pets
headers:
x-next:
type: string
description: A link to the next page of responses
schema:
$ref: 'definitions/Pets'
default:
description: unexpected error
schema:
$ref: '#/definitions/'
post:
summary: Create a pet
operationId: createPets
tags:
- pets
responses:
'201':
description: Null response
default:
description: unexpected error
schema:
$ref: '#/definitions/Error'
/pets/{petId}:
get:
summary: Info for a specific pet
operationId: showPetById
tags:
- pets
parameters:
- name: petId
in: path
required: true
description: The id of the pet to retrieve
type: string
responses:
'200':
description: Expected response to a valid request
schema:
$ref: '#/definitions/Pets'
default:
description: unexpected error
schema:
$ref: '#/definitions/Error'
definitions:
Pet:
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string
Pets:
type: array
items:
$ref: '#/definitions/Pet'
Error:
required:
- code
- message
properties:
code:
type: integer
format: int32
message:
type: string
52 changes: 51 additions & 1 deletion tests/integration/validation/test_validators.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,58 @@
import pytest
from jsonschema.exceptions import RefResolutionError

from openapi_spec_validator.validation.exceptions import OpenAPIValidationError


class TestLocalOpenAPIv2Validator:

LOCAL_SOURCE_DIRECTORY = "data/v2.0/"

def local_test_suite_file_path(self, test_file):
return f"{self.LOCAL_SOURCE_DIRECTORY}{test_file}"

@pytest.mark.parametrize(
"spec_file",
[
"petstore.yaml",
],
)
def test_valid(self, factory, validator_v2, spec_file):
spec_path = self.local_test_suite_file_path(spec_file)
spec = factory.spec_from_file(spec_path)
spec_url = factory.spec_file_url(spec_path)

return validator_v2.validate(spec, spec_url=spec_url)

@pytest.mark.parametrize(
"spec_file",
[
"empty.yaml",
],
)
def test_validation_failed(self, factory, validator_v2, spec_file):
spec_path = self.local_test_suite_file_path(spec_file)
spec = factory.spec_from_file(spec_path)
spec_url = factory.spec_file_url(spec_path)

with pytest.raises(OpenAPIValidationError):
validator_v2.validate(spec, spec_url=spec_url)

@pytest.mark.parametrize(
"spec_file",
[
"missing-reference.yaml",
],
)
def test_ref_failed(self, factory, validator_v2, spec_file):
spec_path = self.local_test_suite_file_path(spec_file)
spec = factory.spec_from_file(spec_path)
spec_url = factory.spec_file_url(spec_path)

with pytest.raises(RefResolutionError):
validator_v2.validate(spec, spec_url=spec_url)


class TestLocalOpenAPIv30Validator:

LOCAL_SOURCE_DIRECTORY = "data/v3.0/"
Expand Down Expand Up @@ -31,7 +81,7 @@ def test_valid(self, factory, validator_v30, spec_file):
"empty.yaml",
],
)
def test_falied(self, factory, validator_v30, spec_file):
def test_failed(self, factory, validator_v30, spec_file):
spec_path = self.local_test_suite_file_path(spec_file)
spec = factory.spec_from_file(spec_path)
spec_url = factory.spec_file_url(spec_path)
Expand Down

0 comments on commit 14ebd85

Please sign in to comment.