From 0404d4893b8b61acca7fc36ca2cce07e661912df Mon Sep 17 00:00:00 2001 From: p1c2u Date: Mon, 12 Sep 2022 14:46:16 +0100 Subject: [PATCH] Auto-detect request and response validator proxies --- README.rst | 18 +- docs/index.rst | 3 +- docs/usage.rst | 6 +- openapi_core/__init__.py | 32 ++- openapi_core/contrib/flask/decorators.py | 4 +- .../unmarshalling/schemas/__init__.py | 14 ++ openapi_core/validation/exceptions.py | 4 + openapi_core/validation/processors.py | 4 +- openapi_core/validation/request/__init__.py | 61 ++++- openapi_core/validation/request/protocols.py | 13 ++ openapi_core/validation/request/proxies.py | 57 +++++ openapi_core/validation/request/validators.py | 11 + openapi_core/validation/response/__init__.py | 48 +++- openapi_core/validation/response/protocols.py | 17 ++ openapi_core/validation/response/proxies.py | 64 ++++++ .../validation/response/validators.py | 11 + openapi_core/validation/shortcuts.py | 4 +- tests/integration/data/v3.1/empty.yaml | 1 + tests/integration/data/v3.1/links.yaml | 48 ++++ tests/integration/data/v3.1/minimal.yaml | 10 + .../data/v3.1/minimal_with_servers.yaml | 12 + tests/integration/data/v3.1/path_param.yaml | 17 ++ .../data/v3.1/security_override.yaml | 41 ++++ .../data/v3.1/webhook-example.yaml | 34 +++ tests/integration/schema/test_link_spec.py | 25 ++- tests/integration/schema/test_path_params.py | 15 +- tests/integration/schema/test_spec.py | 62 ++++- tests/integration/validation/test_minimal.py | 2 + tests/integration/validation/test_petstore.py | 211 ++++++++++-------- .../validation/test_read_only_write_only.py | 16 +- 30 files changed, 724 insertions(+), 141 deletions(-) create mode 100644 openapi_core/validation/request/proxies.py create mode 100644 openapi_core/validation/response/proxies.py create mode 100644 tests/integration/data/v3.1/empty.yaml create mode 100644 tests/integration/data/v3.1/links.yaml create mode 100644 tests/integration/data/v3.1/minimal.yaml create mode 100644 tests/integration/data/v3.1/minimal_with_servers.yaml create mode 100644 tests/integration/data/v3.1/path_param.yaml create mode 100644 tests/integration/data/v3.1/security_override.yaml create mode 100644 tests/integration/data/v3.1/webhook-example.yaml diff --git a/README.rst b/README.rst index 226e551f..c1f3b881 100644 --- a/README.rst +++ b/README.rst @@ -19,7 +19,8 @@ About ##### Openapi-core is a Python library that adds client-side and server-side support -for the `OpenAPI Specification v3 `__. +for the `OpenAPI v3.0 `__ +and `OpenAPI v3.1 `__ specification. Key features ************ @@ -57,7 +58,7 @@ Alternatively you can download the code and install from the repository: Usage ##### -Firstly create your specification object: +Firstly create your specification object. By default, OpenAPI spec version is detected: .. code-block:: python @@ -132,6 +133,19 @@ and unmarshal response data from validation result Response object should implement OpenAPI Response protocol (See `Integrations `__). +In order to explicitly validate a: + +* OpenAPI 3.0 spec, import ``openapi_v30_request_validator`` or ``openapi_v30_response_validator`` +* OpenAPI 3.1 spec, import ``openapi_v31_request_validator`` or ``openapi_v31_response_validator`` + +.. code:: python + + from openapi_core.validation.response import openapi_v31_response_validator + + result = openapi_v31_response_validator.validate(spec, request, response) + +You can also explicitly import ``openapi_v3_request_validator`` or ``openapi_v3_response_validator`` which is a shortcut to the latest v3 release. + Related projects ################ * `bottle-openapi-3 `__ diff --git a/docs/index.rst b/docs/index.rst index 33b5f48c..8090a33b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -7,7 +7,8 @@ Welcome to openapi-core's documentation! ======================================== Openapi-core is a Python library that adds client-side and server-side support -for the `OpenAPI Specification v3 `__. +for the `OpenAPI v3.0 `__ +and `OpenAPI v3.1 `__ specification. Key features ------------ diff --git a/docs/usage.rst b/docs/usage.rst index aa30e485..94ddbda3 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -1,7 +1,7 @@ Usage ===== -Firstly create your specification: object +Firstly create your specification object. By default, OpenAPI spec version is detected: .. code-block:: python @@ -46,7 +46,7 @@ and unmarshal request data from validation result # get security data validated_security = result.security -Request object should be instance of OpenAPIRequest class (See :doc:`integrations`). +Request object should implement OpenAPI Request protocol (See :doc:`integrations`). Response -------- @@ -75,7 +75,7 @@ and unmarshal response data from validation result # get data validated_data = result.data -Response object should be instance of OpenAPIResponse class (See :doc:`integrations`). +Response object should implement OpenAPI Response protocol (See :doc:`integrations`). Security -------- diff --git a/openapi_core/__init__.py b/openapi_core/__init__.py index fa1ace79..9da86a38 100644 --- a/openapi_core/__init__.py +++ b/openapi_core/__init__.py @@ -1,16 +1,14 @@ """OpenAPI core module""" from openapi_core.spec import Spec -from openapi_core.validation.request.validators import RequestBodyValidator -from openapi_core.validation.request.validators import ( - RequestParametersValidator, +from openapi_core.validation.request import openapi_request_body_validator +from openapi_core.validation.request import ( + openapi_request_parameters_validator, ) -from openapi_core.validation.request.validators import RequestSecurityValidator -from openapi_core.validation.request.validators import RequestValidator -from openapi_core.validation.response.validators import ResponseDataValidator -from openapi_core.validation.response.validators import ( - ResponseHeadersValidator, -) -from openapi_core.validation.response.validators import ResponseValidator +from openapi_core.validation.request import openapi_request_security_validator +from openapi_core.validation.request import openapi_request_validator +from openapi_core.validation.response import openapi_response_data_validator +from openapi_core.validation.response import openapi_response_headers_validator +from openapi_core.validation.response import openapi_response_validator from openapi_core.validation.shortcuts import validate_request from openapi_core.validation.shortcuts import validate_response @@ -24,11 +22,11 @@ "Spec", "validate_request", "validate_response", - "RequestValidator", - "ResponseValidator", - "RequestBodyValidator", - "RequestParametersValidator", - "RequestSecurityValidator", - "ResponseDataValidator", - "ResponseHeadersValidator", + "openapi_request_body_validator", + "openapi_request_parameters_validator", + "openapi_request_security_validator", + "openapi_request_validator", + "openapi_response_data_validator", + "openapi_response_headers_validator", + "openapi_response_validator", ] diff --git a/openapi_core/contrib/flask/decorators.py b/openapi_core/contrib/flask/decorators.py index b30f41d8..9e2eb182 100644 --- a/openapi_core/contrib/flask/decorators.py +++ b/openapi_core/contrib/flask/decorators.py @@ -16,10 +16,10 @@ from openapi_core.validation.processors import OpenAPIProcessor from openapi_core.validation.request import openapi_request_validator from openapi_core.validation.request.datatypes import RequestValidationResult -from openapi_core.validation.request.validators import RequestValidator +from openapi_core.validation.request.protocols import RequestValidator from openapi_core.validation.response import openapi_response_validator from openapi_core.validation.response.datatypes import ResponseValidationResult -from openapi_core.validation.response.validators import ResponseValidator +from openapi_core.validation.response.protocols import ResponseValidator class FlaskOpenAPIViewDecorator(OpenAPIProcessor): diff --git a/openapi_core/unmarshalling/schemas/__init__.py b/openapi_core/unmarshalling/schemas/__init__.py index 0591dee2..0a3e2cf1 100644 --- a/openapi_core/unmarshalling/schemas/__init__.py +++ b/openapi_core/unmarshalling/schemas/__init__.py @@ -1,4 +1,5 @@ from openapi_schema_validator import OAS30Validator +from openapi_schema_validator import OAS31Validator from openapi_core.unmarshalling.schemas.enums import UnmarshalContext from openapi_core.unmarshalling.schemas.factories import ( @@ -8,6 +9,9 @@ __all__ = [ "oas30_request_schema_unmarshallers_factory", "oas30_response_schema_unmarshallers_factory", + "oas31_request_schema_unmarshallers_factory", + "oas31_response_schema_unmarshallers_factory", + "oas31_schema_unmarshallers_factory", ] oas30_request_schema_unmarshallers_factory = SchemaUnmarshallersFactory( @@ -19,3 +23,13 @@ OAS30Validator, context=UnmarshalContext.RESPONSE, ) + +oas31_schema_unmarshallers_factory = SchemaUnmarshallersFactory( + OAS31Validator, +) + +# alias to v31 version (request/response are the same bcs no context needed) +oas31_request_schema_unmarshallers_factory = oas31_schema_unmarshallers_factory +oas31_response_schema_unmarshallers_factory = ( + oas31_schema_unmarshallers_factory +) diff --git a/openapi_core/validation/exceptions.py b/openapi_core/validation/exceptions.py index 71b2bb87..5250ecb1 100644 --- a/openapi_core/validation/exceptions.py +++ b/openapi_core/validation/exceptions.py @@ -4,6 +4,10 @@ from openapi_core.exceptions import OpenAPIError +class ValidatorDetectError(OpenAPIError): + pass + + class ValidationError(OpenAPIError): pass diff --git a/openapi_core/validation/processors.py b/openapi_core/validation/processors.py index 13d393bc..c2d9356d 100644 --- a/openapi_core/validation/processors.py +++ b/openapi_core/validation/processors.py @@ -2,10 +2,10 @@ from openapi_core.spec import Spec from openapi_core.validation.request.datatypes import RequestValidationResult from openapi_core.validation.request.protocols import Request -from openapi_core.validation.request.validators import RequestValidator +from openapi_core.validation.request.protocols import RequestValidator from openapi_core.validation.response.datatypes import ResponseValidationResult from openapi_core.validation.response.protocols import Response -from openapi_core.validation.response.validators import ResponseValidator +from openapi_core.validation.response.protocols import ResponseValidator class OpenAPIProcessor: diff --git a/openapi_core/validation/request/__init__.py b/openapi_core/validation/request/__init__.py index 7d088554..d4c57fc4 100644 --- a/openapi_core/validation/request/__init__.py +++ b/openapi_core/validation/request/__init__.py @@ -2,6 +2,10 @@ from openapi_core.unmarshalling.schemas import ( oas30_request_schema_unmarshallers_factory, ) +from openapi_core.unmarshalling.schemas import ( + oas31_schema_unmarshallers_factory, +) +from openapi_core.validation.request.proxies import DetectRequestValidatorProxy from openapi_core.validation.request.validators import RequestBodyValidator from openapi_core.validation.request.validators import ( RequestParametersValidator, @@ -14,6 +18,14 @@ "openapi_v30_request_parameters_validator", "openapi_v30_request_security_validator", "openapi_v30_request_validator", + "openapi_v31_request_body_validator", + "openapi_v31_request_parameters_validator", + "openapi_v31_request_security_validator", + "openapi_v31_request_validator", + "openapi_v3_request_body_validator", + "openapi_v3_request_parameters_validator", + "openapi_v3_request_security_validator", + "openapi_v3_request_validator", "openapi_request_body_validator", "openapi_request_parameters_validator", "openapi_request_security_validator", @@ -33,8 +45,49 @@ schema_unmarshallers_factory=oas30_request_schema_unmarshallers_factory, ) +openapi_v31_request_body_validator = RequestBodyValidator( + schema_unmarshallers_factory=oas31_schema_unmarshallers_factory, +) +openapi_v31_request_parameters_validator = RequestParametersValidator( + schema_unmarshallers_factory=oas31_schema_unmarshallers_factory, +) +openapi_v31_request_security_validator = RequestSecurityValidator( + schema_unmarshallers_factory=oas31_schema_unmarshallers_factory, +) +openapi_v31_request_validator = RequestValidator( + schema_unmarshallers_factory=oas31_schema_unmarshallers_factory, +) + # alias to the latest v3 version -openapi_request_body_validator = openapi_v30_request_body_validator -openapi_request_parameters_validator = openapi_v30_request_parameters_validator -openapi_request_security_validator = openapi_v30_request_security_validator -openapi_request_validator = openapi_v30_request_validator +openapi_v3_request_body_validator = openapi_v31_request_body_validator +openapi_v3_request_parameters_validator = ( + openapi_v31_request_parameters_validator +) +openapi_v3_request_security_validator = openapi_v31_request_security_validator +openapi_v3_request_validator = openapi_v31_request_validator + +# detect version spec +openapi_request_body_validator = DetectRequestValidatorProxy( + { + ("openapi", "3.0"): openapi_v30_request_body_validator, + ("openapi", "3.1"): openapi_v31_request_body_validator, + }, +) +openapi_request_parameters_validator = DetectRequestValidatorProxy( + { + ("openapi", "3.0"): openapi_v30_request_parameters_validator, + ("openapi", "3.1"): openapi_v31_request_parameters_validator, + }, +) +openapi_request_security_validator = DetectRequestValidatorProxy( + { + ("openapi", "3.0"): openapi_v30_request_security_validator, + ("openapi", "3.1"): openapi_v31_request_security_validator, + }, +) +openapi_request_validator = DetectRequestValidatorProxy( + { + ("openapi", "3.0"): openapi_v30_request_validator, + ("openapi", "3.1"): openapi_v31_request_validator, + }, +) diff --git a/openapi_core/validation/request/protocols.py b/openapi_core/validation/request/protocols.py index 1a880eb9..8a3ab254 100644 --- a/openapi_core/validation/request/protocols.py +++ b/openapi_core/validation/request/protocols.py @@ -13,7 +13,9 @@ from typing_extensions import Protocol from typing_extensions import runtime_checkable +from openapi_core.spec import Spec from openapi_core.validation.request.datatypes import RequestParameters +from openapi_core.validation.request.datatypes import RequestValidationResult @runtime_checkable @@ -85,3 +87,14 @@ class SupportsPathPattern(Protocol): @property def path_pattern(self) -> str: ... + + +@runtime_checkable +class RequestValidator(Protocol): + def validate( + self, + spec: Spec, + request: Request, + base_url: Optional[str] = None, + ) -> RequestValidationResult: + ... diff --git a/openapi_core/validation/request/proxies.py b/openapi_core/validation/request/proxies.py new file mode 100644 index 00000000..725853ac --- /dev/null +++ b/openapi_core/validation/request/proxies.py @@ -0,0 +1,57 @@ +"""OpenAPI spec validator validation proxies module.""" +from typing import Any +from typing import Hashable +from typing import Iterator +from typing import Mapping +from typing import Optional +from typing import Tuple + +from openapi_core.exceptions import OpenAPIError +from openapi_core.spec import Spec +from openapi_core.validation.exceptions import ValidatorDetectError +from openapi_core.validation.request.datatypes import RequestValidationResult +from openapi_core.validation.request.protocols import Request +from openapi_core.validation.request.validators import BaseRequestValidator + + +class DetectRequestValidatorProxy: + def __init__( + self, choices: Mapping[Tuple[str, str], BaseRequestValidator] + ): + self.choices = choices + + def detect(self, spec: Spec) -> BaseRequestValidator: + for (key, value), validator in self.choices.items(): + if key in spec and spec[key].startswith(value): + return validator + raise ValidatorDetectError("Spec schema version not detected") + + def validate( + self, + spec: Spec, + request: Request, + base_url: Optional[str] = None, + ) -> RequestValidationResult: + validator = self.detect(spec) + return validator.validate(spec, request, base_url=base_url) + + def is_valid( + self, + spec: Spec, + request: Request, + base_url: Optional[str] = None, + ) -> bool: + validator = self.detect(spec) + error = next( + validator.iter_errors(spec, request, base_url=base_url), None + ) + return error is None + + def iter_errors( + self, + spec: Spec, + request: Request, + base_url: Optional[str] = None, + ) -> Iterator[Exception]: + validator = self.detect(spec) + yield from validator.iter_errors(spec, request, base_url=base_url) diff --git a/openapi_core/validation/request/validators.py b/openapi_core/validation/request/validators.py index c0298fb2..ec703d5a 100644 --- a/openapi_core/validation/request/validators.py +++ b/openapi_core/validation/request/validators.py @@ -2,6 +2,7 @@ import warnings from typing import Any from typing import Dict +from typing import Iterator from typing import Optional from openapi_core.casting.schemas import schema_casters_factory @@ -20,6 +21,7 @@ from openapi_core.deserializing.parameters.factories import ( ParameterDeserializersFactory, ) +from openapi_core.exceptions import OpenAPIError from openapi_core.security import security_provider_factory from openapi_core.security.exceptions import SecurityError from openapi_core.security.factories import SecurityProviderFactory @@ -64,6 +66,15 @@ def __init__( ) self.security_provider_factory = security_provider_factory + def iter_errors( + self, + spec: Spec, + request: Request, + base_url: Optional[str] = None, + ) -> Iterator[Exception]: + result = self.validate(spec, request, base_url=base_url) + yield from result.errors + def validate( self, spec: Spec, diff --git a/openapi_core/validation/response/__init__.py b/openapi_core/validation/response/__init__.py index bce2ee18..3bbc3001 100644 --- a/openapi_core/validation/response/__init__.py +++ b/openapi_core/validation/response/__init__.py @@ -2,6 +2,12 @@ from openapi_core.unmarshalling.schemas import ( oas30_response_schema_unmarshallers_factory, ) +from openapi_core.unmarshalling.schemas import ( + oas31_schema_unmarshallers_factory, +) +from openapi_core.validation.response.proxies import ( + DetectResponseValidatorProxy, +) from openapi_core.validation.response.validators import ResponseDataValidator from openapi_core.validation.response.validators import ( ResponseHeadersValidator, @@ -12,6 +18,12 @@ "openapi_v30_response_data_validator", "openapi_v30_response_headers_validator", "openapi_v30_response_validator", + "openapi_v31_response_data_validator", + "openapi_v31_response_headers_validator", + "openapi_v31_response_validator", + "openapi_v3_response_data_validator", + "openapi_v3_response_headers_validator", + "openapi_v3_response_validator", "openapi_response_data_validator", "openapi_response_headers_validator", "openapi_response_validator", @@ -27,7 +39,37 @@ schema_unmarshallers_factory=oas30_response_schema_unmarshallers_factory, ) +openapi_v31_response_data_validator = ResponseDataValidator( + schema_unmarshallers_factory=oas31_schema_unmarshallers_factory, +) +openapi_v31_response_headers_validator = ResponseHeadersValidator( + schema_unmarshallers_factory=oas31_schema_unmarshallers_factory, +) +openapi_v31_response_validator = ResponseValidator( + schema_unmarshallers_factory=oas31_schema_unmarshallers_factory, +) + # alias to the latest v3 version -openapi_response_data_validator = openapi_v30_response_data_validator -openapi_response_headers_validator = openapi_v30_response_headers_validator -openapi_response_validator = openapi_v30_response_validator +openapi_v3_response_data_validator = openapi_v31_response_data_validator +openapi_v3_response_headers_validator = openapi_v31_response_headers_validator +openapi_v3_response_validator = openapi_v31_response_validator + +# detect version spec +openapi_response_data_validator = DetectResponseValidatorProxy( + { + ("openapi", "3.0"): openapi_v30_response_data_validator, + ("openapi", "3.1"): openapi_v31_response_data_validator, + }, +) +openapi_response_headers_validator = DetectResponseValidatorProxy( + { + ("openapi", "3.0"): openapi_v30_response_headers_validator, + ("openapi", "3.1"): openapi_v31_response_headers_validator, + }, +) +openapi_response_validator = DetectResponseValidatorProxy( + { + ("openapi", "3.0"): openapi_v30_response_validator, + ("openapi", "3.1"): openapi_v31_response_validator, + }, +) diff --git a/openapi_core/validation/response/protocols.py b/openapi_core/validation/response/protocols.py index 2e67ecdb..7a66ea8f 100644 --- a/openapi_core/validation/response/protocols.py +++ b/openapi_core/validation/response/protocols.py @@ -1,5 +1,6 @@ """OpenAPI core validation response protocols module""" from typing import TYPE_CHECKING +from typing import Optional if TYPE_CHECKING: from typing_extensions import Protocol @@ -14,6 +15,10 @@ from werkzeug.datastructures import Headers +from openapi_core.spec import Spec +from openapi_core.validation.request.protocols import Request +from openapi_core.validation.response.datatypes import ResponseValidationResult + @runtime_checkable class Response(Protocol): @@ -45,3 +50,15 @@ def mimetype(self) -> str: @property def headers(self) -> Headers: ... + + +@runtime_checkable +class ResponseValidator(Protocol): + def validate( + self, + spec: Spec, + request: Request, + response: Response, + base_url: Optional[str] = None, + ) -> ResponseValidationResult: + ... diff --git a/openapi_core/validation/response/proxies.py b/openapi_core/validation/response/proxies.py new file mode 100644 index 00000000..750d0337 --- /dev/null +++ b/openapi_core/validation/response/proxies.py @@ -0,0 +1,64 @@ +"""OpenAPI spec validator validation proxies module.""" +from typing import Any +from typing import Hashable +from typing import Iterator +from typing import Mapping +from typing import Optional +from typing import Tuple + +from openapi_core.exceptions import OpenAPIError +from openapi_core.spec import Spec +from openapi_core.validation.exceptions import ValidatorDetectError +from openapi_core.validation.request.protocols import Request +from openapi_core.validation.response.datatypes import ResponseValidationResult +from openapi_core.validation.response.protocols import Response +from openapi_core.validation.response.validators import BaseResponseValidator + + +class DetectResponseValidatorProxy: + def __init__( + self, choices: Mapping[Tuple[str, str], BaseResponseValidator] + ): + self.choices = choices + + def detect(self, spec: Spec) -> BaseResponseValidator: + for (key, value), validator in self.choices.items(): + if key in spec and spec[key].startswith(value): + return validator + raise ValidatorDetectError("Spec schema version not detected") + + def validate( + self, + spec: Spec, + request: Request, + response: Response, + base_url: Optional[str] = None, + ) -> ResponseValidationResult: + validator = self.detect(spec) + return validator.validate(spec, request, response, base_url=base_url) + + def is_valid( + self, + spec: Spec, + request: Request, + response: Response, + base_url: Optional[str] = None, + ) -> bool: + validator = self.detect(spec) + error = next( + validator.iter_errors(spec, request, response, base_url=base_url), + None, + ) + return error is None + + def iter_errors( + self, + spec: Spec, + request: Request, + response: Response, + base_url: Optional[str] = None, + ) -> Iterator[Exception]: + validator = self.detect(spec) + yield from validator.iter_errors( + spec, request, response, base_url=base_url + ) diff --git a/openapi_core/validation/response/validators.py b/openapi_core/validation/response/validators.py index 0e735c82..9c884a06 100644 --- a/openapi_core/validation/response/validators.py +++ b/openapi_core/validation/response/validators.py @@ -2,6 +2,7 @@ import warnings from typing import Any from typing import Dict +from typing import Iterator from typing import List from typing import Optional @@ -30,6 +31,16 @@ class BaseResponseValidator(BaseValidator): + def iter_errors( + self, + spec: Spec, + request: Request, + response: Response, + base_url: Optional[str] = None, + ) -> Iterator[Exception]: + result = self.validate(spec, request, response, base_url=base_url) + yield from result.errors + def validate( self, spec: Spec, diff --git a/openapi_core/validation/shortcuts.py b/openapi_core/validation/shortcuts.py index 7eaed534..35840604 100644 --- a/openapi_core/validation/shortcuts.py +++ b/openapi_core/validation/shortcuts.py @@ -5,11 +5,11 @@ from openapi_core.validation.request import openapi_request_validator from openapi_core.validation.request.datatypes import RequestValidationResult from openapi_core.validation.request.protocols import Request -from openapi_core.validation.request.validators import RequestValidator +from openapi_core.validation.request.protocols import RequestValidator from openapi_core.validation.response import openapi_response_validator from openapi_core.validation.response.datatypes import ResponseValidationResult from openapi_core.validation.response.protocols import Response -from openapi_core.validation.response.validators import ResponseValidator +from openapi_core.validation.response.protocols import ResponseValidator def validate_request( diff --git a/tests/integration/data/v3.1/empty.yaml b/tests/integration/data/v3.1/empty.yaml new file mode 100644 index 00000000..7bd07431 --- /dev/null +++ b/tests/integration/data/v3.1/empty.yaml @@ -0,0 +1 @@ +openapi: "3.1.0" diff --git a/tests/integration/data/v3.1/links.yaml b/tests/integration/data/v3.1/links.yaml new file mode 100644 index 00000000..a35733fa --- /dev/null +++ b/tests/integration/data/v3.1/links.yaml @@ -0,0 +1,48 @@ +openapi: "3.1.0" +info: + title: Minimal valid OpenAPI specification + version: "0.1" +paths: + /linked/noParam: + get: + operationId: noParOp + responses: + default: + description: the linked result + /linked/withParam: + get: + operationId: paramOp + parameters: + - name: opParam + in: query + description: test + schema: + type: string + responses: + default: + description: the linked result + /status: + get: + responses: + default: + description: Return something + links: + noParamLink: + operationId: noParOp + /status/{resourceId}: + get: + parameters: + - name: resourceId + in: path + required: true + schema: + type: string + responses: + default: + description: Return something else + links: + paramLink: + operationId: paramOp + parameters: + opParam: $request.path.resourceId + requestBody: test \ No newline at end of file diff --git a/tests/integration/data/v3.1/minimal.yaml b/tests/integration/data/v3.1/minimal.yaml new file mode 100644 index 00000000..94fb971e --- /dev/null +++ b/tests/integration/data/v3.1/minimal.yaml @@ -0,0 +1,10 @@ +openapi: "3.1.0" +info: + title: Minimal valid OpenAPI specification + version: "0.1" +paths: + /status: + get: + responses: + default: + description: Return the API status. \ No newline at end of file diff --git a/tests/integration/data/v3.1/minimal_with_servers.yaml b/tests/integration/data/v3.1/minimal_with_servers.yaml new file mode 100644 index 00000000..d437c20f --- /dev/null +++ b/tests/integration/data/v3.1/minimal_with_servers.yaml @@ -0,0 +1,12 @@ +openapi: "3.1.0" +info: + title: Minimal valid OpenAPI specification with explicit 'servers' array + version: "0.1" +servers: + - url: / +paths: + /status: + get: + responses: + default: + description: Return the API status. \ No newline at end of file diff --git a/tests/integration/data/v3.1/path_param.yaml b/tests/integration/data/v3.1/path_param.yaml new file mode 100644 index 00000000..72c9b676 --- /dev/null +++ b/tests/integration/data/v3.1/path_param.yaml @@ -0,0 +1,17 @@ +openapi: "3.1.0" +info: + title: Minimal OpenAPI specification with path parameters + version: "0.1" +paths: + /resource/{resId}: + parameters: + - name: resId + in: path + required: true + description: the ID of the resource to retrieve + schema: + type: string + get: + responses: + default: + description: Return the resource. \ No newline at end of file diff --git a/tests/integration/data/v3.1/security_override.yaml b/tests/integration/data/v3.1/security_override.yaml new file mode 100644 index 00000000..9d6bec96 --- /dev/null +++ b/tests/integration/data/v3.1/security_override.yaml @@ -0,0 +1,41 @@ +openapi: "3.1.0" +info: + title: Minimal OpenAPI specification with security override + version: "0.1" +security: + - api_key: [] +paths: + /resource/{resId}: + parameters: + - name: resId + in: path + required: true + description: the ID of the resource to retrieve + schema: + type: string + get: + responses: + default: + description: Default security. + post: + security: + - petstore_auth: + - write:pets + - read:pets + responses: + default: + description: Override security. + put: + security: [] + responses: + default: + description: Remove security. +components: + securitySchemes: + api_key: + type: apiKey + name: api_key + in: query + petstore_auth: + type: http + scheme: basic \ No newline at end of file diff --git a/tests/integration/data/v3.1/webhook-example.yaml b/tests/integration/data/v3.1/webhook-example.yaml new file mode 100644 index 00000000..44fc73aa --- /dev/null +++ b/tests/integration/data/v3.1/webhook-example.yaml @@ -0,0 +1,34 @@ +openapi: 3.1.0 +info: + title: Webhook Example + version: 1.0.0 +# Since OAS 3.1.0 the paths element isn't necessary. Now a valid OpenAPI Document can describe only paths, webhooks, or even only reusable components +webhooks: + # Each webhook needs a name + newPet: + # This is a Path Item Object, the only difference is that the request is initiated by the API provider + post: + requestBody: + description: Information about a new pet in the system + content: + application/json: + schema: + $ref: "#/components/schemas/Pet" + responses: + "200": + description: Return a 200 status to indicate that the data was received successfully + +components: + schemas: + Pet: + required: + - id + - name + properties: + id: + type: integer + format: int64 + name: + type: string + tag: + type: string diff --git a/tests/integration/schema/test_link_spec.py b/tests/integration/schema/test_link_spec.py index e2ee046d..7e519f9b 100644 --- a/tests/integration/schema/test_link_spec.py +++ b/tests/integration/schema/test_link_spec.py @@ -1,6 +1,16 @@ +import pytest + + class TestLinkSpec: - def test_no_param(self, factory): - spec = factory.spec_from_file("data/v3.0/links.yaml") + @pytest.mark.parametrize( + "spec_file", + [ + "data/v3.0/links.yaml", + "data/v3.1/links.yaml", + ], + ) + def test_no_param(self, spec_file, factory): + spec = factory.spec_from_file(spec_file) resp = spec / "paths#/status#get#responses#default" links = resp / "links" @@ -12,8 +22,15 @@ def test_no_param(self, factory): assert "requestBody" not in link assert "parameters" not in link - def test_param(self, factory): - spec = factory.spec_from_file("data/v3.0/links.yaml") + @pytest.mark.parametrize( + "spec_file", + [ + "data/v3.0/links.yaml", + "data/v3.1/links.yaml", + ], + ) + def test_param(self, spec_file, factory): + spec = factory.spec_from_file(spec_file) resp = spec / "paths#/status/{resourceId}#get#responses#default" links = resp / "links" diff --git a/tests/integration/schema/test_path_params.py b/tests/integration/schema/test_path_params.py index 1c9e8606..34ed7d05 100644 --- a/tests/integration/schema/test_path_params.py +++ b/tests/integration/schema/test_path_params.py @@ -2,12 +2,15 @@ class TestMinimal: - - spec_paths = ["data/v3.0/path_param.yaml"] - - @pytest.mark.parametrize("spec_path", spec_paths) - def test_param_present(self, factory, spec_path): - spec = factory.spec_from_file(spec_path) + @pytest.mark.parametrize( + "spec_file", + [ + "data/v3.0/path_param.yaml", + "data/v3.1/path_param.yaml", + ], + ) + def test_param_present(self, spec_file, factory): + spec = factory.spec_from_file(spec_file) path = spec / "paths#/resource/{resId}" diff --git a/tests/integration/schema/test_spec.py b/tests/integration/schema/test_spec.py index 4fecad7e..fbca2d81 100644 --- a/tests/integration/schema/test_spec.py +++ b/tests/integration/schema/test_spec.py @@ -1,6 +1,8 @@ from base64 import b64encode import pytest +from openapi_spec_validator import openapi_v30_spec_validator +from openapi_spec_validator import openapi_v31_spec_validator from openapi_core.schema.servers import get_server_url from openapi_core.schema.specs import get_spec_url @@ -30,7 +32,9 @@ def spec_dict(self, factory): @pytest.fixture def spec(self, spec_dict, spec_uri): - return Spec.create(spec_dict, url=spec_uri) + return Spec.create( + spec_dict, url=spec_uri, validator=openapi_v30_spec_validator + ) @pytest.fixture def request_validator(self, spec): @@ -297,3 +301,59 @@ def test_spec(self, spec, spec_dict): schema_spec = spec_dict["components"]["schemas"][schema_name] assert schema.getkey("readOnly") == schema_spec.get("readOnly") assert schema.getkey("writeOnly") == schema_spec.get("writeOnly") + + +class TestWebhook: + api_key = "12345" + + @property + def api_key_encoded(self): + api_key_bytes = self.api_key.encode("utf8") + api_key_bytes_enc = b64encode(api_key_bytes) + return str(api_key_bytes_enc, "utf8") + + @pytest.fixture + def spec_uri(self): + return "file://tests/integration/data/v3.1/webhook-example.yaml" + + @pytest.fixture + def spec_dict(self, factory): + content, _ = factory.content_from_file( + "data/v3.1/webhook-example.yaml" + ) + return content + + @pytest.fixture + def spec(self, spec_dict, spec_uri): + return Spec.create( + spec_dict, + url=spec_uri, + validator=openapi_v31_spec_validator, + ) + + @pytest.fixture + def request_validator(self, spec): + return RequestValidator(spec) + + @pytest.fixture + def response_validator(self, spec): + return ResponseValidator(spec) + + def test_spec(self, spec, spec_dict): + + info = spec / "info" + info_spec = spec_dict["info"] + assert info["title"] == info_spec["title"] + assert info["version"] == info_spec["version"] + + webhooks = spec / "webhooks" + webhooks_spec = spec_dict["webhooks"] + assert webhooks["newPet"] == webhooks_spec["newPet"] + + components = spec.get("components") + if not components: + return + + schemas = components.get("schemas", {}) + for schema_name, schema in schemas.items(): + assert spec_dict["components"]["schemas"][schema_name] is not None diff --git a/tests/integration/validation/test_minimal.py b/tests/integration/validation/test_minimal.py index 74803180..bc52c41b 100644 --- a/tests/integration/validation/test_minimal.py +++ b/tests/integration/validation/test_minimal.py @@ -20,6 +20,8 @@ class TestMinimal: spec_paths = [ "data/v3.0/minimal_with_servers.yaml", "data/v3.0/minimal.yaml", + "data/v3.1/minimal_with_servers.yaml", + "data/v3.1/minimal.yaml", ] @pytest.mark.parametrize("server", servers) diff --git a/tests/integration/validation/test_petstore.py b/tests/integration/validation/test_petstore.py index 589f0bbf..fd9e9f5c 100644 --- a/tests/integration/validation/test_petstore.py +++ b/tests/integration/validation/test_petstore.py @@ -20,15 +20,21 @@ from openapi_core.unmarshalling.schemas.exceptions import InvalidSchemaValue from openapi_core.validation.exceptions import MissingRequiredHeader from openapi_core.validation.exceptions import MissingRequiredParameter -from openapi_core.validation.request import openapi_request_body_validator +from openapi_core.validation.request import openapi_v30_request_body_validator from openapi_core.validation.request import ( - openapi_request_parameters_validator, + openapi_v30_request_parameters_validator, +) +from openapi_core.validation.request import ( + openapi_v30_request_security_validator, ) -from openapi_core.validation.request import openapi_request_security_validator from openapi_core.validation.request.datatypes import Parameters -from openapi_core.validation.response import openapi_response_data_validator -from openapi_core.validation.response import openapi_response_headers_validator -from openapi_core.validation.response import openapi_response_validator +from openapi_core.validation.response import ( + openapi_v30_response_data_validator, +) +from openapi_core.validation.response import ( + openapi_v30_response_headers_validator, +) +from openapi_core.validation.response import openapi_v30_response_validator from openapi_core.validation.shortcuts import validate_request from openapi_core.validation.shortcuts import validate_response @@ -73,7 +79,9 @@ def test_get_pets(self, spec): with pytest.warns(DeprecationWarning): result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, + request, + validator=openapi_v30_request_parameters_validator, ) assert result.parameters == Parameters( @@ -85,7 +93,7 @@ def test_get_pets(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) assert result.body is None @@ -126,7 +134,9 @@ def test_get_pets_response(self, spec): with pytest.warns(DeprecationWarning): result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, + request, + validator=openapi_v30_request_parameters_validator, ) assert result.parameters == Parameters( @@ -138,7 +148,7 @@ def test_get_pets_response(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) assert result.body is None @@ -182,7 +192,9 @@ def test_get_pets_response_no_schema(self, spec): with pytest.warns(DeprecationWarning): result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, + request, + validator=openapi_v30_request_parameters_validator, ) assert result.parameters == Parameters( @@ -194,7 +206,7 @@ def test_get_pets_response_no_schema(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) assert result.body is None @@ -225,7 +237,9 @@ def test_get_pets_invalid_response(self, spec): with pytest.warns(DeprecationWarning): result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, + request, + validator=openapi_v30_request_parameters_validator, ) assert result.parameters == Parameters( @@ -237,7 +251,7 @@ def test_get_pets_invalid_response(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) assert result.body is None @@ -260,10 +274,10 @@ def test_get_pets_invalid_response(self, spec): spec, request, response, - validator=openapi_response_data_validator, + validator=openapi_v30_response_data_validator, ) - response_result = openapi_response_validator.validate( + response_result = openapi_v30_response_validator.validate( spec, request, response ) @@ -295,7 +309,9 @@ def test_get_pets_ids_param(self, spec): with pytest.warns(DeprecationWarning): result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, + request, + validator=openapi_v30_request_parameters_validator, ) assert result.parameters == Parameters( @@ -308,7 +324,7 @@ def test_get_pets_ids_param(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) assert result.body is None @@ -343,7 +359,9 @@ def test_get_pets_tags_param(self, spec): with pytest.warns(DeprecationWarning): result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, + request, + validator=openapi_v30_request_parameters_validator, ) assert result.parameters == Parameters( @@ -356,7 +374,7 @@ def test_get_pets_tags_param(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) assert result.body is None @@ -394,11 +412,11 @@ def test_get_pets_parameter_deserialization_error(self, spec): validate_request( spec, request, - validator=openapi_request_parameters_validator, + validator=openapi_v30_request_parameters_validator, ) result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) assert result.body is None @@ -423,11 +441,11 @@ def test_get_pets_wrong_parameter_type(self, spec): validate_request( spec, request, - validator=openapi_request_parameters_validator, + validator=openapi_v30_request_parameters_validator, ) result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) assert result.body is None @@ -447,11 +465,11 @@ def test_get_pets_raises_missing_required_param(self, spec): validate_request( spec, request, - validator=openapi_request_parameters_validator, + validator=openapi_v30_request_parameters_validator, ) result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) assert result.body is None @@ -476,10 +494,10 @@ def test_get_pets_empty_value(self, spec): validate_request( spec, request, - validator=openapi_request_parameters_validator, + validator=openapi_v30_request_parameters_validator, ) result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) assert result.body is None @@ -502,7 +520,9 @@ def test_get_pets_allow_empty_value(self, spec): with pytest.warns(DeprecationWarning): result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, + request, + validator=openapi_v30_request_parameters_validator, ) assert result.parameters == Parameters( @@ -514,7 +534,7 @@ def test_get_pets_allow_empty_value(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) assert result.body is None @@ -536,7 +556,9 @@ def test_get_pets_none_value(self, spec): with pytest.warns(DeprecationWarning): result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, + request, + validator=openapi_v30_request_parameters_validator, ) assert result.parameters == Parameters( @@ -548,7 +570,7 @@ def test_get_pets_none_value(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) assert result.body is None @@ -571,7 +593,9 @@ def test_get_pets_param_order(self, spec): with pytest.warns(DeprecationWarning): result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, + request, + validator=openapi_v30_request_parameters_validator, ) assert result.parameters == Parameters( @@ -584,7 +608,7 @@ def test_get_pets_param_order(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) assert result.body is None @@ -611,7 +635,9 @@ def test_get_pets_param_coordinates(self, spec): with pytest.warns(DeprecationWarning): result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, + request, + validator=openapi_v30_request_parameters_validator, ) assert result.parameters == Parameters( @@ -624,7 +650,7 @@ def test_get_pets_param_coordinates(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) assert result.body is None @@ -674,7 +700,7 @@ def test_post_birds(self, spec, spec_dict): ) result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, request, validator=openapi_v30_request_parameters_validator ) assert result.parameters == Parameters( @@ -690,7 +716,7 @@ def test_post_birds(self, spec, spec_dict): ) result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) schemas = spec_dict["components"]["schemas"] @@ -706,7 +732,7 @@ def test_post_birds(self, spec, spec_dict): assert result.body.healthy == pet_healthy result = validate_request( - spec, request, validator=openapi_request_security_validator + spec, request, validator=openapi_v30_request_security_validator ) assert result.security == {} @@ -751,7 +777,7 @@ def test_post_cats(self, spec, spec_dict): ) result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, request, validator=openapi_v30_request_parameters_validator ) assert result.parameters == Parameters( @@ -764,7 +790,7 @@ def test_post_cats(self, spec, spec_dict): ) result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) schemas = spec_dict["components"]["schemas"] @@ -819,7 +845,7 @@ def test_post_cats_boolean_string(self, spec, spec_dict): ) result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, request, validator=openapi_v30_request_parameters_validator ) assert result.parameters == Parameters( @@ -832,7 +858,7 @@ def test_post_cats_boolean_string(self, spec, spec_dict): ) result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) schemas = spec_dict["components"]["schemas"] @@ -875,7 +901,7 @@ def test_post_no_one_of_schema(self, spec, spec_dict): ) result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, request, validator=openapi_v30_request_parameters_validator ) assert result.parameters == Parameters( @@ -889,7 +915,7 @@ def test_post_no_one_of_schema(self, spec, spec_dict): with pytest.raises(InvalidSchemaValue): validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) def test_post_cats_only_required_body(self, spec, spec_dict): @@ -922,7 +948,7 @@ def test_post_cats_only_required_body(self, spec, spec_dict): ) result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, request, validator=openapi_v30_request_parameters_validator ) assert result.parameters == Parameters( @@ -935,7 +961,7 @@ def test_post_cats_only_required_body(self, spec, spec_dict): ) result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) schemas = spec_dict["components"]["schemas"] @@ -972,7 +998,7 @@ def test_post_pets_raises_invalid_mimetype(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, request, validator=openapi_v30_request_parameters_validator ) assert result.parameters == Parameters( @@ -986,7 +1012,7 @@ def test_post_pets_raises_invalid_mimetype(self, spec): with pytest.raises(MediaTypeNotFound): validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) def test_post_pets_missing_cookie(self, spec, spec_dict): @@ -1016,11 +1042,13 @@ def test_post_pets_missing_cookie(self, spec, spec_dict): with pytest.raises(MissingRequiredParameter): validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, + request, + validator=openapi_v30_request_parameters_validator, ) result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) schemas = spec_dict["components"]["schemas"] @@ -1057,11 +1085,13 @@ def test_post_pets_missing_header(self, spec, spec_dict): with pytest.raises(MissingRequiredParameter): validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, + request, + validator=openapi_v30_request_parameters_validator, ) result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) schemas = spec_dict["components"]["schemas"] @@ -1099,12 +1129,14 @@ def test_post_pets_raises_invalid_server_error(self, spec): with pytest.raises(ServerNotFound): validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, + request, + validator=openapi_v30_request_parameters_validator, ) with pytest.raises(ServerNotFound): validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) data_id = 1 @@ -1126,7 +1158,7 @@ def test_post_pets_raises_invalid_server_error(self, spec): spec, request, response, - validator=openapi_response_data_validator, + validator=openapi_v30_response_data_validator, ) def test_get_pet(self, spec): @@ -1149,7 +1181,7 @@ def test_get_pet(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, request, validator=openapi_v30_request_parameters_validator ) assert result.parameters == Parameters( @@ -1159,13 +1191,13 @@ def test_get_pet(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) assert result.body is None result = validate_request( - spec, request, validator=openapi_request_security_validator + spec, request, validator=openapi_v30_request_security_validator ) assert result.security == { @@ -1209,7 +1241,7 @@ def test_get_pet_not_found(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, request, validator=openapi_v30_request_parameters_validator ) assert result.parameters == Parameters( @@ -1219,7 +1251,7 @@ def test_get_pet_not_found(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) assert result.body is None @@ -1258,7 +1290,7 @@ def test_get_pet_wildcard(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, request, validator=openapi_v30_request_parameters_validator ) assert result.parameters == Parameters( @@ -1268,7 +1300,7 @@ def test_get_pet_wildcard(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) assert result.body is None @@ -1294,13 +1326,13 @@ def test_get_tags(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, request, validator=openapi_v30_request_parameters_validator ) assert result.parameters == Parameters() result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) assert result.body is None @@ -1334,14 +1366,14 @@ def test_post_tags_extra_body_properties(self, spec, spec_dict): ) result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, request, validator=openapi_v30_request_parameters_validator ) assert result.parameters == Parameters() with pytest.raises(InvalidSchemaValue): validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) def test_post_tags_empty_body(self, spec, spec_dict): @@ -1359,14 +1391,14 @@ def test_post_tags_empty_body(self, spec, spec_dict): ) result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, request, validator=openapi_v30_request_parameters_validator ) assert result.parameters == Parameters() with pytest.raises(InvalidSchemaValue): validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) def test_post_tags_wrong_property_type(self, spec): @@ -1384,14 +1416,14 @@ def test_post_tags_wrong_property_type(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, request, validator=openapi_v30_request_parameters_validator ) assert result.parameters == Parameters() with pytest.raises(InvalidSchemaValue): validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) def test_post_tags_additional_properties(self, spec): @@ -1412,13 +1444,13 @@ def test_post_tags_additional_properties(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, request, validator=openapi_v30_request_parameters_validator ) assert result.parameters == Parameters() result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) assert isinstance(result.body, BaseModel) @@ -1466,13 +1498,13 @@ def test_post_tags_created_now(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, request, validator=openapi_v30_request_parameters_validator ) assert result.parameters == Parameters() result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) assert isinstance(result.body, BaseModel) @@ -1521,13 +1553,13 @@ def test_post_tags_created_datetime(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, request, validator=openapi_v30_request_parameters_validator ) assert result.parameters == Parameters() result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) assert isinstance(result.body, BaseModel) @@ -1550,7 +1582,10 @@ def test_post_tags_created_datetime(self, spec): response = MockResponse(response_data, status_code=404) result = validate_response( - spec, request, response, validator=openapi_response_data_validator + spec, + request, + response, + validator=openapi_v30_response_data_validator, ) assert isinstance(result.data, BaseModel) @@ -1588,14 +1623,14 @@ def test_post_tags_created_invalid_type(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, request, validator=openapi_v30_request_parameters_validator ) assert result.parameters == Parameters() with pytest.raises(InvalidSchemaValue): validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) code = 400 @@ -1639,13 +1674,13 @@ def test_delete_tags_with_requestbody(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, request, validator=openapi_v30_request_parameters_validator ) assert result.parameters == Parameters() result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) assert isinstance(result.body, BaseModel) @@ -1667,7 +1702,7 @@ def test_delete_tags_with_requestbody(self, spec): spec, request, response, - validator=openapi_response_headers_validator, + validator=openapi_v30_response_headers_validator, ) assert result.headers == { @@ -1685,13 +1720,13 @@ def test_delete_tags_no_requestbody(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, request, validator=openapi_v30_request_parameters_validator ) assert result.parameters == Parameters() result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) assert result.body is None @@ -1707,13 +1742,13 @@ def test_delete_tags_raises_missing_required_response_header(self, spec): ) result = validate_request( - spec, request, validator=openapi_request_parameters_validator + spec, request, validator=openapi_v30_request_parameters_validator ) assert result.parameters == Parameters() result = validate_request( - spec, request, validator=openapi_request_body_validator + spec, request, validator=openapi_v30_request_body_validator ) assert result.body is None @@ -1722,7 +1757,7 @@ def test_delete_tags_raises_missing_required_response_header(self, spec): response = MockResponse(data, status_code=200) with pytest.warns(DeprecationWarning): - response_result = openapi_response_validator.validate( + response_result = openapi_v30_response_validator.validate( spec, request, response ) diff --git a/tests/integration/validation/test_read_only_write_only.py b/tests/integration/validation/test_read_only_write_only.py index 1c16cef6..e4bc1fda 100644 --- a/tests/integration/validation/test_read_only_write_only.py +++ b/tests/integration/validation/test_read_only_write_only.py @@ -5,8 +5,8 @@ from openapi_core.testing import MockRequest from openapi_core.testing import MockResponse from openapi_core.unmarshalling.schemas.exceptions import InvalidSchemaValue -from openapi_core.validation.request import openapi_request_validator -from openapi_core.validation.response import openapi_response_validator +from openapi_core.validation.request import openapi_v30_request_validator +from openapi_core.validation.response import openapi_v30_response_validator @pytest.fixture(scope="class") @@ -27,7 +27,7 @@ def test_write_a_read_only_property(self, spec): host_url="", method="POST", path="/users", data=data ) - result = openapi_request_validator.validate(spec, request) + result = openapi_v30_request_validator.validate(spec, request) assert type(result.errors[0]) == InvalidSchemaValue assert result.body is None @@ -44,7 +44,9 @@ def test_read_only_property_response(self, spec): response = MockResponse(data) - result = openapi_response_validator.validate(spec, request, response) + result = openapi_v30_response_validator.validate( + spec, request, response + ) assert not result.errors assert result.data == { @@ -66,7 +68,7 @@ def test_write_only_property(self, spec): host_url="", method="POST", path="/users", data=data ) - result = openapi_request_validator.validate(spec, request) + result = openapi_v30_request_validator.validate(spec, request) assert not result.errors assert result.body == { @@ -86,7 +88,9 @@ def test_read_a_write_only_property(self, spec): request = MockRequest(host_url="", method="POST", path="/users") response = MockResponse(data) - result = openapi_response_validator.validate(spec, request, response) + result = openapi_v30_response_validator.validate( + spec, request, response + ) assert type(result.errors[0]) == InvalidSchemaValue assert result.data is None pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy