def test_add_error_new(self): meta = Meta() meta.add_error('additional', 'changed') assert meta.raw() == {'': { 'err': ['additional'], 'val': 'changed', }}
def test_error_with_data(self): meta = Meta() meta.add_error("invalid url", data={"url": "invalid"}) assert list( meta.iter_errors()) == [["invalid url", { "url": "invalid" }]]
def test_get_root(self): assert Meta(input_meta).raw() == input_meta assert Meta(input_meta).get() == input_meta[''] assert list(Meta(input_meta).iter_errors()) == [['existing', {}]] assert Meta(input_meta).get_event_errors() == [ {'type': 'existing', 'value': 'original'}, ]
def test_add_error_none(self): data = {'': None} meta = Meta(data) meta.add_error('additional', 'changed') assert data == {'': { 'err': ['additional'], 'val': 'changed', }}
def test_add_error_nested_missing(self): data = {} meta = Meta(data) meta.enter('field').add_error('additional', 'changed') assert meta.enter('field').get() == { 'err': ['additional'], 'val': 'changed', }
def test_get_root(self): assert Meta(input_meta).raw() == input_meta assert Meta(input_meta).get() == input_meta[""] assert list(Meta(input_meta).iter_errors()) == [["existing", {}]] assert Meta(input_meta).get_event_errors() == [{ "type": "existing", "value": "original" }]
def test_add_error_nested_missing(self): data = {} meta = Meta(data) meta.enter("field").add_error("additional", "changed") assert meta.enter("field").get() == { "err": ["additional"], "val": "changed" }
def test_get_nested_existing(self): data = {'field': input_meta} assert Meta(data).enter('field').raw() == input_meta assert Meta(data).enter('field').get() == input_meta[''] assert list(Meta(data).enter('field').iter_errors()) == [['existing', {}]] assert Meta(data).enter('field').get_event_errors() == [ {'type': 'existing', 'name': 'field', 'value': 'original'} ]
def test_add_error_root(self): changed = deepcopy(input_meta) meta = Meta(changed) meta.add_error('additional', 'changed') assert meta.get() == { 'err': ['existing', 'additional'], 'val': 'changed', 'rem': [{'type': 'x'}], }
def test_add_error_nested_existing(self): data = {'field': input_meta} changed = deepcopy(data) meta = Meta(changed) meta.enter('field').add_error('additional', 'changed') assert meta.enter('field').get() == { 'err': ['existing', 'additional'], 'val': 'changed', 'rem': [{'type': 'x'}], }
def test_add_error_root(self): changed = deepcopy(input_meta) meta = Meta(changed) meta.add_error("additional", "changed") assert meta.get() == { "err": ["existing", "additional"], "val": "changed", "rem": [{ "type": "x" }], }
def test_add_error_nested_existing(self): data = {"field": input_meta} changed = deepcopy(data) meta = Meta(changed) meta.enter("field").add_error("additional", "changed") assert meta.enter("field").get() == { "err": ["existing", "additional"], "val": "changed", "rem": [{ "type": "x" }], }
def test_get_nested_existing(self): data = {"field": input_meta} assert Meta(data).enter("field").raw() == input_meta assert Meta(data).enter("field").get() == input_meta[""] assert list( Meta(data).enter("field").iter_errors()) == [["existing", {}]] assert Meta(data).enter("field").get_event_errors() == [{ "type": "existing", "name": "field", "value": "original" }]
def test_get_multiple_event_errors(self): # XXX: Value is only added to the first error, which is usually the # normalization error. assert Meta(merged_meta).get_event_errors() == [ {'type': 'existing', 'value': 'changed'}, {'type': 'additional'} ]
class ProcessTimestampTest(TestCase): def setUp(self): self.meta = Meta() def test_iso_timestamp(self): assert process_timestamp( '2012-01-01T10:30:45', self.meta, current_datetime=datetime(2012, 1, 1, 10, 30, 45), ) == 1325413845.0 def test_iso_timestamp_with_ms(self): assert process_timestamp( '2012-01-01T10:30:45.434', self.meta, current_datetime=datetime(2012, 1, 1, 10, 30, 45, 434000), ) == 1325413845.0 def test_timestamp_iso_timestamp_with_Z(self): assert process_timestamp( '2012-01-01T10:30:45Z', self.meta, current_datetime=datetime(2012, 1, 1, 10, 30, 45), ) == 1325413845.0 def test_invalid_timestamp(self): assert process_timestamp('foo', self.meta) is None assert len(list(self.meta.iter_errors())) == 1 def test_invalid_numeric_timestamp(self): assert process_timestamp('100000000000000000000.0', self.meta) is None assert len(list(self.meta.iter_errors())) == 1 def test_future_timestamp(self): assert process_timestamp('2052-01-01T10:30:45Z', self.meta) is None assert len(list(self.meta.iter_errors())) == 1 def test_long_microseconds_value(self): assert process_timestamp( '2012-01-01T10:30:45.341324Z', self.meta, current_datetime=datetime(2012, 1, 1, 10, 30, 45), ) == 1325413845.0 def test_invalid_type(self): assert process_timestamp({}, self.meta) is None
def test_get_multiple_event_errors(self): # XXX: Value is only added to the first error, which is usually the # normalization error. assert Meta(merged_meta).get_event_errors() == [ { "type": "existing", "value": "changed" }, { "type": "additional" }, ]
def test_merge_none(self): data = {'': None} meta = Meta(data) assert meta.merge(Meta(other_meta)) == other_meta[''] assert data == other_meta
def test_create_root(self): changed = deepcopy(input_meta) meta = Meta(changed) # should be idempotent assert meta.create() == input_meta[''] assert changed == input_meta
def test_create_nested_index(self): data = {} meta = Meta(data) assert meta.enter(0).create() == {} assert data == {'0': {'': {}}}
def test_error_with_data(self): meta = Meta() meta.add_error('invalid url', data={'url': 'invalid'}) assert list(meta.iter_errors()) == [['invalid url', {'url': 'invalid'}]]
def test_stringify_error(self): meta = Meta() meta.add_error(ValueError('invalid stuff'), 'changed') assert list(meta.iter_errors()) == [['invalid stuff', {}]]
def test_merge_missing(self): data = {} meta = Meta(data) assert meta.merge(Meta(other_meta)) == other_meta[""] assert data == other_meta
def test_get_none(self): assert Meta({"": None}).raw() == {"": None} assert Meta({"": None}).get() == {} assert list(Meta({"": None}).iter_errors()) == [] assert Meta({"": None}).get_event_errors() == []
def test_merge_new(self): meta = Meta() assert meta.merge(Meta(other_meta)) == other_meta[""] assert meta.raw() == other_meta
def test_get_missing(self): assert Meta({}).raw() == {} assert Meta({}).get() == {} assert list(Meta({}).iter_errors()) == [] assert Meta({}).get_event_errors() == []
def test_create_new(self): meta = Meta() assert meta.create() == {} assert meta.raw() == {'': {}}
def test_get_new(self): assert Meta().raw() == {} assert Meta().get() == {} assert list(Meta().iter_errors()) == [] assert Meta().get_event_errors() == []
def test_create_nested_index(self): data = {} meta = Meta(data) assert meta.enter(0).create() == {} assert data == {"0": {"": {}}}
def test_create_none(self): data = {'': None} meta = Meta(data) assert meta.create() == {} assert data == {'': {}}
def test_merge_missing(self): data = {} meta = Meta(data) assert meta.merge(Meta(other_meta)) == other_meta[''] assert data == other_meta
def test_create_missing(self): data = {} meta = Meta(data) assert meta.create() == {} assert data == {'': {}}
def test_merge_new(self): meta = Meta() assert meta.merge(Meta(other_meta)) == other_meta[''] assert meta.raw() == other_meta
def test_stringify_error(self): meta = Meta() meta.add_error(ValueError("invalid stuff"), "changed") assert list(meta.iter_errors()) == [["invalid stuff", {}]]
def test_create_nested_existing(self): data = {'field': input_meta} changed = deepcopy(data) meta = Meta(changed) assert meta.enter('field').create() == input_meta[''] assert changed == data
def test_merge_nested_missing(self): data = {} meta = Meta(data) assert meta.enter('field').merge(Meta(other_meta)) == other_meta[''] assert data == {'field': other_meta}
def test_merge_none(self): data = {"": None} meta = Meta(data) assert meta.merge(Meta(other_meta)) == other_meta[""] assert data == other_meta
def test_create_new(self): meta = Meta() assert meta.create() == {} assert meta.raw() == {"": {}}
def test_merge_empty(self): data = {'': {}} meta = Meta(data) assert meta.merge(Meta(other_meta)) == other_meta[''] assert data == other_meta
def test_add_error_new(self): meta = Meta() meta.add_error("additional", "changed") assert meta.raw() == {"": {"err": ["additional"], "val": "changed"}}
def setUp(self): self.meta = Meta()
def test_create_missing(self): data = {} meta = Meta(data) assert meta.create() == {} assert data == {"": {}}
def test_create_nested_missing(self): data = {} meta = Meta(data) assert meta.enter('field').create() == {} assert data == {'field': {'': {}}}
def test_add_error_missing(self): data = {} meta = Meta(data) meta.add_error("additional", "changed") assert data == {"": {"err": ["additional"], "val": "changed"}}
def test_merge_root(self): changed = deepcopy(input_meta) meta = Meta(changed) assert meta.merge(Meta(other_meta)) == merged_meta[''] assert changed == merged_meta
def test_create_none(self): data = {"": None} meta = Meta(data) assert meta.create() == {} assert data == {"": {}}
def test_merge_nested_existing(self): data = {'field': input_meta} changed = deepcopy(data) meta = Meta(changed) assert meta.enter('field').merge(Meta(other_meta)) == merged_meta[''] assert changed == {'field': merged_meta}
def validate_and_default_interface(data, interface, name=None, meta=None, strip_nones=True, raise_on_invalid=False): """ Modify data to conform to named interface's schema. Takes the object in `data` and checks it against the schema for `interface`, removing or defaulting any keys that do not pass validation and adding defaults for any keys that are required by (and have a default value in) the schema. Returns whether the resulting modified data is valid against the schema and a list of any validation errors encountered in processing. """ if meta is None: meta = Meta() is_valid = True needs_revalidation = False errors = [] validator = validator_for_interface(interface) if validator is None: return (True, []) schema = validator.schema # Strip Nones so we don't have to take null into account for all schemas. if strip_nones and isinstance(data, dict): for k in data.keys(): if data[k] is None: del data[k] # Values that are missing entirely, but are required and should be defaulted if 'properties' in schema and 'required' in schema and isinstance(data, dict): for p in schema['required']: if p not in data: if p in schema['properties'] and 'default' in schema['properties'][p]: default = schema['properties'][p]['default'] data[p] = default() if callable(default) else default else: meta.add_error(EventError.MISSING_ATTRIBUTE, data={'name': p}) errors.append({'type': EventError.MISSING_ATTRIBUTE, 'name': p}) validator_errors = list(validator.iter_errors(data)) keyed_errors = [e for e in reversed(validator_errors) if len(e.path)] if len(validator_errors) > len(keyed_errors): needs_revalidation = True # Values that need to be defaulted or deleted because they are not valid. for key, group in groupby(keyed_errors, lambda e: e.path[0]): ve = six.next(group) is_max = ve.validator.startswith('max') if is_max: error_type = EventError.VALUE_TOO_LONG elif key == 'environment': error_type = EventError.INVALID_ENVIRONMENT else: error_type = EventError.INVALID_DATA meta.enter(key).add_error(error_type, data[key]) errors.append({'type': error_type, 'name': name or key, 'value': data[key]}) if 'default' in ve.schema: default = ve.schema['default'] data[key] = default() if callable(default) else default else: needs_revalidation = True del data[key] if needs_revalidation: is_valid = validator.is_valid(data) return is_valid, errors
def test_create_empty(self): data = {'': {}} meta = Meta(data) assert meta.create() == {} assert data == {'': {}}