"""Validator Tests. Testing generic validator methods """ import json import flask from jsonschema import Draft3Validator from oto import response import pytest from product.validation import json_schema from product.validation.schema import json_validators app = flask.Flask(__name__) @pytest.fixture def schema(): """Test schema to validate against. Returns: dict: validation schema """ return { 'type': 'object', 'properties': { 'string-property': {'type': 'string'}, 'numeric-property': {'type': 'number'} } } @pytest.fixture def validator(schema): """Validator instance that uses our test schema. Returns: Draft3Validator: validator instance """ return Draft3Validator(schema) @pytest.fixture def valid_data(): """Data that will pass validation against the test schema. Returns: dict: valid data """ return { 'string-property': 'this is a string', 'numeric-property': 123 } @pytest.fixture def invalid_data(): """Data that will fail validation against the test schema. Returns: dict: invalid data """ return { 'string-property': 79.3, 'numeric-property': 'i am a number, i swear' } @pytest.fixture def resource(): """Return a test resource name.""" return '/test_route' def test_validate_success(valid_data, validator): """Test status and message when data is valid.""" response = json_schema.validate(valid_data, validator) assert response.status == 200 assert response.message == {'status': 'ok'} def test_validate_failure(invalid_data, validator,): """Test status and errors when data is invalid.""" teapot_status = 418 response = json_schema.validate(invalid_data, validator, teapot_status) message = response.errors.get('message') assert response.status == teapot_status assert 'string-property' in message assert 'numeric-property' in message def test_validate_request_args(mocker, resource): """Test to validate request args. Test that a query args validator is constructed and called with the args from the given request. """ validator = mocker.Mock() mocker.patch.object( json_validators, 'query_args_validator', return_value=validator) mocker.patch.object(json_schema, 'validate') with app.test_request_context(query_string='foo=bar&baz=boink'): json_schema.validate_request_args(resource, 'get') json_validators.query_args_validator.assert_called_with(resource, 'get') json_schema.validate.assert_called_with( {'foo': 'bar', 'baz': 'boink'}, validator) def test_validate_headers(mocker, resource): """Test to validate headers. Test that a headers validator is constructed and called with the headers from the given request. """ validator = mocker.Mock() mocker.patch.object( json_validators, 'headers_validator', return_value=validator) mocker.patch.object(json_schema, 'validate') headers = {'HTTP_CORRELATION_ID': 'bar'} with app.test_request_context(headers=headers): json_schema.validate_request_headers(resource, 'get') json_validators.headers_validator.assert_called_with(resource, 'get') assert json_schema.validate.call_count == 1 call_spec = json_schema.validate.call_args[0] assert 'Http-Correlation-Id' in call_spec[0] assert call_spec[1] is validator def test_validate_body(mocker, resource): """Test to validate body. Test that a body validator is constructed and called with the body from the given request. """ validator = mocker.Mock() mocker.patch.object( json_validators, 'body_validator', return_value=validator) mocker.patch.object(json_schema, 'validate') body = {'int_prop': 1, 'string_prop': 'hi'} data = json.dumps(body) headers = {'Content-Type': 'application/json'} with app.test_request_context(data=data, headers=headers): json_schema.validate_request_body(resource, 'get') json_validators.body_validator.assert_called_with(resource, 'get') json_schema.validate.assert_called_with(body, validator) def test_wrap_request_validation_success(mocker, resource): """Test that on validation success the wrapped function is called.""" validation_function = mocker.Mock(return_value=response.Response()) @json_schema.wrap_request_validation(resource, 'get', validation_function) def wrapped_function(): return 'i fired!' with app.test_request_context(): assert wrapped_function() == 'i fired!' def test_wrap_request_validation_failure(mocker, resource): """Test validation failure. Test that on validation failure an error is returned and the wrapped function never gets called. """ errors = {'message': 'something bad happened here'} validation_function = mocker.Mock( return_value=response.Response(status=400, errors=errors)) call_me_maybe = mocker.Mock() @json_schema.wrap_request_validation(resource, 'get', validation_function) def wrapped_function(ignored_function): ignored_function() with app.test_request_context(): result = wrapped_function(call_me_maybe) result_json = json.loads(result.data.decode('utf-8')) assert result.status_code == 400 assert result_json == errors call_me_maybe.assert_not_called()