Skip to content

Commit

Permalink
Merge pull request sanic-org#109 from chenjr0719/extend_test_cases
Browse files Browse the repository at this point in the history
Extend test cases
  • Loading branch information
ahopkins committed Jun 20, 2019
2 parents 0d3ddb8 + 5706094 commit cbf0f5b
Show file tree
Hide file tree
Showing 11 changed files with 883 additions and 56 deletions.
6 changes: 5 additions & 1 deletion .travis.yml
Expand Up @@ -9,8 +9,12 @@ matrix:
- python: 3.7
dist: xenial
sudo: true
install: pip install tox-travis
install:
- pip install tox-travis
- pip install codecov
script: tox
after_success:
- codecov
deploy:
provider: pypi
user: channelcat
Expand Down
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -4,6 +4,7 @@
[![PyPI](https://img.shields.io/pypi/v/sanic-openapi.svg)](https://pypi.python.org/pypi/sanic-openapi/)
[![PyPI](https://img.shields.io/pypi/pyversions/sanic-openapi.svg)](https://pypi.python.org/pypi/sanic-openapi/)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/python/black)
[![codecov](https://codecov.io/gh/huge-success/sanic-openapi/branch/master/graph/badge.svg)](https://codecov.io/gh/huge-success/sanic-openapi)

Give your Sanic API a UI and OpenAPI documentation, all for the price of free!

Expand Down
2 changes: 1 addition & 1 deletion sanic_openapi/__init__.py
@@ -1,4 +1,4 @@
from .swagger import blueprint as swagger_blueprint
from .swagger import swagger_blueprint

__version__ = "0.5.3"
__all__ = ["swagger_blueprint"]
2 changes: 2 additions & 0 deletions sanic_openapi/doc.py
Expand Up @@ -100,6 +100,8 @@ def serialize(self):
items = Tuple(self.items).serialize()
elif self.items:
items = serialize_schema(self.items[0])
else:
items = []
return {"type": "array", "items": items, **super().serialize()}


Expand Down
23 changes: 14 additions & 9 deletions sanic_openapi/swagger.py
Expand Up @@ -10,20 +10,20 @@
from .doc import route as doc_route
from .doc import route_specs, serialize_schema

blueprint = Blueprint("swagger", url_prefix="swagger")
swagger_blueprint = Blueprint("swagger", url_prefix="/swagger")

dir_path = os.path.dirname(os.path.realpath(__file__))
dir_path = os.path.abspath(dir_path + "/ui")


# Redirect "/swagger" to "/swagger/"
@blueprint.route("", strict_slashes=True)
@swagger_blueprint.route("", strict_slashes=True)
def index(request):
return redirect("{}/".format(blueprint.url_prefix))
return redirect("{}/".format(swagger_blueprint.url_prefix))


blueprint.static("/", dir_path + "/index.html", strict_slashes=True)
blueprint.static("/", dir_path)
swagger_blueprint.static("/", dir_path + "/index.html", strict_slashes=True)
swagger_blueprint.static("/", dir_path)


_spec = {}
Expand All @@ -38,7 +38,7 @@ def remove_nulls(dictionary, deep=True):
}


@blueprint.listener("before_server_start")
@swagger_blueprint.listener("before_server_start")
def build_spec(app, loop):
_spec["swagger"] = "2.0"
_spec["info"] = {
Expand Down Expand Up @@ -95,7 +95,12 @@ def build_spec(app, loop):
paths = {}
for uri, route in app.router.routes_all.items():

if "static" in route.name:
# Ignore routes under swagger blueprint
if route.uri.startswith(swagger_blueprint.url_prefix):
continue

# route.name will be None when using class based view
if route.name and "static" in route.name:
# TODO: add static flag in sanic routes
continue

Expand Down Expand Up @@ -240,13 +245,13 @@ def build_spec(app, loop):
_spec["paths"] = paths


@blueprint.route("/swagger.json")
@swagger_blueprint.route("/swagger.json")
@doc_route(exclude=True)
def spec(request):
return json(_spec)


@blueprint.route("/swagger-config")
@swagger_blueprint.route("/swagger-config")
def config(request):
options = {}

Expand Down
15 changes: 15 additions & 0 deletions tests/conftest.py
@@ -0,0 +1,15 @@
import pytest
from sanic import Sanic

import sanic_openapi


@pytest.fixture()
def app():
app = Sanic("test")
app.blueprint(sanic_openapi.swagger_blueprint)
yield app

# Clean up
sanic_openapi.swagger.definitions = {}
sanic_openapi.swagger._spec = {}
186 changes: 186 additions & 0 deletions tests/test_decorators.py
@@ -0,0 +1,186 @@
import pytest
from sanic.response import json, text

from sanic_openapi import doc
from sanic_openapi.doc import RouteField


@pytest.mark.parametrize(
"route_kwargs, route_fields",
[
({"summary": "test"}, {"summary": "test"}),
({"description": "test"}, {"description": "test"}),
({"consumes": [RouteField(str)]}, {}),
({"produces": RouteField(str)}, {}),
({"consumes_content_type": ["text/html"]}, {"consumes": ["text/html"]}),
({"produces_content_type": ["text/html"]}, {"produces": ["text/html"]}),
({"response": [{400, RouteField(str)}]}, {}),
],
)
def test_route(app, route_kwargs, route_fields):
@app.post("/")
@doc.route(**route_kwargs)
def test(request):
return text("")

_, response = app.test_client.get("/swagger/swagger.json")
assert response.status == 200
assert response.content_type == "application/json"

swagger_json = response.json
assert all(
item in swagger_json["paths"]["/"]["post"].items()
for item in route_fields.items()
)


@pytest.mark.parametrize("exclude", [True, False])
def test_exclude(app, exclude):
@app.get("/")
@doc.exclude(exclude)
def test(request):
return text("test")

_, response = app.test_client.get("/swagger/swagger.json")
assert response.status == 200
assert response.content_type == "application/json"

swagger_json = response.json
assert not ("/" in swagger_json["paths"]) == exclude


def test_summary(app):
@app.get("/")
@doc.summary("Test route")
def test(request):
return text("test")

_, response = app.test_client.get("/swagger/swagger.json")
assert response.status == 200
assert response.content_type == "application/json"

swagger_json = response.json
assert swagger_json["paths"]["/"]["get"]["summary"] == "Test route"


def test_description(app):
@app.get("/")
@doc.description("This is test route")
def test(request):
return text("test")

_, response = app.test_client.get("/swagger/swagger.json")
assert response.status == 200
assert response.content_type == "application/json"

swagger_json = response.json
assert swagger_json["paths"]["/"]["get"]["description"] == "This is test route"


class TestSchema:
id = int


@pytest.mark.parametrize(
"consumes_args, consumes_kwargs, parameters",
[
([], {"location": "body", "required": False}, []),
(
[doc.String()],
{"location": "header", "required": True, "content_type": "text/html"},
[{"type": "string", "required": True, "in": "header", "name": None}],
),
(
[TestSchema],
{"location": "body", "required": True, "content_type": "application/json"},
[
{
"type": "object",
"required": True,
"in": "body",
"name": "body",
"schema": {"$ref": "#/definitions/TestSchema"},
}
],
),
],
)
def test_consumes(app, consumes_args, consumes_kwargs, parameters):
@app.post("/")
@doc.consumes(*consumes_args, **consumes_kwargs)
def test(request):
return text("test")

_, response = app.test_client.get("/swagger/swagger.json")
assert response.status == 200
assert response.content_type == "application/json"

swagger_json = response.json
assert swagger_json["paths"]["/"]["post"]["parameters"] == parameters


@pytest.mark.parametrize(
"produces_args, produces_kwargs, responses",
[
([], {}, {"200": {}}),
([doc.String], {}, {"200": {"schema": {"type": "string"}}}),
(
[TestSchema],
{"content_type": "application/json"},
{"200": {"schema": {"$ref": "#/definitions/TestSchema", "type": "object"}}},
),
],
)
def test_produces(app, produces_args, produces_kwargs, responses):
@app.post("/")
@doc.produces(*produces_args, **produces_kwargs)
def test(request):
return text("test")

_, response = app.test_client.get("/swagger/swagger.json")
assert response.status == 200
assert response.content_type == "application/json"

swagger_json = response.json
assert swagger_json["paths"]["/"]["post"]["responses"] == responses


@pytest.mark.parametrize(
"response_args, responses",
[
([], {'200': {}}),
(
[201, {}],
{"200": {}, "201": {"schema": {"type": "object", "properties": {}}}},
),
],
)
def test_response(app, response_args, responses):
@app.post("/")
@doc.response(*response_args)
def test(request):
return text("test")

_, response = app.test_client.get("/swagger/swagger.json")
assert response.status == 200
assert response.content_type == "application/json"

swagger_json = response.json
print(swagger_json["paths"]["/"]["post"]["responses"])
assert swagger_json["paths"]["/"]["post"]["responses"] == responses


@pytest.mark.skip(reason='Break tests due to global variables.')
def test_tag(app):
@app.get('/')
@doc.tag('test')
def test(request):
return text('test')

_, response = app.test_client.get("/swagger/swagger.json")
assert response.status == 200
assert response.content_type == "application/json"

swagger_json = response.json
assert {'name': 'test'} in swagger_json['tags']
assert 'test' in swagger_json["paths"]["/"]["get"]['tags']

0 comments on commit cbf0f5b

Please sign in to comment.