oggit/packages/flask-restx/opengnsys-flask-restx-1.3.0/tests/legacy/test_api_legacy.py

389 lines
13 KiB
Python

import flask
import pytest
from json import dumps, JSONEncoder
from flask import Blueprint, redirect, views
from werkzeug.exceptions import HTTPException, Unauthorized, BadRequest
import flask_restx as restx
# Add a dummy Resource to verify that the app is properly set.
class HelloWorld(restx.Resource):
def get(self):
return {}
class APITest(object):
def test_unauthorized_no_challenge_by_default(self, api, mocker):
response = mocker.Mock()
response.headers = {}
response = api.unauthorized(response)
assert "WWW-Authenticate" not in response.headers
@pytest.mark.api(serve_challenge_on_401=True)
def test_unauthorized(self, api, mocker):
response = mocker.Mock()
response.headers = {}
response = api.unauthorized(response)
assert response.headers["WWW-Authenticate"] == 'Basic realm="flask-restx"'
@pytest.mark.options(HTTP_BASIC_AUTH_REALM="Foo")
@pytest.mark.api(serve_challenge_on_401=True)
def test_unauthorized_custom_realm(self, api, mocker):
response = mocker.Mock()
response.headers = {}
response = api.unauthorized(response)
assert response.headers["WWW-Authenticate"] == 'Basic realm="Foo"'
def test_handle_error_401_no_challenge_by_default(self, api):
resp = api.handle_error(Unauthorized())
assert resp.status_code == 401
assert "WWW-Autheneticate" not in resp.headers
@pytest.mark.api(serve_challenge_on_401=True)
def test_handle_error_401_sends_challege_default_realm(self, api):
exception = HTTPException()
exception.code = 401
exception.data = {"foo": "bar"}
resp = api.handle_error(exception)
assert resp.status_code == 401
assert resp.headers["WWW-Authenticate"] == 'Basic realm="flask-restx"'
@pytest.mark.api(serve_challenge_on_401=True)
@pytest.mark.options(HTTP_BASIC_AUTH_REALM="test-realm")
def test_handle_error_401_sends_challege_configured_realm(self, api):
resp = api.handle_error(Unauthorized())
assert resp.status_code == 401
assert resp.headers["WWW-Authenticate"] == 'Basic realm="test-realm"'
def test_handle_error_does_not_swallow_exceptions(self, api):
exception = BadRequest("x")
resp = api.handle_error(exception)
assert resp.status_code == 400
assert resp.get_data() == b'{"message": "x"}\n'
def test_api_representation(self, api):
@api.representation("foo")
def foo():
pass
assert api.representations["foo"] == foo
def test_api_base(self, app):
api = restx.Api(app)
assert api.urls == {}
assert api.prefix == ""
assert api.default_mediatype == "application/json"
def test_api_delayed_initialization(self, app, client):
api = restx.Api()
api.add_resource(HelloWorld, "/", endpoint="hello")
api.init_app(app)
assert client.get("/").status_code == 200
def test_api_prefix(self, app):
api = restx.Api(app, prefix="/foo")
assert api.prefix == "/foo"
@pytest.mark.api(serve_challenge_on_401=True)
def test_handle_auth(self, api):
resp = api.handle_error(Unauthorized())
assert resp.status_code == 401
expected_data = dumps({"message": Unauthorized.description}) + "\n"
assert resp.data.decode() == expected_data
assert "WWW-Authenticate" in resp.headers
def test_media_types(self, app):
api = restx.Api(app)
with app.test_request_context("/foo", headers={"Accept": "application/json"}):
assert api.mediatypes() == ["application/json"]
def test_media_types_method(self, app, mocker):
api = restx.Api(app)
with app.test_request_context(
"/foo", headers={"Accept": "application/xml; q=0.5"}
):
assert api.mediatypes_method()(mocker.Mock()) == [
"application/xml",
"application/json",
]
def test_media_types_q(self, app):
api = restx.Api(app)
with app.test_request_context(
"/foo",
headers={"Accept": "application/json; q=1.0, application/xml; q=0.5"},
):
assert api.mediatypes() == ["application/json", "application/xml"]
def test_decorator(self, mocker, mock_app):
def return_zero(func):
return 0
view = mocker.Mock()
api = restx.Api(mock_app)
api.decorators.append(return_zero)
api.output = mocker.Mock()
api.add_resource(view, "/foo", endpoint="bar")
mock_app.add_url_rule.assert_called_with("/foo", view_func=0)
def test_add_resource_endpoint(self, app, mocker):
view = mocker.Mock(**{"as_view.return_value.__name__": str("test_view")})
api = restx.Api(app)
api.add_resource(view, "/foo", endpoint="bar")
view.as_view.assert_called_with("bar", api)
def test_add_two_conflicting_resources_on_same_endpoint(self, app):
api = restx.Api(app)
class Foo1(restx.Resource):
def get(self):
return "foo1"
class Foo2(restx.Resource):
def get(self):
return "foo2"
api.add_resource(Foo1, "/foo", endpoint="bar")
with pytest.raises(ValueError):
api.add_resource(Foo2, "/foo/toto", endpoint="bar")
def test_add_the_same_resource_on_same_endpoint(self, app):
api = restx.Api(app)
class Foo1(restx.Resource):
def get(self):
return "foo1"
api.add_resource(Foo1, "/foo", endpoint="bar")
api.add_resource(Foo1, "/foo/toto", endpoint="blah")
with app.test_client() as client:
foo1 = client.get("/foo")
assert foo1.data == b'"foo1"\n'
foo2 = client.get("/foo/toto")
assert foo2.data == b'"foo1"\n'
def test_add_resource(self, mocker, mock_app):
api = restx.Api(mock_app)
api.output = mocker.Mock()
api.add_resource(views.MethodView, "/foo")
mock_app.add_url_rule.assert_called_with("/foo", view_func=api.output())
def test_add_resource_kwargs(self, mocker, mock_app):
api = restx.Api(mock_app)
api.output = mocker.Mock()
api.add_resource(views.MethodView, "/foo", defaults={"bar": "baz"})
mock_app.add_url_rule.assert_called_with(
"/foo", view_func=api.output(), defaults={"bar": "baz"}
)
def test_add_resource_forward_resource_class_parameters(self, app, client):
api = restx.Api(app)
class Foo(restx.Resource):
def __init__(self, api, *args, **kwargs):
self.one = args[0]
self.two = kwargs["secret_state"]
super(Foo, self).__init__(api, *args, **kwargs)
def get(self):
return "{0} {1}".format(self.one, self.two)
api.add_resource(
Foo,
"/foo",
resource_class_args=("wonderful",),
resource_class_kwargs={"secret_state": "slurm"},
)
foo = client.get("/foo")
assert foo.data == b'"wonderful slurm"\n'
def test_output_unpack(self, app):
def make_empty_response():
return {"foo": "bar"}
api = restx.Api(app)
with app.test_request_context("/foo"):
wrapper = api.output(make_empty_response)
resp = wrapper()
assert resp.status_code == 200
assert resp.data.decode() == '{"foo": "bar"}\n'
def test_output_func(self, app):
def make_empty_resposne():
return flask.make_response("")
api = restx.Api(app)
with app.test_request_context("/foo"):
wrapper = api.output(make_empty_resposne)
resp = wrapper()
assert resp.status_code == 200
assert resp.data.decode() == ""
def test_resource(self, app, mocker):
resource = restx.Resource()
resource.get = mocker.Mock()
with app.test_request_context("/foo"):
resource.dispatch_request()
def test_resource_resp(self, app, mocker):
resource = restx.Resource()
resource.get = mocker.Mock()
with app.test_request_context("/foo"):
resource.get.return_value = flask.make_response("")
resource.dispatch_request()
def test_resource_text_plain(self, app):
def text(data, code, headers=None):
return flask.make_response(str(data))
class Foo(restx.Resource):
representations = {
"text/plain": text,
}
def get(self):
return "hello"
with app.test_request_context("/foo", headers={"Accept": "text/plain"}):
resource = Foo(None)
resp = resource.dispatch_request()
assert resp.data.decode() == "hello"
@pytest.mark.request_context("/foo")
def test_resource_error(self, app):
resource = restx.Resource()
with pytest.raises(AssertionError):
resource.dispatch_request()
@pytest.mark.request_context("/foo", method="HEAD")
def test_resource_head(self, app):
resource = restx.Resource()
with pytest.raises(AssertionError):
resource.dispatch_request()
def test_endpoints(self, app):
api = restx.Api(app)
api.add_resource(HelloWorld, "/ids/<int:id>", endpoint="hello")
with app.test_request_context("/foo"):
assert api._has_fr_route() is False
with app.test_request_context("/ids/3"):
assert api._has_fr_route() is True
def test_url_for(self, app):
api = restx.Api(app)
api.add_resource(HelloWorld, "/ids/<int:id>")
with app.test_request_context("/foo"):
assert api.url_for(HelloWorld, id=123) == "/ids/123"
def test_url_for_with_blueprint(self, app):
"""Verify that url_for works when an Api object is mounted on a
Blueprint.
"""
api_bp = Blueprint("api", __name__)
api = restx.Api(api_bp)
api.add_resource(HelloWorld, "/foo/<string:bar>")
app.register_blueprint(api_bp)
with app.test_request_context("/foo"):
assert api.url_for(HelloWorld, bar="baz") == "/foo/baz"
def test_exception_header_forwarding_doesnt_duplicate_headers(self, api):
"""Test that HTTPException's headers do not add a duplicate
Content-Length header
https://github.com/flask-restful/flask-restful/issues/534
"""
r = api.handle_error(BadRequest())
assert len(r.headers.getlist("Content-Length")) == 1
def test_read_json_settings_from_config(self, app, client):
class TestConfig(object):
RESTX_JSON = {"indent": 2, "sort_keys": True, "separators": (", ", ": ")}
app.config.from_object(TestConfig)
api = restx.Api(app)
class Foo(restx.Resource):
def get(self):
return {"foo": "bar", "baz": "qux"}
api.add_resource(Foo, "/foo")
data = client.get("/foo").data
expected = b'{\n "baz": "qux", \n "foo": "bar"\n}\n'
assert data == expected
def test_use_custom_jsonencoder(self, app, client):
class CabageEncoder(JSONEncoder):
def default(self, obj):
return "cabbage"
class TestConfig(object):
RESTX_JSON = {"cls": CabageEncoder}
app.config.from_object(TestConfig)
api = restx.Api(app)
class Cabbage(restx.Resource):
def get(self):
return {"frob": object()}
api.add_resource(Cabbage, "/cabbage")
data = client.get("/cabbage").data
expected = b'{"frob": "cabbage"}\n'
assert data == expected
def test_json_with_no_settings(self, api, client):
class Foo(restx.Resource):
def get(self):
return {"foo": "bar"}
api.add_resource(Foo, "/foo")
data = client.get("/foo").data
expected = b'{"foo": "bar"}\n'
assert data == expected
def test_redirect(self, api, client):
class FooResource(restx.Resource):
def get(self):
return redirect("/")
api.add_resource(FooResource, "/api")
resp = client.get("/api")
assert resp.status_code == 302
# FIXME: The behavior changed somewhere between Flask 2.0.3 and 2.2.x
assert resp.headers["Location"].endswith("/")
def test_calling_owns_endpoint_before_api_init(self):
api = restx.Api()
api.owns_endpoint("endpoint")
# with pytest.raises(AttributeError):
# try:
# except AttributeError as ae:
# self.fail(ae.message)