378 lines
11 KiB
Python
378 lines
11 KiB
Python
import flask_restx as restx
|
|
|
|
|
|
class PayloadTest(object):
|
|
def assert_errors(self, client, url, data, *errors):
|
|
out = client.post_json(url, data, status=400)
|
|
assert "message" in out
|
|
assert "errors" in out
|
|
for error in errors:
|
|
assert error in out["errors"]
|
|
|
|
def test_validation_false_on_constructor(self, app, client):
|
|
api = restx.Api(app, validate=False)
|
|
|
|
fields = api.model(
|
|
"Person",
|
|
{
|
|
"name": restx.fields.String(required=True),
|
|
"age": restx.fields.Integer,
|
|
"birthdate": restx.fields.DateTime,
|
|
},
|
|
)
|
|
|
|
@api.route("/validation/")
|
|
class ValidationOff(restx.Resource):
|
|
@api.expect(fields)
|
|
def post(self):
|
|
return {}
|
|
|
|
data = client.post_json("/validation/", {})
|
|
assert data == {}
|
|
|
|
def test_validation_false_on_constructor_with_override(self, app, client):
|
|
api = restx.Api(app, validate=False)
|
|
|
|
fields = api.model(
|
|
"Person",
|
|
{
|
|
"name": restx.fields.String(required=True),
|
|
"age": restx.fields.Integer,
|
|
"birthdate": restx.fields.DateTime,
|
|
},
|
|
)
|
|
|
|
@api.route("/validation/")
|
|
class ValidationOn(restx.Resource):
|
|
@api.expect(fields, validate=True)
|
|
def post(self):
|
|
return {}
|
|
|
|
self.assert_errors(client, "/validation/", {}, "name")
|
|
|
|
def test_validation_true_on_constructor(self, app, client):
|
|
api = restx.Api(app, validate=True)
|
|
|
|
fields = api.model(
|
|
"Person",
|
|
{
|
|
"name": restx.fields.String(required=True),
|
|
"age": restx.fields.Integer,
|
|
"birthdate": restx.fields.DateTime,
|
|
},
|
|
)
|
|
|
|
@api.route("/validation/")
|
|
class ValidationOff(restx.Resource):
|
|
@api.expect(fields)
|
|
def post(self):
|
|
return {}
|
|
|
|
self.assert_errors(client, "/validation/", {}, "name")
|
|
|
|
def test_validation_true_on_constructor_with_override(self, app, client):
|
|
api = restx.Api(app, validate=True)
|
|
|
|
fields = api.model(
|
|
"Person",
|
|
{
|
|
"name": restx.fields.String(required=True),
|
|
"age": restx.fields.Integer,
|
|
"birthdate": restx.fields.DateTime,
|
|
},
|
|
)
|
|
|
|
@api.route("/validation/")
|
|
class ValidationOff(restx.Resource):
|
|
@api.expect(fields, validate=False)
|
|
def post(self):
|
|
return {}
|
|
|
|
data = client.post_json("/validation/", {})
|
|
assert data == {}
|
|
|
|
def _setup_api_format_checker_tests(self, app, format_checker=None):
|
|
class IPAddress(restx.fields.Raw):
|
|
__schema_type__ = "string"
|
|
__schema_format__ = "ipv4"
|
|
|
|
api = restx.Api(app, format_checker=format_checker)
|
|
model = api.model("MyModel", {"ip": IPAddress(required=True)})
|
|
|
|
@api.route("/format_checker/")
|
|
class TestResource(restx.Resource):
|
|
@api.expect(model, validate=True)
|
|
def post(self):
|
|
return {}
|
|
|
|
def test_format_checker_none_on_constructor(self, app, client):
|
|
self._setup_api_format_checker_tests(app)
|
|
|
|
out = client.post_json("/format_checker/", {"ip": "192.168.1"})
|
|
assert out == {}
|
|
|
|
def test_format_checker_object_on_constructor(self, app, client):
|
|
from jsonschema import FormatChecker
|
|
|
|
self._setup_api_format_checker_tests(app, format_checker=FormatChecker())
|
|
|
|
out = client.post_json("/format_checker/", {"ip": "192.168.1"}, status=400)
|
|
assert "ipv4" in out["errors"]["ip"]
|
|
|
|
def test_validation_false_in_config(self, app, client):
|
|
app.config["RESTX_VALIDATE"] = False
|
|
api = restx.Api(app)
|
|
|
|
fields = api.model(
|
|
"Person",
|
|
{
|
|
"name": restx.fields.String(required=True),
|
|
"age": restx.fields.Integer,
|
|
"birthdate": restx.fields.DateTime,
|
|
},
|
|
)
|
|
|
|
@api.route("/validation/")
|
|
class ValidationOff(restx.Resource):
|
|
@api.expect(fields)
|
|
def post(self):
|
|
return {}
|
|
|
|
out = client.post_json("/validation/", {})
|
|
|
|
# assert response.status_code == 200
|
|
# out = json.loads(response.data.decode('utf8'))
|
|
assert out == {}
|
|
|
|
def test_validation_in_config(self, app, client):
|
|
app.config["RESTX_VALIDATE"] = True
|
|
api = restx.Api(app)
|
|
|
|
fields = api.model(
|
|
"Person",
|
|
{
|
|
"name": restx.fields.String(required=True),
|
|
"age": restx.fields.Integer,
|
|
"birthdate": restx.fields.DateTime,
|
|
},
|
|
)
|
|
|
|
@api.route("/validation/")
|
|
class ValidationOn(restx.Resource):
|
|
@api.expect(fields)
|
|
def post(self):
|
|
return {}
|
|
|
|
self.assert_errors(client, "/validation/", {}, "name")
|
|
|
|
def test_api_payload(self, app, client):
|
|
api = restx.Api(app, validate=True)
|
|
|
|
fields = api.model(
|
|
"Person",
|
|
{
|
|
"name": restx.fields.String(required=True),
|
|
"age": restx.fields.Integer,
|
|
"birthdate": restx.fields.DateTime,
|
|
},
|
|
)
|
|
|
|
@api.route("/validation/")
|
|
class Payload(restx.Resource):
|
|
payload = None
|
|
|
|
@api.expect(fields)
|
|
def post(self):
|
|
Payload.payload = api.payload
|
|
return {}
|
|
|
|
data = {
|
|
"name": "John Doe",
|
|
"age": 15,
|
|
}
|
|
|
|
client.post_json("/validation/", data)
|
|
|
|
assert Payload.payload == data
|
|
|
|
def test_validation_with_inheritance(self, app, client):
|
|
"""It should perform validation with inheritance (allOf/$ref)"""
|
|
api = restx.Api(app, validate=True)
|
|
|
|
fields = api.model(
|
|
"Parent",
|
|
{
|
|
"name": restx.fields.String(required=True),
|
|
},
|
|
)
|
|
|
|
child_fields = api.inherit(
|
|
"Child",
|
|
fields,
|
|
{
|
|
"age": restx.fields.Integer,
|
|
},
|
|
)
|
|
|
|
@api.route("/validation/")
|
|
class Inheritance(restx.Resource):
|
|
@api.expect(child_fields)
|
|
def post(self):
|
|
return {}
|
|
|
|
client.post_json(
|
|
"/validation/",
|
|
{
|
|
"name": "John Doe",
|
|
"age": 15,
|
|
},
|
|
)
|
|
|
|
self.assert_errors(
|
|
client,
|
|
"/validation/",
|
|
{
|
|
"age": "15",
|
|
},
|
|
"name",
|
|
"age",
|
|
)
|
|
|
|
def test_validation_on_list(self, app, client):
|
|
"""It should perform validation on lists"""
|
|
api = restx.Api(app, validate=True)
|
|
|
|
person = api.model(
|
|
"Person",
|
|
{
|
|
"name": restx.fields.String(required=True),
|
|
"age": restx.fields.Integer(required=True),
|
|
},
|
|
)
|
|
|
|
family = api.model(
|
|
"Family",
|
|
{
|
|
"name": restx.fields.String(required=True),
|
|
"members": restx.fields.List(restx.fields.Nested(person)),
|
|
},
|
|
)
|
|
|
|
@api.route("/validation/")
|
|
class List(restx.Resource):
|
|
@api.expect(family)
|
|
def post(self):
|
|
return {}
|
|
|
|
self.assert_errors(
|
|
client,
|
|
"/validation/",
|
|
{"name": "Doe", "members": [{"name": "Jonn"}, {"age": 42}]},
|
|
"members.0.age",
|
|
"members.1.name",
|
|
)
|
|
|
|
def _setup_expect_validation_single_resource_tests(self, app):
|
|
# Setup a minimal Api with endpoint that expects in input payload
|
|
# a single object of a resource
|
|
api = restx.Api(app, validate=True)
|
|
|
|
user = api.model("User", {"username": restx.fields.String()})
|
|
|
|
@api.route("/validation/")
|
|
class Users(restx.Resource):
|
|
@api.expect(user)
|
|
def post(self):
|
|
return {}
|
|
|
|
def _setup_expect_validation_collection_resource_tests(self, app):
|
|
# Setup a minimal Api with endpoint that expects in input payload
|
|
# one or more objects of a resource
|
|
api = restx.Api(app, validate=True)
|
|
|
|
user = api.model("User", {"username": restx.fields.String()})
|
|
|
|
@api.route("/validation/")
|
|
class Users(restx.Resource):
|
|
@api.expect([user])
|
|
def post(self):
|
|
return {}
|
|
|
|
def test_expect_validation_single_resource_success(self, app, client):
|
|
self._setup_expect_validation_single_resource_tests(app)
|
|
|
|
# Input payload is a valid JSON object
|
|
out = client.post_json("/validation/", {"username": "alice"})
|
|
assert {} == out
|
|
|
|
def test_expect_validation_single_resource_error(self, app, client):
|
|
self._setup_expect_validation_single_resource_tests(app)
|
|
|
|
# Input payload is an invalid JSON object
|
|
self.assert_errors(client, "/validation/", {"username": 123}, "username")
|
|
|
|
# Input payload is a JSON array (expected JSON object)
|
|
self.assert_errors(client, "/validation/", [{"username": 123}], "")
|
|
|
|
def test_expect_validation_collection_resource_success(self, app, client):
|
|
self._setup_expect_validation_collection_resource_tests(app)
|
|
|
|
# Input payload is a valid JSON object
|
|
out = client.post_json("/validation/", {"username": "alice"})
|
|
assert {} == out
|
|
|
|
# Input payload is a JSON array with valid JSON objects
|
|
out = client.post_json(
|
|
"/validation/", [{"username": "alice"}, {"username": "bob"}]
|
|
)
|
|
assert {} == out
|
|
|
|
def test_expect_validation_collection_resource_error(self, app, client):
|
|
self._setup_expect_validation_collection_resource_tests(app)
|
|
|
|
# Input payload is an invalid JSON object
|
|
self.assert_errors(client, "/validation/", {"username": 123}, "username")
|
|
|
|
# Input payload is a JSON array but with an invalid JSON object
|
|
self.assert_errors(
|
|
client,
|
|
"/validation/",
|
|
[{"username": "alice"}, {"username": 123}],
|
|
"username",
|
|
)
|
|
|
|
def test_validation_with_propagate(self, app, client):
|
|
app.config["PROPAGATE_EXCEPTIONS"] = True
|
|
api = restx.Api(app, validate=True)
|
|
|
|
fields = api.model(
|
|
"Person",
|
|
{
|
|
"name": restx.fields.String(required=True),
|
|
"age": restx.fields.Integer,
|
|
"birthdate": restx.fields.DateTime,
|
|
},
|
|
)
|
|
|
|
@api.route("/validation/")
|
|
class ValidationOff(restx.Resource):
|
|
@api.expect(fields)
|
|
def post(self):
|
|
return {}
|
|
|
|
self.assert_errors(client, "/validation/", {}, "name")
|
|
|
|
def test_empty_payload(self, app, client):
|
|
api = restx.Api(app, validate=True)
|
|
|
|
@api.route("/empty/")
|
|
class Payload(restx.Resource):
|
|
def post(self):
|
|
return {}
|
|
|
|
response = client.post(
|
|
"/empty/", data="", headers={"content-type": "application/json"}
|
|
)
|
|
|
|
assert response.status_code == 200
|