"""Validator Tests. Testing generic validator methods """ import json from jsonschema import Draft3Validator from owsresponse import response import pytest from werkzeug import datastructures from features.validation import json_schema from features.validation.schema import json_validators @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 teapot_status(): """Non-success status code to use when testing validation failure. Returns: int: status code """ return 418 @pytest.fixture def mock_request_with_args(mocker): """Fixture for request with args.""" args_dict = {'foo': 'bar', 'baz': 'boink'} return mocker.Mock(args=mocker.Mock(to_dict=mocker.Mock(return_value=args_dict))) @pytest.fixture def mock_request_with_body(mocker): """Fixture for request with body.""" get_json = mocker.Mock(return_value={'int_prop': 1, 'string_prop': 'hi'}) return mocker.Mock(get_json=get_json) @pytest.fixture def mock_request_with_headers(mocker): """Fixture for request with headers.""" headers = datastructures.EnvironHeaders({'HTTP_CORRELATION_ID': 'bar'}) return mocker.Mock(headers=headers) @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.""" result = json_schema.validate(valid_data, validator) assert result.status == 200 assert result.message == {'status': 'ok'} def test_validate_failure(invalid_data, validator, teapot_status): """Test status and errors when data is invalid.""" result = json_schema.validate(invalid_data, validator, teapot_status) message = result.errors.get('message') assert result.status == teapot_status assert 'string-property' in message assert 'numeric-property' in message def test_validate_request_args(mocker, mock_request_with_args, 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') json_schema.validate_request_args(mock_request_with_args, resource, 'get') json_validators.query_args_validator.assert_called_with(resource, 'get') json_schema.validate.assert_called_with( mock_request_with_args.args.to_dict(), validator ) def test_validate_headers(mocker, mock_request_with_headers, 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') json_schema.validate_request_headers(mock_request_with_headers, resource, 'get') json_validators.headers_validator.assert_called_with(resource, 'get') json_schema.validate.assert_called_with( dict(mock_request_with_headers.headers), validator ) def test_validate_body(mocker, mock_request_with_body, 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') json_schema.validate_request_body(mock_request_with_body, resource, 'get') json_validators.body_validator.assert_called_with(resource, 'get') json_schema.validate.assert_called_with( mock_request_with_body.get_json(), validator ) def test_wrap_request_validation_success(mocker, resource): """Test that on validation success the wrapped function is called.""" request = mocker.Mock() validation_function = mocker.Mock(return_value=response.Response()) @json_schema.wrap_request_validation(request, resource, 'get', validation_function) def wrapped_function(): return 'i fired!' 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. """ request = mocker.Mock() 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(request, resource, 'get', validation_function) def wrapped_function(ignored_function): ignored_function() 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()