From 17ba4690ed7dd0f488dd3446894239073cd41c07 Mon Sep 17 00:00:00 2001 From: jacob Date: Mon, 10 Jun 2019 13:46:48 +0800 Subject: [PATCH] Test: Add test cases --- tests/conftest.py | 10 + tests/{test_types.py => test_fields.py} | 10 +- tests/test_openapi.py | 15 -- tests/test_swagger.py | 296 ++++++++++++++++++++++++ 4 files changed, 309 insertions(+), 22 deletions(-) create mode 100644 tests/conftest.py rename tests/{test_types.py => test_fields.py} (73%) delete mode 100644 tests/test_openapi.py create mode 100644 tests/test_swagger.py diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..48d307e --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,10 @@ +import pytest +from sanic import Sanic +from sanic_openapi import swagger_blueprint + + +@pytest.fixture() +def app(): + app = Sanic('test') + app.blueprint(swagger_blueprint) + return app diff --git a/tests/test_types.py b/tests/test_fields.py similarity index 73% rename from tests/test_types.py rename to tests/test_fields.py index f657c4e..e4c2470 100644 --- a/tests/test_types.py +++ b/tests/test_fields.py @@ -1,26 +1,22 @@ from json import loads as json_loads -from sanic import Sanic from sanic.response import json -from sanic_openapi import doc, swagger_blueprint +from sanic_openapi import doc # ------------------------------------------------------------ # # GET # ------------------------------------------------------------ # -def test_list_default(): - app = Sanic("test_get") - - app.blueprint(swagger_blueprint) +def test_list_default(app): @app.put("/test") @doc.consumes(doc.List(int, description="All the numbers"), location="body") def test(request): return json({"test": True}) - request, response = app.test_client.get("/swagger/swagger.json") + _, response = app.test_client.get("/swagger/swagger.json") response_schema = json_loads(response.body.decode()) parameter = response_schema["paths"]["/test"]["put"]["parameters"][0] diff --git a/tests/test_openapi.py b/tests/test_openapi.py deleted file mode 100644 index 3b7313a..0000000 --- a/tests/test_openapi.py +++ /dev/null @@ -1,15 +0,0 @@ -from sanic import Sanic - -from sanic_openapi import swagger_blueprint - -# ------------------------------------------------------------ # -# GET -# ------------------------------------------------------------ # - - -def test_get_docs(): - app = Sanic("test_get") - app.blueprint(swagger_blueprint) - - request, response = app.test_client.get("/swagger/swagger.json") - assert response.status == 200 diff --git a/tests/test_swagger.py b/tests/test_swagger.py new file mode 100644 index 0000000..0ca2c93 --- /dev/null +++ b/tests/test_swagger.py @@ -0,0 +1,296 @@ +import pytest +from sanic import Blueprint +from sanic.constants import HTTP_METHODS +from sanic.response import text +from sanic.views import CompositionView, HTTPMethodView + +METHODS = [method.lower() for method in HTTP_METHODS] + + +class SimpleView(HTTPMethodView): + def get(self, request): + return text("I am get method") + + def post(self, request): + return text("I am post method") + + def put(self, request): + return text("I am put method") + + def patch(self, request): + return text("I am patch method") + + def delete(self, request): + return text("I am delete method") + + def head(self, request): + return text("I am head method") + + def options(self, request): + return text("I am options method") + + +def get_handler(request): + return text('I am a get method') + +view = CompositionView() +view.add(['GET'], get_handler) +view.add(['POST', 'PUT'], lambda request: text('I am a post/put method')) + + +def test_swagger_endpoint(app): + _, response = app.test_client.get("/swagger/") + assert response.status == 200 + assert response.content_type == "text/html" + + +def test_swagger_endpoint_redirect(app): + _, response = app.test_client.get("/swagger") + assert response.status == 200 + assert response.content_type == "text/html" + assert len(response.history) == 1 + assert response.history[0].status == 302 + assert str(response.history[0].url).endswith("/swagger") + + +def test_swagger_json(app): + _, 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.get("swagger") == "2.0" + assert swagger_json.get("definitions") == {} + assert swagger_json.get("tags") == [] + assert swagger_json.get("paths") == {} + + +@pytest.mark.parametrize("method", METHODS) +def test_document_route(app, method): + @app.route("/", methods=[method]) + 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"] == { + "/": { + method: { + "operationId": "test", + "consumes": ["application/json"], + "produces": ["application/json"], + "parameters": [], + "responses": {"200": {}}, + } + } + } + + +@pytest.mark.parametrize("method", METHODS) +def test_document_blueprint_route(app, method): + + bp = Blueprint("test") + + @bp.route("/", methods=[method]) + def test(request): + return text("test") + + app.blueprint(bp) + + _, 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 swagger_json["paths"] == { + "/": { + method: { + "operationId": "test.test", + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["test"], + "parameters": [], + "responses": {"200": {}}, + } + } + } + + +def test_class_based_view(app): + """ + In sanic_openapi/swagger.py#n124, class based view will not document endpoint with options method. + """ + app.add_route(SimpleView.as_view(), "/") + + _, response = app.test_client.get("/swagger/swagger.json") + assert response.status == 200 + assert response.content_type == "application/json" + + swagger_json = response.json + methods = METHODS.copy() + methods.remove("options") + + assert sorted(set(methods)) == sorted(set(swagger_json["paths"]["/"].keys())) + + +def test_blueprint_class_based_view(app): + + bp = Blueprint("test") + bp.add_route(SimpleView.as_view(), "/") + app.blueprint(bp) + + _, response = app.test_client.get("/swagger/swagger.json") + assert response.status == 200 + assert response.content_type == "application/json" + + swagger_json = response.json + methods = METHODS.copy() + methods.remove("options") + + assert sorted(set(methods)) == sorted(set(swagger_json["paths"]["/"].keys())) + assert {"name": "test"} in swagger_json["tags"] + + +def test_document_compositionview(app): + app.add_route(view, '/') + + _, response = app.test_client.get("/swagger/swagger.json") + assert response.status == 200 + assert response.content_type == "application/json" + + swagger_json = response.json + assert set(swagger_json["paths"]["/"].keys()) == set(['get', 'post', 'put']) + assert {"name": "test"} in swagger_json["tags"] + + +@pytest.mark.skip(reason='Not support now.') +def test_document_blueprint_compositionview(app): + + bp = Blueprint('test') + bp.add_route(view, '/') + + _, response = app.test_client.get("/swagger/swagger.json") + assert response.status == 200 + assert response.content_type == "application/json" + + swagger_json = response.json + assert set(swagger_json["paths"]["/"].keys()) == set(['get', 'post', 'put']) + + +def test_swagger_ui_config(app): + + _, response = app.test_client.get("/swagger/swagger-config") + assert response.status == 200 + assert response.content_type == "application/json" + + swagger_config = response.json + assert swagger_config == {} + + swagger_ui_configuration = { + "validatorUrl": None, # Disable Swagger validator + "displayRequestDuration": True, + "docExpansion": "full", + } + app.config.SWAGGER_UI_CONFIGURATION = swagger_ui_configuration + + _, response = app.test_client.get("/swagger/swagger-config") + assert response.status == 200 + assert response.content_type == "application/json" + + swagger_config = response.json + assert swagger_config == swagger_ui_configuration + + +@pytest.mark.parametrize( + "configs", + [ + { + "API_HOST": "http://0.0.0.0", + "API_BASEPATH": "/api", + "API_VERSION": "0.1.0", + "API_TITLE": "Sanic OpenAPI test", + "API_DESCRIPTION": "The API doc", + "API_TERMS_OF_SERVICE": "Use with caution!", + "API_CONTACT_EMAIL": "foo@bar.com", + "API_LICENSE_NAME": "MIT", + "API_LICENSE_URL": "https://choosealicense.com/licenses/mit/", + }, + { + "API_HOST": 'http://test.sanic-openapi', + "API_BASEPATH": '/api_test', + "API_VERSION": None, + "API_TITLE": None, + "API_DESCRIPTION": None, + "API_TERMS_OF_SERVICE": None, + "API_CONTACT_EMAIL": None, + "API_LICENSE_NAME": None, + "API_LICENSE_URL": None, + }, + ], +) +def test_configs(app, configs): + + app.config.update(configs) + + _, 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['host'] == configs['API_HOST'] + assert swagger_json['basePath'] == configs['API_BASEPATH'] + + info = swagger_json.get("info") + assert isinstance(info, dict) + assert info["version"] == configs["API_VERSION"] + assert info["title"] == configs["API_TITLE"] + assert info["description"] == configs["API_DESCRIPTION"] + assert info["termsOfService"] == configs["API_TERMS_OF_SERVICE"] + assert info["contact"]["email"] == configs["API_CONTACT_EMAIL"] + assert info["license"]["name"] == configs["API_LICENSE_NAME"] + assert info["license"]["url"] == configs["API_LICENSE_URL"] + + +@pytest.mark.skip(reason="The uri '/static' still in swagger.json now. This might already fixed by #80.") +def test_skip_static_file(app): + app.static('/static', __file__) + + _, response = app.test_client.get("/swagger/swagger.json") + assert response.status == 200 + assert response.content_type == "application/json" + + swagger_json = response.json + assert '/static' not in swagger_json['paths'] + + +def test_uri_parsed(app): + + @app.get('/') + def test(request, name): + return text(name) + + _, response = app.test_client.get("/swagger/swagger.json") + assert response.status == 200 + assert response.content_type == "application/json" + + swagger_json = response.json + assert '/{name}' in swagger_json['paths'] + + +def test_ignore_options_route(app): + + @app.options('/') + 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']['/'] == {}