"""Tests for Validation.""" import copy from datetime import datetime import json import os from unittest.mock import MagicMock from unittest.mock import patch from flask import Request from flask import Response from freezegun import freeze_time from jsonschema import Draft3Validator from ows_product_physical.constant import error from ows_product_physical.constant import header from ows_product_physical.validation import validation from tests.validation.validation_test_utils import get_validation_response def test_add_error_to_errors(): """Test creating a standard validation errors object.""" initial_errors_object = {} mutated_object = validation.add_error_to_errors( initial_errors_object, 'square', '4_sided', True, 'Shape does not have 4 sides.') assert mutated_object == initial_errors_object == { 'square': { 'validator': '4_sided', 'validator_value': True, 'message': 'Shape does not have 4 sides.'}} def test_validate_post_header_success( valid_post_header, post_header_validation_schema): """Test general use case valid POST header success.""" response = validation.validate( data=valid_post_header, validator=Draft3Validator(post_header_validation_schema)) assert response.status == 200 def test_validate_put_body_validation_fail(valid_put_header): """Test validate put body fail.""" result = get_validation_response('/product/', 'PUT', valid_put_header, {'foo': 'bar'}) assert result.status_code == 400 def test_validate_post_header_fail_required( valid_post_header, post_header_validation_schema): """Test general invalid POST header fail because of required fields.""" mutated_header = copy.copy(valid_post_header) mutated_header.pop(header.CONTENT_TYPE) mutated_header.pop(header.GRASS_ACCOUNT_TYPE) mutated_header.pop(header.GRASS_ACCOUNT_ID) response = validation.validate( data=mutated_header, validator=Draft3Validator(post_header_validation_schema)) message = response.errors.get('message') assert response.status == 400 assert 'required' in message.get( header.CONTENT_TYPE).get('validator') assert 'required' in message.get( header.GRASS_ACCOUNT_TYPE).get('validator') assert 'required' in message.get( header.GRASS_ACCOUNT_ID).get('validator') def test_validate_post_header_fail_pattern( valid_post_header, post_header_validation_schema): """Test general use case invalid POST header fail because pattern.""" mutated_header = copy.copy(valid_post_header) mutated_header[header.CONTENT_TYPE] = 'application/farts' mutated_header[header.GRASS_ACCOUNT_TYPE] = 'banana' mutated_header[header.GRASS_ACCOUNT_ID] = 'pizza' response = validation.validate( data=mutated_header, validator=Draft3Validator(post_header_validation_schema)) message = response.errors.get('message') assert response.status == 400 assert 'pattern' in message.get( header.CONTENT_TYPE).get('validator') assert 'pattern' in message.get( header.GRASS_ACCOUNT_TYPE).get('validator') assert 'pattern' in message.get( header.GRASS_ACCOUNT_ID).get('validator') def test_validate_post_header_fail_type( valid_post_header, post_header_validation_schema): """Test general use case invalid POST header fail because type.""" mutated_header = copy.copy(valid_post_header) mutated_header[header.CONTENT_TYPE] = 1234 mutated_header[header.GRASS_ACCOUNT_TYPE] = 555 mutated_header[header.CORRELATION_ID] = 444 response = validation.validate( data=mutated_header, validator=Draft3Validator(post_header_validation_schema)) message = response.errors.get('message') assert response.status == 400 assert 'type' in message.get( header.CONTENT_TYPE).get('validator') assert 'type' in message.get( header.GRASS_ACCOUNT_TYPE).get('validator') assert 'type' in message.get( header.CORRELATION_ID).get('validator') def test_validate_get_header_success( valid_get_header, get_header_validation_schema): """Test general use case valid GET header success.""" response = validation.validate( data=valid_get_header, validator=Draft3Validator(get_header_validation_schema)) assert response.status == 200 def test_validate_get_header_fail_required( valid_get_header, get_header_validation_schema): """Test general invalid GET header fail because of required fields.""" mutated_header = copy.copy(valid_get_header) mutated_header.pop(header.GRASS_ACCOUNT_TYPE) mutated_header.pop(header.GRASS_ACCOUNT_ID) response = validation.validate( data=mutated_header, validator=Draft3Validator(get_header_validation_schema)) message = response.errors.get('message') assert response.status == 400 assert 'required' in message.get( header.GRASS_ACCOUNT_TYPE).get('validator') assert 'required' in message.get( header.GRASS_ACCOUNT_ID).get('validator') def test_validate_get_header_fail_pattern( valid_get_header, get_header_validation_schema): """Test general use case invalid GET header fail because pattern.""" mutated_header = copy.copy(valid_get_header) mutated_header[header.GRASS_ACCOUNT_TYPE] = 'banana' mutated_header[header.GRASS_ACCOUNT_ID] = 'pizza' response = validation.validate( data=mutated_header, validator=Draft3Validator(get_header_validation_schema)) message = response.errors.get('message') assert response.status == 400 assert 'pattern' in message.get( header.GRASS_ACCOUNT_TYPE).get('validator') assert 'pattern' in message.get( header.GRASS_ACCOUNT_ID).get('validator') def test_validate_get_header_fail_type( valid_get_header, get_header_validation_schema): """Test general use case invalid GET header fail because type.""" mutated_header = copy.copy(valid_get_header) mutated_header[header.CONTENT_TYPE] = 1234 mutated_header[header.GRASS_ACCOUNT_TYPE] = 555 mutated_header[header.CORRELATION_ID] = 444 response = validation.validate( data=mutated_header, validator=Draft3Validator(get_header_validation_schema)) message = response.errors.get('message') assert response.status == 400 assert 'type' in message.get( header.GRASS_ACCOUNT_TYPE).get('validator') assert 'type' in message.get( header.CORRELATION_ID).get('validator') def test_validation_success( monkeypatch, example_data_to_validate, example_validation_schema): """Test example validation is successful using a validator.""" response = validation.validate( data=example_data_to_validate, validator=Draft3Validator(example_validation_schema)) assert response.status == 200 def test_validation_error( monkeypatch, example_data_to_validate, example_validation_schema): """Test example validation fails using our validator. It should return error messages in our desired format. """ mutated_data = copy.copy(example_data_to_validate) mutated_data.pop('apple') mutated_data['orange'] = 333333 mutated_data['banana'] = '12345678901' mutated_data['mango'] = 3333333 mutated_data['pizza'] = 'party' response = validation.validate( data=mutated_data, validator=Draft3Validator(example_validation_schema)) message = response.errors.get('message') assert response.status == 400 assert response.errors.get('code') == error.VALIDATION_ERROR assert 'required' == message.get('apple').get('validator') assert 'type' == message.get('orange').get('validator') assert 'maxLength' in message.get('banana').get('validator') assert 'pizza' in message.get('additionalProperties').get('message') def test_validate_delete_header_success( valid_delete_header, delete_header_validation_schema): """Test general use case valid DELETE header success.""" response = validation.validate( data=valid_delete_header, validator=Draft3Validator(delete_header_validation_schema)) assert response.status == 200 def test_validate_delete_header_fail_required(delete_header_validation_schema): """Test general invalid DELETE header fail because of required fields.""" invalid_delete_header = {} response = validation.validate( data=invalid_delete_header, validator=Draft3Validator(delete_header_validation_schema)) validator_errors = response.errors.get('message') assert response.status == 400 assert 'required' in validator_errors.get( header.GRASS_ACCOUNT_TYPE).get('validator') assert 'required' in validator_errors.get( header.GRASS_ACCOUNT_ID).get('validator') def test_validate_delete_tracks_header_success( valid_delete_header, delete_header_validation_schema): """Test general use case valid tracks DELETE header success.""" response = validation.validate( data=valid_delete_header, validator=Draft3Validator(delete_header_validation_schema)) assert response.status == 200 def test_validate_delete_tracks_header_fail_required( delete_header_validation_schema): """Test general tracks DELETE header fail because of required fields.""" invalid_delete_header = {} response = validation.validate( data=invalid_delete_header, validator=Draft3Validator(delete_header_validation_schema)) validator_errors = response.errors.get('message') assert response.status == 400 assert 'required' in validator_errors.get( header.GRASS_ACCOUNT_TYPE).get('validator') assert 'required' in validator_errors.get( header.GRASS_ACCOUNT_ID).get('validator') def test_json_validator_loads_a_schema(): """Test that json validator loads an arbitrary file.""" path = os.path.dirname(__file__) with open(os.path.join(path, 'sample_schema.json')) as f: schema = validation.json_validator(json.load(f)).schema assert schema.get('properties').get('some_property').\ get('type') == 'string' def run_with_reject_grass_headers(headers): """Submit request with headers and get response.""" request = MagicMock(spec=Request, headers=headers) success_response = MagicMock(spec=Response, status_code=200) def inner(): return success_response with patch.object(validation, 'request', request): return validation.reject_grass_headers(inner)() def test_reject_grass_headers(): """Test that 400 return when grass request made.""" result = run_with_reject_grass_headers({ header.GRASS_ACCOUNT_ID: 1234, header.GRASS_ACCOUNT_TYPE: 'subaccount'}) assert result.status_code == 400 def test_reject_grass_headers_passing(): """Test that inner function called when not grass.""" result = run_with_reject_grass_headers({ 'foo': 'bar'}) assert result.status_code == 200 def test_date_is_after_successful(): """Test sale date should be at least `time_delta` days after today.""" date = '2017-10-10' now = datetime(2017, 8, 10, 0, 0, 0) time_delta = 60 with freeze_time(now): assert validation.date_is_after( date, time_delta) def test_date_is_after_failure(): """Test sale date not at least some `time_delta` days after today.""" date = '2017-10-10' now = datetime(2017, 9, 10, 0, 0, 0) time_delta = 60 with freeze_time(now): assert not validation.date_is_after( date, time_delta)