114 lines
3.8 KiB
Python
114 lines
3.8 KiB
Python
import json
|
|
|
|
import pytest
|
|
from guardrails.schema.validator import SchemaValidationError, validate_payload
|
|
|
|
with open(
|
|
"tests/integration_tests/test_assets/json_schemas/choice_case.json", "r"
|
|
) as choice_case_json_file:
|
|
schema = json.loads(choice_case_json_file.read())
|
|
|
|
|
|
class TestValidatePayload:
|
|
def test_happy_path(self):
|
|
payload = {"action": {"chosen_action": "fight", "weapon": "crossbow"}}
|
|
|
|
validate_payload(payload, schema)
|
|
|
|
def test_extra_properties_allowed(self):
|
|
payload = {
|
|
"action": {"chosen_action": "fight", "weapon": "crossbow"},
|
|
"reason": "Peregrin Took is a brave hobbit",
|
|
}
|
|
|
|
validate_payload(payload, schema)
|
|
|
|
def test_failure_invalid_discriminator_value(self):
|
|
payload = {"action": {"chosen_action": "dance", "type": "jig"}}
|
|
|
|
with pytest.raises(Exception) as excinfo:
|
|
validate_payload(payload, schema)
|
|
|
|
assert isinstance(excinfo.value, SchemaValidationError) is True
|
|
schema_error: SchemaValidationError = excinfo.value
|
|
assert (
|
|
str(schema_error)
|
|
== "The provided payload is not compliant with the provided schema!"
|
|
)
|
|
assert schema_error.fields == {
|
|
"$.action.chosen_action": ["'dance' is not one of ['fight', 'flight']"]
|
|
}
|
|
|
|
def test_failure_invalid_type(self):
|
|
payload = {
|
|
"action": {
|
|
"chosen_action": "flight",
|
|
"flight_direction": "north",
|
|
"distance": "2",
|
|
}
|
|
}
|
|
|
|
with pytest.raises(Exception) as excinfo:
|
|
validate_payload(payload, schema)
|
|
|
|
assert isinstance(excinfo.value, SchemaValidationError) is True
|
|
schema_error: SchemaValidationError = excinfo.value
|
|
assert (
|
|
str(schema_error)
|
|
== "The provided payload is not compliant with the provided schema!"
|
|
)
|
|
# Type coercion is not automatic!
|
|
assert schema_error.fields == {
|
|
"$.action.distance": ["'2' is not of type 'integer'"]
|
|
}
|
|
|
|
# NOTE: Technically the same as an invalid type
|
|
def test_failure_invalid_structure(self):
|
|
payload = {
|
|
"action": [
|
|
{
|
|
"chosen_action": "flight",
|
|
"flight_direction": "north",
|
|
"distance": "2",
|
|
}
|
|
]
|
|
}
|
|
|
|
with pytest.raises(Exception) as excinfo:
|
|
validate_payload(payload, schema)
|
|
|
|
assert isinstance(excinfo.value, SchemaValidationError) is True
|
|
schema_error: SchemaValidationError = excinfo.value
|
|
assert (
|
|
str(schema_error)
|
|
== "The provided payload is not compliant with the provided schema!"
|
|
)
|
|
assert schema_error.fields == {
|
|
"$.action": [
|
|
"[{'chosen_action': 'flight', 'flight_direction': 'north', 'distance': '2'}] is not of type 'object'" # noqa
|
|
]
|
|
}
|
|
|
|
def test_failure_missing_required_properties(self):
|
|
payload = {"action": {"chosen_action": "flight"}}
|
|
|
|
with pytest.raises(Exception) as excinfo:
|
|
validate_payload(payload, schema)
|
|
|
|
assert isinstance(excinfo.value, SchemaValidationError) is True
|
|
schema_error: SchemaValidationError = excinfo.value
|
|
assert (
|
|
str(schema_error)
|
|
== "The provided payload is not compliant with the provided schema!"
|
|
)
|
|
|
|
assert schema_error.fields == {
|
|
"$.action": ["'distance' is a required property"]
|
|
}
|
|
|
|
def test_subschema_validation(self):
|
|
# Missing required properites, but that's allowed with validate_subschema
|
|
payload = {"action": {"chosen_action": "flight"}}
|
|
|
|
validate_payload(payload, schema, validate_subschema=True)
|