Skip to content

Instantly share code, notes, and snippets.

@pasenor
Last active December 8, 2015 09:26
Show Gist options
  • Save pasenor/943886890e9529e986b5 to your computer and use it in GitHub Desktop.
Save pasenor/943886890e9529e986b5 to your computer and use it in GitHub Desktop.
match json error description with hamcrest
#coding: utf-8
from copy import deepcopy
import re
from hamcrest.core.base_matcher import BaseMatcher
from hamcrest import assert_that
from webob import Response
# Это хранится в конфиге:
error_skeleton = {
'code': 'invalid_content_publication',
'message': 'cannot publish catalog {catalog_id}:{catalog_revision}',
'duplicate': [],
'missing': []
}
fields_error_skeleton = {
"status_code": 400,
"code": "invalid_parameter_value",
"message": "Invalid parameter value",
"errors": []
}
# Это приходит от API:
error_instance = {
"code": "invalid_content_publication",
"message": "cannot publish catalog 31fd2d1c-a8df-40c8-8815-9d7129f3b3a1:1",
"duplicate":
[
"1c034690-45f0-43a0-9670-1f0493bd5c5d"
],
"missing": []
}
fields_error_instance = {
"code": "invalid_parameter_value",
"message": "Invalid parameter value",
"errors": [
{
"field": "id",
"type": "invalid",
},
{
"field": "msisdn",
"type": "missing"
}
]
}
# Если параметров нет, ошибка хранится как есть
simple_error = {
'code': 'error_code',
'message': 'Error Message'
}
class ErrorMatcher(BaseMatcher):
def __init__(self, error_skeleton, fields_attr='errors'):
self.skeleton = deepcopy(error_skeleton)
self.status_code = self.skeleton.pop('status_code') \
if 'status_code' in self.skeleton \
else None
self.fields_attr = fields_attr
def _match_dict(self, error_dict):
if self.fields_attr in error_dict:
error_dict[self.fields_attr].sort()
return error_dict == self.skeleton
def _matches(self, item):
if isinstance(item, dict):
return self._match_dict(item)
else:
return self._match_dict(item.json) and item.status_code == self.status_code
def describe_to(self, description):
return description.append(u'<{}>'.format(self.skeleton))
def with_params(self, **kwargs):
for key, val in kwargs.iteritems():
if key in self.skeleton:
self.skeleton[key] = val
escaped_name = r'\{' + re.escape(key) + '\}'
for param_name, param_value in self.skeleton.iteritems():
if not isinstance(param_value, basestring):
continue
self.skeleton[param_name] = re.sub(escaped_name, unicode(val), param_value)
return self
def with_fields(self, **kwargs):
if not self.fields_attr:
return self
error_list = []
for error_field, error_type in kwargs.iteritems():
error_list.append(
{
'field': error_field,
'type': error_type,
}
)
self.skeleton[self.fields_attr] = sorted(error_list)
return self
def contains_error(item):
return ErrorMatcher(item)
assert_that(
error_instance,
contains_error(
error_skeleton
).with_params(
catalog_id='31fd2d1c-a8df-40c8-8815-9d7129f3b3a1',
catalog_revision=1,
duplicate=['1c034690-45f0-43a0-9670-1f0493bd5c5d'])
)
assert_that(simple_error, contains_error(simple_error))
assert_that(
fields_error_instance,
contains_error(fields_error_skeleton).with_fields(id='invalid', msisdn='missing')
)
assert_that(
fields_error_instance,
contains_error(fields_error_skeleton).with_fields(msisdn='missing', id='invalid')
)
fields_error_response = Response(json=fields_error_instance, status='400 Invalid Parameter')
assert_that(fields_error_response,
contains_error(fields_error_skeleton).with_fields(msisdn='missing', id='invalid'))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment