Files
connexion/tests/api/test_responses.py
2023-10-16 23:51:21 +02:00

465 lines
15 KiB
Python

import json
from struct import unpack
import yaml
from connexion import FlaskApp
from connexion.frameworks.flask import FlaskJSONProvider
from conftest import build_app_from_fixture
def test_app(simple_app):
app_client = simple_app.test_client()
# by default the Swagger UI is enabled
swagger_ui = app_client.get("/v1.0/ui/")
assert swagger_ui.status_code == 200
assert "Swagger UI" in swagger_ui.text
# test return Swagger UI static files
swagger_icon = app_client.get("/v1.0/ui/swagger-ui.js")
assert swagger_icon.status_code == 200
post_greeting_url = app_client.post(
"/v1.0/greeting/jsantos/the/third/of/his/name", data={}
)
assert post_greeting_url.status_code == 200
assert post_greeting_url.headers.get("content-type") == "application/json"
greeting_response_url = post_greeting_url.json()
assert (
greeting_response_url["greeting"]
== "Hello jsantos thanks for the/third/of/his/name"
)
post_greeting = app_client.post("/v1.0/greeting/jsantos", data={})
assert post_greeting.status_code == 200
assert post_greeting.headers.get("content-type") == "application/json"
greeting_response = post_greeting.json()
assert greeting_response["greeting"] == "Hello jsantos"
get_bye = app_client.get("/v1.0/bye/jsantos")
assert get_bye.status_code == 200
assert get_bye.text == "Goodbye jsantos"
post_greeting = app_client.post("/v1.0/greeting/jsantos", data={})
assert post_greeting.status_code == 200
assert post_greeting.headers.get("content-type") == "application/json"
greeting_response = post_greeting.json()
assert greeting_response["greeting"] == "Hello jsantos"
def test_openapi_yaml_behind_proxy(reverse_proxied_app):
"""Verify the swagger.json file is returned with base_path updated
according to X-Original-URI header.
"""
app_client = reverse_proxied_app.test_client()
headers = {"X-Forwarded-Path": "/behind/proxy"}
swagger_ui = app_client.get("/v1.0/ui/", headers=headers)
assert swagger_ui.status_code == 200
openapi_yaml = app_client.get(
"/v1.0/" + reverse_proxied_app._spec_file, headers=headers
)
assert openapi_yaml.status_code == 200
assert openapi_yaml.headers.get("Content-Type").startswith("text/yaml")
spec = yaml.load(openapi_yaml.text, Loader=yaml.BaseLoader)
if reverse_proxied_app._spec_file == "swagger.yaml":
assert 'url: "/behind/proxy/v1.0/swagger.json"' in swagger_ui.text
assert (
spec.get("basePath") == "/behind/proxy/v1.0"
), "basePath should contains original URI"
else:
assert 'url: "/behind/proxy/v1.0/openapi.json"' in swagger_ui.text
url = spec.get("servers", [{}])[0].get("url")
assert url == "/behind/proxy/v1.0", "basePath should contains original URI"
def test_produce_decorator(simple_app):
app_client = simple_app.test_client()
get_bye = app_client.get("/v1.0/bye/jsantos")
assert get_bye.headers.get("content-type", "").startswith("text/plain")
def test_returning_response_tuple(simple_app):
app_client = simple_app.test_client()
result = app_client.get("/v1.0/response_tuple")
assert result.status_code == 201, result.text
assert result.headers.get("content-type") == "application/json"
result_data = result.json()
assert result_data == {"foo": "bar"}
def test_jsonifier(simple_app):
app_client = simple_app.test_client()
post_greeting = app_client.post("/v1.0/greeting/jsantos")
assert post_greeting.status_code == 200
assert post_greeting.headers.get("content-type") == "application/json"
greeting_response = post_greeting.json()
assert greeting_response["greeting"] == "Hello jsantos"
get_list_greeting = app_client.get("/v1.0/list/jsantos")
assert get_list_greeting.status_code == 200
assert get_list_greeting.headers.get("content-type") == "application/json"
greeting_response = get_list_greeting.json()
assert len(greeting_response) == 2
assert greeting_response[0] == "hello"
assert greeting_response[1] == "jsantos"
get_greetings = app_client.get("/v1.0/greetings/jsantos")
assert get_greetings.status_code == 200
assert get_greetings.headers.get("content-type") == "application/x.connexion+json"
greetings_response = get_greetings.json()
assert len(greetings_response) == 1
assert greetings_response["greetings"] == "Hello jsantos"
def test_not_content_response(simple_app):
app_client = simple_app.test_client()
get_no_content_response = app_client.get("/v1.0/test_no_content_response")
assert get_no_content_response.status_code == 204
assert get_no_content_response.headers.get("content-length") is None
def test_pass_through(simple_app):
app_client = simple_app.test_client()
response = app_client.get("/v1.0/multimime")
assert response.status_code == 500
detail = response.json()["detail"]
assert (
detail == "Multiple response content types are defined in the "
"operation spec, but the handler response did not specify "
"which one to return."
)
def test_empty(simple_app):
app_client = simple_app.test_client()
response = app_client.get("/v1.0/empty")
assert response.status_code == 204
assert not response.text
def test_exploded_deep_object_param_endpoint_openapi_simple(simple_openapi_app):
app_client = simple_openapi_app.test_client()
response = app_client.get("/v1.0/exploded-deep-object-param?id[foo]=bar")
assert response.status_code == 200
response_data = response.json()
assert response_data == {"foo": "bar", "foo4": "blubb"}
def test_exploded_deep_object_param_endpoint_openapi_multiple_data_types(
simple_openapi_app,
):
app_client = simple_openapi_app.test_client()
response = app_client.get(
"/v1.0/exploded-deep-object-param?id[foo]=bar&id[fooint]=2&id[fooboo]=false"
)
assert response.status_code == 200, response.text
response_data = response.json()
assert response_data == {
"foo": "bar",
"fooint": 2,
"fooboo": False,
"foo4": "blubb",
}
def test_exploded_deep_object_param_endpoint_openapi_additional_properties(
simple_openapi_app,
):
app_client = simple_openapi_app.test_client()
response = app_client.get(
"/v1.0/exploded-deep-object-param-additional-properties?id[foo]=bar&id[fooint]=2"
)
assert response.status_code == 200
response_data = response.json()
assert response_data == {"foo": "bar", "fooint": "2"}
def test_exploded_deep_object_param_endpoint_openapi_additional_properties_false(
simple_openapi_app,
):
app_client = simple_openapi_app.test_client()
response = app_client.get(
"/v1.0/exploded-deep-object-param?id[foo]=bar&id[foofoo]=barbar"
)
assert response.status_code == 400
def test_exploded_deep_object_param_endpoint_openapi_with_dots(simple_openapi_app):
app_client = simple_openapi_app.test_client()
response = app_client.get(
"/v1.0/exploded-deep-object-param-additional-properties?id[foo]=bar&id[foo.foo]=barbar"
)
assert response.status_code == 200
response_data = response.json()
assert response_data == {"foo": "bar", "foo.foo": "barbar"}
def test_nested_exploded_deep_object_param_endpoint_openapi(simple_openapi_app):
app_client = simple_openapi_app.test_client()
response = app_client.get(
"/v1.0/nested-exploded-deep-object-param?id[foo][foo2]=bar&id[foofoo]=barbar"
)
assert response.status_code == 200
response_data = response.json()
assert response_data == {
"foo": {"foo2": "bar", "foo3": "blubb"},
"foofoo": "barbar",
}
def test_redirect_endpoint(simple_app):
app_client = simple_app.test_client()
resp = app_client.get("/v1.0/test-redirect-endpoint", follow_redirects=False)
assert resp.status_code == 302
def test_redirect_response_endpoint(simple_app):
app_client = simple_app.test_client()
resp = app_client.get(
"/v1.0/test-redirect-response-endpoint", follow_redirects=False
)
assert resp.status_code == 302
def test_default_object_body(simple_app):
app_client = simple_app.test_client()
resp = app_client.post(
"/v1.0/test-default-object-body", headers={"content-type": "application/json"}
)
assert resp.status_code == 200
response = resp.json()
assert response["stack"] == {"image_version": "default_image"}
resp = app_client.post(
"/v1.0/test-default-integer-body", headers={"content-type": "application/json"}
)
assert resp.status_code == 200
response = resp.json()
assert response == 1
def test_required_body(simple_app):
app_client = simple_app.test_client()
resp = app_client.post(
"/v1.0/test-required-body", headers={"content-type": "application/json"}
)
assert resp.status_code == 400
resp = app_client.post("/v1.0/test-required-body", json={"foo": "bar"})
assert resp.status_code == 200
def test_empty_object_body(simple_app):
app_client = simple_app.test_client()
resp = app_client.post(
"/v1.0/test-empty-object-body",
json={},
)
assert resp.status_code == 200
response = resp.json()
assert response["stack"] == {}
def test_nested_additional_properties(simple_openapi_app):
app_client = simple_openapi_app.test_client()
resp = app_client.post(
"/v1.0/test-nested-additional-properties",
json={"nested": {"object": True}},
headers={"Content-Type": "application/json"},
)
assert resp.status_code == 200
response = resp.json()
assert response == {"nested": {"object": True}}
def test_custom_provider(spec):
simple_flask_app = build_app_from_fixture(
"simple", app_class=FlaskApp, spec_file=spec, validate_responses=True
)
class CustomProvider(FlaskJSONProvider):
def default(self, o):
if o.__class__.__name__ == "DummyClass":
return "cool result"
return super().default(o)
flask_app = simple_flask_app.app
flask_app.json = CustomProvider(flask_app)
app_client = simple_flask_app.test_client()
resp = app_client.get("/v1.0/custom-json-response")
assert resp.status_code == 200
response = resp.json()
assert response["theResult"] == "cool result"
def test_content_type_not_json(simple_app):
app_client = simple_app.test_client()
resp = app_client.get("/v1.0/blob-response")
assert resp.status_code == 200
try:
# AsyncApp
content = resp.content
except AttributeError:
# FlaskApp
content = resp.data
# validate binary content
text, number = unpack("!4sh", content)
assert text == b"cool"
assert number == 8
def test_maybe_blob_or_json(simple_app):
app_client = simple_app.test_client()
resp = app_client.get("/v1.0/binary-response")
assert resp.status_code == 200
assert resp.headers.get("content-type") == "application/octet-stream"
try:
# AsyncApp
content = resp.content
except AttributeError:
# FlaskApp
content = resp.data
# validate binary content
text, number = unpack("!4sh", content)
assert text == b"cool"
assert number == 8
def test_bad_operations(bad_operations_app):
# Bad operationIds in bad_operations_app should result in 501
app_client = bad_operations_app.test_client()
resp = app_client.get("/v1.0/welcome")
assert resp.status_code == 501
resp = app_client.put("/v1.0/welcome")
assert resp.status_code == 501
resp = app_client.post("/v1.0/welcome")
assert resp.status_code == 501
def test_text_request(simple_app):
app_client = simple_app.test_client()
resp = app_client.post("/v1.0/text-request", content="text")
assert resp.status_code == 200
def test_operation_handler_returns_flask_object(invalid_resp_allowed_app):
app_client = invalid_resp_allowed_app.test_client()
resp = app_client.get("/v1.0/get_non_conforming_response")
assert resp.status_code == 200
def test_post_wrong_content_type(simple_app):
app_client = simple_app.test_client()
resp = app_client.post(
"/v1.0/post_wrong_content_type",
headers={"content-type": "application/xml"},
json={"some": "data"},
)
assert resp.status_code == 415
resp = app_client.post(
"/v1.0/post_wrong_content_type",
headers={"content-type": "application/x-www-form-urlencoded"},
content="a=1&b=2",
)
assert resp.status_code == 415
resp = app_client.post(
"/v1.0/post_wrong_content_type",
headers={"content-type": "application/json"},
content="not a valid json",
)
assert (
resp.status_code == 400
), "Should return 400 when Content-Type is json but content not parsable"
def test_get_unicode_response(simple_app):
app_client = simple_app.test_client()
resp = app_client.get("/v1.0/get_unicode_response")
actualJson = {"currency": "\xa3", "key": "leena"}
assert resp.json() == actualJson
def test_get_enum_response(simple_app):
app_client = simple_app.test_client()
resp = app_client.get("/v1.0/get_enum_response")
assert resp.status_code == 200
def test_get_httpstatus_response(simple_app):
app_client = simple_app.test_client()
resp = app_client.get("/v1.0/get_httpstatus_response")
assert resp.status_code == 200
def test_get_bad_default_response(simple_app):
app_client = simple_app.test_client()
resp = app_client.get("/v1.0/get_bad_default_response/200")
assert resp.status_code == 200
resp = app_client.get("/v1.0/get_bad_default_response/202")
assert resp.status_code == 500
def test_streaming_response(simple_app):
app_client = simple_app.test_client()
resp = app_client.get("/v1.0/get_streaming_response")
assert resp.status_code == 200, resp.text
def test_oneof(simple_openapi_app):
app_client = simple_openapi_app.test_client()
post_greeting = app_client.post(
"/v1.0/oneof_greeting",
json={"name": 3},
)
assert post_greeting.status_code == 200
assert post_greeting.headers.get("content-type") == "application/json"
greeting_response = post_greeting.json()
assert greeting_response["greeting"] == "Hello 3"
post_greeting = app_client.post(
"/v1.0/oneof_greeting",
json={"name": True},
)
assert post_greeting.status_code == 200
assert post_greeting.headers.get("content-type") == "application/json"
greeting_response = post_greeting.json()
assert greeting_response["greeting"] == "Hello True"
post_greeting = app_client.post(
"/v1.0/oneof_greeting",
json={"name": "jsantos"},
)
assert post_greeting.status_code == 400