mirror of
https://github.com/correl/openapi-core.git
synced 2024-11-22 19:18:36 +00:00
Merge pull request #10 from p1c2u/feature/responses-validation
Responses validation
This commit is contained in:
commit
fda4615057
12 changed files with 477 additions and 29 deletions
25
README.rst
25
README.rst
|
@ -103,6 +103,31 @@ or specify request wrapper class for shortcuts
|
|||
validated_body = validate_body(
|
||||
spec, request, wrapper_class=FlaskOpenAPIRequest)
|
||||
|
||||
You can also validate responses
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from openapi_core.validators import ResponseValidator
|
||||
|
||||
validator = ResponseValidator(spec)
|
||||
result = validator.validate(request, response)
|
||||
|
||||
# raise errors if response invalid
|
||||
result.raise_for_errors()
|
||||
|
||||
# get list of errors
|
||||
errors = result.errors
|
||||
|
||||
and unmarshal response data from validation result
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# get headers
|
||||
validated_headers = result.headers
|
||||
|
||||
# get data
|
||||
validated_data = result.data
|
||||
|
||||
Related projects
|
||||
================
|
||||
* `openapi-spec-validator <https://github.com/p1c2u/openapi-spec-validator>`__
|
||||
|
|
|
@ -69,5 +69,9 @@ class InvalidContentType(OpenAPIBodyError):
|
|||
pass
|
||||
|
||||
|
||||
class InvalidResponse(OpenAPIMappingError):
|
||||
pass
|
||||
|
||||
|
||||
class InvalidValue(OpenAPIMappingError):
|
||||
pass
|
||||
|
|
|
@ -5,8 +5,10 @@ from functools import lru_cache
|
|||
|
||||
from six import iteritems
|
||||
|
||||
from openapi_core.exceptions import InvalidResponse
|
||||
from openapi_core.parameters import ParametersGenerator
|
||||
from openapi_core.request_bodies import RequestBodyFactory
|
||||
from openapi_core.responses import ResponsesGenerator
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
@ -15,10 +17,11 @@ class Operation(object):
|
|||
"""Represents an OpenAPI Operation."""
|
||||
|
||||
def __init__(
|
||||
self, http_method, path_name, parameters, request_body=None,
|
||||
deprecated=False, operation_id=None):
|
||||
self, http_method, path_name, responses, parameters,
|
||||
request_body=None, deprecated=False, operation_id=None):
|
||||
self.http_method = http_method
|
||||
self.path_name = path_name
|
||||
self.responses = dict(responses)
|
||||
self.parameters = dict(parameters)
|
||||
self.request_body = request_body
|
||||
self.deprecated = deprecated
|
||||
|
@ -27,6 +30,21 @@ class Operation(object):
|
|||
def __getitem__(self, name):
|
||||
return self.parameters[name]
|
||||
|
||||
def get_response(self, http_status='default'):
|
||||
try:
|
||||
return self.responses[http_status]
|
||||
except KeyError:
|
||||
# try range
|
||||
http_status_range = '{0}XX'.format(http_status[0])
|
||||
if http_status_range in self.responses:
|
||||
return self.responses[http_status_range]
|
||||
|
||||
if 'default' not in self.responses:
|
||||
raise InvalidResponse(
|
||||
"Unknown response http status {0}".format(http_status))
|
||||
|
||||
return self.responses['default']
|
||||
|
||||
|
||||
class OperationsGenerator(object):
|
||||
"""Represents an OpenAPI Operation in a service."""
|
||||
|
@ -42,9 +60,12 @@ class OperationsGenerator(object):
|
|||
continue
|
||||
|
||||
operation_deref = self.dereferencer.dereference(operation)
|
||||
responses_spec = operation_deref['responses']
|
||||
responses = self.responses_generator.generate(responses_spec)
|
||||
deprecated = operation_deref.get('deprecated', False)
|
||||
parameters_list = operation_deref.get('parameters', [])
|
||||
parameters = self.parameters_generator.generate(parameters_list)
|
||||
parameters = self.parameters_generator.generate_from_list(
|
||||
parameters_list)
|
||||
|
||||
request_body = None
|
||||
if 'requestBody' in operation_deref:
|
||||
|
@ -55,11 +76,16 @@ class OperationsGenerator(object):
|
|||
yield (
|
||||
http_method,
|
||||
Operation(
|
||||
http_method, path_name, list(parameters),
|
||||
http_method, path_name, responses, list(parameters),
|
||||
request_body=request_body, deprecated=deprecated,
|
||||
),
|
||||
)
|
||||
|
||||
@property
|
||||
@lru_cache()
|
||||
def responses_generator(self):
|
||||
return ResponsesGenerator(self.dereferencer, self.schemas_registry)
|
||||
|
||||
@property
|
||||
@lru_cache()
|
||||
def parameters_generator(self):
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
import logging
|
||||
import warnings
|
||||
|
||||
from six import iteritems
|
||||
|
||||
from openapi_core.exceptions import (
|
||||
EmptyValue, InvalidValueType, InvalidParameterValue,
|
||||
)
|
||||
|
@ -54,10 +56,12 @@ class ParametersGenerator(object):
|
|||
self.dereferencer = dereferencer
|
||||
self.schemas_registry = schemas_registry
|
||||
|
||||
def generate(self, paramters):
|
||||
for parameter in paramters:
|
||||
def generate(self, parameters):
|
||||
for parameter_name, parameter in iteritems(parameters):
|
||||
parameter_deref = self.dereferencer.dereference(parameter)
|
||||
|
||||
parameter_in = parameter_deref.get('in', 'header')
|
||||
|
||||
allow_empty_value = parameter_deref.get('allowEmptyValue')
|
||||
required = parameter_deref.get('required', False)
|
||||
|
||||
|
@ -67,9 +71,33 @@ class ParametersGenerator(object):
|
|||
schema, _ = self.schemas_registry.get_or_create(schema_spec)
|
||||
|
||||
yield (
|
||||
parameter_deref['name'],
|
||||
parameter_name,
|
||||
Parameter(
|
||||
parameter_deref['name'], parameter_deref['in'],
|
||||
parameter_name, parameter_in,
|
||||
schema=schema, required=required,
|
||||
allow_empty_value=allow_empty_value,
|
||||
),
|
||||
)
|
||||
|
||||
def generate_from_list(self, parameters_list):
|
||||
for parameter in parameters_list:
|
||||
parameter_deref = self.dereferencer.dereference(parameter)
|
||||
|
||||
parameter_name = parameter_deref['name']
|
||||
parameter_in = parameter_deref.get('in', 'header')
|
||||
|
||||
allow_empty_value = parameter_deref.get('allowEmptyValue')
|
||||
required = parameter_deref.get('required', False)
|
||||
|
||||
schema_spec = parameter_deref.get('schema', None)
|
||||
schema = None
|
||||
if schema_spec:
|
||||
schema, _ = self.schemas_registry.get_or_create(schema_spec)
|
||||
|
||||
yield (
|
||||
parameter_name,
|
||||
Parameter(
|
||||
parameter_name, parameter_in,
|
||||
schema=schema, required=required,
|
||||
allow_empty_value=allow_empty_value,
|
||||
),
|
||||
|
|
62
openapi_core/responses.py
Normal file
62
openapi_core/responses.py
Normal file
|
@ -0,0 +1,62 @@
|
|||
"""OpenAPI core responses module"""
|
||||
from functools import lru_cache
|
||||
|
||||
from six import iteritems
|
||||
|
||||
from openapi_core.exceptions import InvalidContentType
|
||||
from openapi_core.media_types import MediaTypeGenerator
|
||||
from openapi_core.parameters import ParametersGenerator
|
||||
|
||||
|
||||
class Response(object):
|
||||
|
||||
def __init__(
|
||||
self, http_status, description, headers=None, content=None,
|
||||
links=None):
|
||||
self.http_status = http_status
|
||||
self.description = description
|
||||
self.headers = headers and dict(headers) or {}
|
||||
self.content = content and dict(content) or {}
|
||||
self.links = links and dict(links) or {}
|
||||
|
||||
def __getitem__(self, mimetype):
|
||||
try:
|
||||
return self.content[mimetype]
|
||||
except KeyError:
|
||||
raise InvalidContentType(
|
||||
"Invalid mime type `{0}`".format(mimetype))
|
||||
|
||||
|
||||
class ResponsesGenerator(object):
|
||||
|
||||
def __init__(self, dereferencer, schemas_registry):
|
||||
self.dereferencer = dereferencer
|
||||
self.schemas_registry = schemas_registry
|
||||
|
||||
def generate(self, responses):
|
||||
for http_status, response in iteritems(responses):
|
||||
description = response['description']
|
||||
headers = response.get('headers')
|
||||
content = response.get('content')
|
||||
|
||||
media_types = None
|
||||
if content:
|
||||
media_types = self.media_types_generator.generate(content)
|
||||
|
||||
parameters = None
|
||||
if headers:
|
||||
parameters = self.parameters_generator.generate(headers)
|
||||
|
||||
yield http_status, Response(
|
||||
http_status, description,
|
||||
content=media_types, headers=parameters)
|
||||
|
||||
@property
|
||||
@lru_cache()
|
||||
def media_types_generator(self):
|
||||
return MediaTypeGenerator(self.dereferencer, self.schemas_registry)
|
||||
|
||||
@property
|
||||
@lru_cache()
|
||||
def parameters_generator(self):
|
||||
return ParametersGenerator(self.dereferencer, self.schemas_registry)
|
|
@ -2,7 +2,7 @@
|
|||
from six import iteritems
|
||||
|
||||
from openapi_core.exceptions import (
|
||||
OpenAPIMappingError, MissingParameter, MissingBody,
|
||||
OpenAPIMappingError, MissingParameter, MissingBody, InvalidResponse,
|
||||
)
|
||||
|
||||
|
||||
|
@ -43,6 +43,14 @@ class RequestValidationResult(BaseValidationResult):
|
|||
self.parameters = parameters or RequestParameters()
|
||||
|
||||
|
||||
class ResponseValidationResult(BaseValidationResult):
|
||||
|
||||
def __init__(self, errors, data=None, headers=None):
|
||||
super(ResponseValidationResult, self).__init__(errors)
|
||||
self.data = data
|
||||
self.headers = headers
|
||||
|
||||
|
||||
class RequestValidator(object):
|
||||
|
||||
def __init__(self, spec):
|
||||
|
@ -120,3 +128,63 @@ class RequestValidator(object):
|
|||
raise MissingBody("Missing required request body")
|
||||
|
||||
return request.body
|
||||
|
||||
|
||||
class ResponseValidator(object):
|
||||
|
||||
def __init__(self, spec):
|
||||
self.spec = spec
|
||||
|
||||
def validate(self, request, response):
|
||||
errors = []
|
||||
data = None
|
||||
headers = {}
|
||||
|
||||
try:
|
||||
server = self.spec.get_server(request.full_url_pattern)
|
||||
# don't process if server errors
|
||||
except OpenAPIMappingError as exc:
|
||||
errors.append(exc)
|
||||
return ResponseValidationResult(errors, data, headers)
|
||||
|
||||
operation_pattern = request.full_url_pattern.replace(
|
||||
server.default_url, '')
|
||||
|
||||
try:
|
||||
operation = self.spec.get_operation(
|
||||
operation_pattern, request.method)
|
||||
# don't process if operation errors
|
||||
except OpenAPIMappingError as exc:
|
||||
errors.append(exc)
|
||||
return ResponseValidationResult(errors, data, headers)
|
||||
|
||||
try:
|
||||
operation_response = operation.get_response(str(response.status))
|
||||
# don't process if invalid response status code
|
||||
except InvalidResponse as exc:
|
||||
errors.append(exc)
|
||||
return ResponseValidationResult(errors, data, headers)
|
||||
|
||||
if operation_response.content:
|
||||
try:
|
||||
media_type = operation_response[response.mimetype]
|
||||
except OpenAPIMappingError as exc:
|
||||
errors.append(exc)
|
||||
else:
|
||||
try:
|
||||
raw_data = self._get_raw_data(response)
|
||||
except MissingBody as exc:
|
||||
errors.append(exc)
|
||||
else:
|
||||
try:
|
||||
data = media_type.unmarshal(raw_data)
|
||||
except OpenAPIMappingError as exc:
|
||||
errors.append(exc)
|
||||
|
||||
return ResponseValidationResult(errors, data, headers)
|
||||
|
||||
def _get_raw_data(self, response):
|
||||
if not response.data:
|
||||
raise MissingBody("Missing required response data")
|
||||
|
||||
return response.data
|
||||
|
|
|
@ -104,3 +104,38 @@ class FlaskOpenAPIRequest(BaseOpenAPIRequest):
|
|||
@property
|
||||
def mimetype(self):
|
||||
return self.request.mimetype
|
||||
|
||||
|
||||
class BaseOpenAPIResponse(object):
|
||||
|
||||
body = NotImplemented
|
||||
status = NotImplemented
|
||||
|
||||
mimetype = NotImplemented
|
||||
|
||||
|
||||
class MockResponse(BaseOpenAPIRequest):
|
||||
|
||||
def __init__(self, data, status=200, mimetype='application/json'):
|
||||
self.data = data
|
||||
|
||||
self.status = status
|
||||
self.mimetype = mimetype
|
||||
|
||||
|
||||
class FlaskOpenAPIResponse(BaseOpenAPIResponse):
|
||||
|
||||
def __init__(self, response):
|
||||
self.response = response
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
return self.response.data
|
||||
|
||||
@property
|
||||
def status(self):
|
||||
return self.response.status
|
||||
|
||||
@property
|
||||
def mimetype(self):
|
||||
return self.response.mimetype
|
||||
|
|
|
@ -61,12 +61,6 @@ paths:
|
|||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Pets"
|
||||
default:
|
||||
description: unexpected error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
post:
|
||||
summary: Create a pet
|
||||
operationId: createPets
|
||||
|
@ -164,9 +158,12 @@ components:
|
|||
position:
|
||||
$ref: "#/components/schemas/Position"
|
||||
Pets:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Pet"
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Pet"
|
||||
Error:
|
||||
type: object
|
||||
required:
|
||||
|
|
|
@ -9,8 +9,10 @@ from openapi_core.exceptions import (
|
|||
)
|
||||
from openapi_core.media_types import MediaType
|
||||
from openapi_core.operations import Operation
|
||||
from openapi_core.parameters import Parameter
|
||||
from openapi_core.paths import Path
|
||||
from openapi_core.request_bodies import RequestBody
|
||||
from openapi_core.responses import Response
|
||||
from openapi_core.schemas import Schema
|
||||
from openapi_core.servers import Server, ServerVariable
|
||||
from openapi_core.shortcuts import create_spec
|
||||
|
@ -59,6 +61,60 @@ class TestPetstore(object):
|
|||
assert operation.http_method == http_method
|
||||
|
||||
operation_spec = spec_dict['paths'][path_name][http_method]
|
||||
|
||||
responses_spec = operation_spec.get('responses')
|
||||
|
||||
for http_status, response in iteritems(operation.responses):
|
||||
assert type(response) == Response
|
||||
assert response.http_status == http_status
|
||||
|
||||
response_spec = responses_spec[http_status]
|
||||
description_spec = response_spec['description']
|
||||
|
||||
assert response.description == description_spec
|
||||
|
||||
for mimetype, media_type in iteritems(response.content):
|
||||
assert type(media_type) == MediaType
|
||||
assert media_type.mimetype == mimetype
|
||||
|
||||
content_spec = response_spec['content'][mimetype]
|
||||
schema_spec = content_spec.get('schema')
|
||||
assert bool(schema_spec) == bool(media_type.schema)
|
||||
|
||||
if not schema_spec:
|
||||
continue
|
||||
|
||||
# @todo: test with defererence
|
||||
if '$ref' in schema_spec:
|
||||
continue
|
||||
|
||||
assert type(media_type.schema) == Schema
|
||||
assert media_type.schema.type == schema_spec['type']
|
||||
assert media_type.schema.required == schema_spec.get(
|
||||
'required', False)
|
||||
|
||||
for parameter_name, parameter in iteritems(
|
||||
response.headers):
|
||||
assert type(parameter) == Parameter
|
||||
assert parameter.name == parameter_name
|
||||
|
||||
headers_spec = response_spec['headers']
|
||||
parameter_spec = headers_spec[parameter_name]
|
||||
schema_spec = parameter_spec.get('schema')
|
||||
assert bool(schema_spec) == bool(parameter.schema)
|
||||
|
||||
if not schema_spec:
|
||||
continue
|
||||
|
||||
# @todo: test with defererence
|
||||
if '$ref' in schema_spec:
|
||||
continue
|
||||
|
||||
assert type(parameter.schema) == Schema
|
||||
assert parameter.schema.type == schema_spec['type']
|
||||
assert parameter.schema.required == schema_spec.get(
|
||||
'required', False)
|
||||
|
||||
request_body_spec = operation_spec.get('requestBody')
|
||||
|
||||
assert bool(request_body_spec) == bool(operation.request_body)
|
||||
|
|
|
@ -3,11 +3,11 @@ import pytest
|
|||
|
||||
from openapi_core.exceptions import (
|
||||
InvalidServer, InvalidOperation, MissingParameter,
|
||||
MissingBody, InvalidContentType,
|
||||
MissingBody, InvalidContentType, InvalidResponse, InvalidMediaTypeValue,
|
||||
)
|
||||
from openapi_core.shortcuts import create_spec
|
||||
from openapi_core.validators import RequestValidator
|
||||
from openapi_core.wrappers import MockRequest
|
||||
from openapi_core.validators import RequestValidator, ResponseValidator
|
||||
from openapi_core.wrappers import MockRequest, MockResponse
|
||||
|
||||
|
||||
class TestRequestValidator(object):
|
||||
|
@ -155,3 +155,104 @@ class TestRequestValidator(object):
|
|||
'petId': 1,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class TestResponseValidator(object):
|
||||
|
||||
host_url = 'http://petstore.swagger.io'
|
||||
|
||||
@pytest.fixture
|
||||
def spec_dict(self, factory):
|
||||
return factory.spec_from_file("data/v3.0/petstore.yaml")
|
||||
|
||||
@pytest.fixture
|
||||
def spec(self, spec_dict):
|
||||
return create_spec(spec_dict)
|
||||
|
||||
@pytest.fixture
|
||||
def validator(self, spec):
|
||||
return ResponseValidator(spec)
|
||||
|
||||
def test_invalid_server(self, validator):
|
||||
request = MockRequest('http://petstore.invalid.net/v1', 'get', '/')
|
||||
response = MockResponse('Not Found', status=404)
|
||||
|
||||
result = validator.validate(request, response)
|
||||
|
||||
assert len(result.errors) == 1
|
||||
assert type(result.errors[0]) == InvalidServer
|
||||
assert result.data is None
|
||||
assert result.headers == {}
|
||||
|
||||
def test_invalid_operation(self, validator):
|
||||
request = MockRequest(self.host_url, 'get', '/v1')
|
||||
response = MockResponse('Not Found', status=404)
|
||||
|
||||
result = validator.validate(request, response)
|
||||
|
||||
assert len(result.errors) == 1
|
||||
assert type(result.errors[0]) == InvalidOperation
|
||||
assert result.data is None
|
||||
assert result.headers == {}
|
||||
|
||||
def test_invalid_response(self, validator):
|
||||
request = MockRequest(self.host_url, 'get', '/v1/pets')
|
||||
response = MockResponse('Not Found', status=409)
|
||||
|
||||
result = validator.validate(request, response)
|
||||
|
||||
assert len(result.errors) == 1
|
||||
assert type(result.errors[0]) == InvalidResponse
|
||||
assert result.data is None
|
||||
assert result.headers == {}
|
||||
|
||||
def test_invalid_content_type(self, validator):
|
||||
request = MockRequest(self.host_url, 'get', '/v1/pets')
|
||||
response = MockResponse('Not Found', mimetype='text/csv')
|
||||
|
||||
result = validator.validate(request, response)
|
||||
|
||||
assert len(result.errors) == 1
|
||||
assert type(result.errors[0]) == InvalidContentType
|
||||
assert result.data is None
|
||||
assert result.headers == {}
|
||||
|
||||
def test_missing_body(self, validator):
|
||||
request = MockRequest(self.host_url, 'get', '/v1/pets')
|
||||
response = MockResponse(None)
|
||||
|
||||
result = validator.validate(request, response)
|
||||
|
||||
assert len(result.errors) == 1
|
||||
assert type(result.errors[0]) == MissingBody
|
||||
assert result.data is None
|
||||
assert result.headers == {}
|
||||
|
||||
def test_invalid_media_type_value(self, validator):
|
||||
request = MockRequest(self.host_url, 'get', '/v1/pets')
|
||||
response = MockResponse('\{\}')
|
||||
|
||||
result = validator.validate(request, response)
|
||||
|
||||
assert len(result.errors) == 1
|
||||
assert type(result.errors[0]) == InvalidMediaTypeValue
|
||||
assert result.data is None
|
||||
assert result.headers == {}
|
||||
|
||||
def test_get_pets(self, validator):
|
||||
request = MockRequest(self.host_url, 'get', '/v1/pets')
|
||||
response_json = {
|
||||
'data': [
|
||||
{
|
||||
'id': 1,
|
||||
},
|
||||
],
|
||||
}
|
||||
response_data = json.dumps(response_json)
|
||||
response = MockResponse(response_data)
|
||||
|
||||
result = validator.validate(request, response)
|
||||
|
||||
assert result.errors == []
|
||||
assert result.data == response_json
|
||||
assert result.headers == {}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import pytest
|
||||
|
||||
from flask.wrappers import Request
|
||||
from flask.wrappers import Request, Response
|
||||
from werkzeug.datastructures import EnvironHeaders, ImmutableMultiDict
|
||||
from werkzeug.routing import Map, Rule, Subdomain
|
||||
from werkzeug.test import create_environ
|
||||
|
||||
from openapi_core.wrappers import FlaskOpenAPIRequest
|
||||
from openapi_core.wrappers import FlaskOpenAPIRequest, FlaskOpenAPIResponse
|
||||
|
||||
|
||||
class TestFlaskOpenAPIRequest(object):
|
||||
|
@ -90,3 +90,22 @@ class TestFlaskOpenAPIRequest(object):
|
|||
assert openapi_request.path_pattern == request.url_rule.rule
|
||||
assert openapi_request.body == request.data
|
||||
assert openapi_request.mimetype == request.mimetype
|
||||
|
||||
|
||||
class TestFlaskOpenAPIResponse(object):
|
||||
|
||||
@pytest.fixture
|
||||
def response_factory(self):
|
||||
def create_response(body, status=200):
|
||||
return Response('Not Found', status=404)
|
||||
return create_response
|
||||
|
||||
def test_invalid_server(self, response_factory):
|
||||
response = response_factory('Not Found', status=404)
|
||||
|
||||
openapi_response = FlaskOpenAPIResponse(response)
|
||||
|
||||
assert openapi_response.response == response
|
||||
assert openapi_response.data == response.data
|
||||
assert openapi_response.status == response.status
|
||||
assert openapi_response.mimetype == response.mimetype
|
||||
|
|
|
@ -7,14 +7,41 @@ from openapi_core.operations import Operation
|
|||
class TestSchemas(object):
|
||||
|
||||
@pytest.fixture
|
||||
def oepration(self):
|
||||
def operation(self):
|
||||
parameters = {
|
||||
'parameter_1': mock.sentinel.parameter_1,
|
||||
'parameter_2': mock.sentinel.parameter_2,
|
||||
}
|
||||
return Operation('get', '/path', parameters=parameters)
|
||||
return Operation('get', '/path', {}, parameters=parameters)
|
||||
|
||||
@property
|
||||
def test_iteritems(self, oepration):
|
||||
for name in oepration.parameters.keys():
|
||||
assert oepration[name] == oepration.parameters[name]
|
||||
def test_iteritems(self, operation):
|
||||
for name in operation.parameters.keys():
|
||||
assert operation[name] == operation.parameters[name]
|
||||
|
||||
|
||||
class TestResponses(object):
|
||||
|
||||
@pytest.fixture
|
||||
def operation(self):
|
||||
responses = {
|
||||
'200': mock.sentinel.response_200,
|
||||
'299': mock.sentinel.response_299,
|
||||
'2XX': mock.sentinel.response_2XX,
|
||||
'default': mock.sentinel.response_default,
|
||||
}
|
||||
return Operation('get', '/path', responses, parameters={})
|
||||
|
||||
def test_default(self, operation):
|
||||
response = operation.get_response()
|
||||
|
||||
assert response == operation.responses['default']
|
||||
|
||||
def test_range(self, operation):
|
||||
response = operation.get_response('201')
|
||||
|
||||
assert response == operation.responses['2XX']
|
||||
|
||||
def test_exact(self, operation):
|
||||
response = operation.get_response('200')
|
||||
|
||||
assert response == operation.responses['200']
|
||||
|
|
Loading…
Reference in a new issue