Skip to content

Commit

Permalink
Generate examples when mocked, using JSF library.
Browse files Browse the repository at this point in the history
  • Loading branch information
mjp4 committed Feb 9, 2024
1 parent f8f461c commit 97f12d4
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 5 deletions.
6 changes: 5 additions & 1 deletion connexion/operations/openapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from connexion.datastructures import MediaTypeDict
from connexion.operations.abstract import AbstractOperation
from connexion.uri_parsing import OpenAPIURIParser
from connexion.utils import deep_get
from connexion.utils import deep_get, generate_example

logger = logging.getLogger("connexion.operations.openapi3")

Expand Down Expand Up @@ -210,6 +210,10 @@ def _nested_example(self, schema):
try:
# Recurse if schema is an array
return [self._nested_example(schema["items"])]
except KeyError:
pass
try:
return generate_example(schema)
except KeyError:
raise

Expand Down
6 changes: 5 additions & 1 deletion connexion/operations/swagger2.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from connexion.exceptions import InvalidSpecification
from connexion.operations.abstract import AbstractOperation
from connexion.uri_parsing import Swagger2URIParser
from connexion.utils import deep_get
from connexion.utils import deep_get, generate_example

logger = logging.getLogger("connexion.operations.swagger2")

Expand Down Expand Up @@ -232,6 +232,10 @@ def _nested_example(self, schema):
try:
# Recurse if schema is an array
return [self._nested_example(schema["items"])]
except KeyError:
pass
try:
return generate_example(schema)
except KeyError:
raise

Expand Down
6 changes: 6 additions & 0 deletions connexion/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import typing as t

import yaml
from jsf import JSF
from starlette.routing import compile_path

from connexion.exceptions import TypeValidationError
Expand Down Expand Up @@ -512,3 +513,8 @@ def sort_apis_by_basepath(apis: t.List["API"]) -> t.List["API"]:
:return: List of APIs sorted by basepath
"""
return sort_routes(apis, key=lambda api: api.base_path or "/")


def generate_example(schema):
faker = JSF(schema)
return faker.generate()
4 changes: 3 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,13 @@ a2wsgi = { version = ">= 1.7", optional = true }
flask = { version = ">= 2.2", extras = ["async"], optional = true }
swagger-ui-bundle = { version = ">= 1.1.0", optional = true }
uvicorn = { version = ">= 0.17.6", extras = ["standard"], optional = true }
jsf = { version = ">=0.10.0", optional = true }

[tool.poetry.extras]
flask = ["a2wsgi", "flask"]
swagger-ui = ["swagger-ui-bundle"]
uvicorn = ["uvicorn"]
mock = ["jsf"]

[tool.poetry.group.tests.dependencies]
pre-commit = "~2.21.0"
Expand Down Expand Up @@ -106,4 +108,4 @@ exclude_lines = [

[[tool.mypy.overrides]]
module = "referencing.jsonschema.*"
follow_imports = "skip"
follow_imports = "skip"
6 changes: 4 additions & 2 deletions tests/test_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,8 @@ def test_mock_resolver_no_example_nested_in_object():

response, status_code = resolver.mock_operation(operation)
assert status_code == 200
assert response == "No example response was defined."
assert isinstance(response, dict)
assert isinstance(response["foo"], str)


def test_mock_resolver_no_example_nested_in_list_openapi():
Expand Down Expand Up @@ -256,7 +257,8 @@ def test_mock_resolver_no_example_nested_in_list_openapi():

response, status_code = resolver.mock_operation(operation)
assert status_code == 202
assert response == "No example response was defined."
assert isinstance(response, list)
assert all(isinstance(c, str) for c in response)


def test_mock_resolver_no_examples():
Expand Down
144 changes: 144 additions & 0 deletions tests/test_mock2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
from re import fullmatch

from connexion.utils import generate_example


def test_generate_example_string():

schema = {
"type": "string",
}

example = generate_example(schema)

assert isinstance(example, str)


def test_generate_example_integer():

schema = {
"type": "integer",
}

example = generate_example(schema)

assert isinstance(example, int)


def test_generate_example_number():

schema = {
"type": "number",
}

example = generate_example(schema)

assert isinstance(example, float)


def test_generate_example_boolean():

schema = {
"type": "boolean",
}

example = generate_example(schema)

assert isinstance(example, bool)


def test_generate_example_integer_minimum():

schema = {
"type": "integer",
"minimum": 4,
}

example = generate_example(schema)

assert example >= schema["minimum"] and isinstance(example, int)


def test_generate_example_integer_maximum():

schema = {
"type": "integer",
"maximum": 17,
}

example = generate_example(schema)

assert example <= schema["maximum"] and isinstance(example, int)


def test_generate_example_integer_exclusive_minimum():

schema = {
"type": "integer",
"minimum": 4,
"exclusiveMinimum": True,
}
example = generate_example(schema)

assert example > schema["minimum"] and isinstance(example, int)


def test_generate_example_integer_exclusive_maximum():

schema = {
"type": "integer",
"maximum": 17,
"exclusiveMaximum": True,
}

example = generate_example(schema)

assert example < schema["maximum"] and isinstance(example, int)


def test_generate_example_string_regular_expression():

pattern = "^\d{3}-\d{2}-\d{4}$"

schema = {
"type": "string",
"pattern": pattern,
}

example = generate_example(schema)

assert fullmatch(pattern, example) != None and isinstance(example, str)


def test_generate_example_string_maximum():

schema = {
"type": "string",
"maxLength": 20,
}

example = generate_example(schema)

assert isinstance(example, str) and len(example) <= schema["maxLength"]


def test_generate_example_string_minimum():

schema = {
"type": "string",
"minLength": 20,
}

example = generate_example(schema)

assert isinstance(example, str) and len(example) >= schema["minLength"]


def test_generate_example_enum():

schema = {"type": "string", "enum": ["asc", "desc"]}

example = generate_example(schema)

assert isinstance(example, str)
assert example == "asc" or example == "desc"

0 comments on commit 97f12d4

Please sign in to comment.