Merge "Send HTTP exceptions in the format expected by neutronclient"

This commit is contained in:
Jenkins 2014-08-23 01:43:08 +00:00 committed by Gerrit Code Review
commit 35b2d27883
2 changed files with 86 additions and 36 deletions

View File

@ -99,17 +99,16 @@ def Resource(controller, faults=None, deserializers=None, serializers=None):
else:
LOG.exception(_('%s failed'), action)
e = translate(e, language)
# following structure is expected by python-neutronclient
err_data = {'type': e.__class__.__name__,
'message': e, 'detail': ''}
body = serializer.serialize({'NeutronError': err_data})
body = serializer.serialize(
{'NeutronError': get_exception_data(e)})
kwargs = {'body': body, 'content_type': content_type}
raise mapped_exc(**kwargs)
except webob.exc.HTTPException as e:
type_, value, tb = sys.exc_info()
LOG.exception(_('%s failed'), action)
translate(e, language)
value.body = serializer.serialize({'NeutronError': e})
value.body = serializer.serialize(
{'NeutronError': get_exception_data(e)})
value.content_type = content_type
six.reraise(type_, value, tb)
except NotImplementedError as e:
@ -121,7 +120,7 @@ def Resource(controller, faults=None, deserializers=None, serializers=None):
# because a plugin does not implement a feature,
# returning 500 is definitely confusing.
body = serializer.serialize(
{'NotImplementedError': e.message})
{'NotImplementedError': get_exception_data(e)})
kwargs = {'body': body, 'content_type': content_type}
raise webob.exc.HTTPNotImplemented(**kwargs)
except Exception:
@ -131,7 +130,9 @@ def Resource(controller, faults=None, deserializers=None, serializers=None):
msg = _('Request Failed: internal server error while '
'processing your request.')
msg = translate(msg, language)
body = serializer.serialize({'NeutronError': msg})
body = serializer.serialize(
{'NeutronError': get_exception_data(
webob.exc.HTTPInternalServerError(msg))})
kwargs = {'body': body, 'content_type': content_type}
raise webob.exc.HTTPInternalServerError(**kwargs)
@ -148,6 +149,21 @@ def Resource(controller, faults=None, deserializers=None, serializers=None):
return resource
def get_exception_data(e):
"""Extract the information about an exception.
Neutron client for the v2 API expects exceptions to have 'type', 'message'
and 'detail' attributes.This information is extracted and converted into a
dictionary.
:param e: the exception to be reraised
:returns: a structured dict with the exception data
"""
err_data = {'type': e.__class__.__name__,
'message': e, 'detail': ''}
return err_data
def translate(translatable, locale):
"""Translates the object to the given locale.

View File

@ -122,6 +122,13 @@ class RequestTestCase(base.BaseTestCase):
class ResourceTestCase(base.BaseTestCase):
@staticmethod
def _get_deserializer(req_format):
if req_format == 'json':
return wsgi.JSONDeserializer()
else:
return wsgi.XMLDeserializer()
def test_unmapped_neutron_error_with_json(self):
msg = u'\u7f51\u7edc'
@ -260,47 +267,74 @@ class ResourceTestCase(base.BaseTestCase):
self.assertIn(msg_translation,
str(wsgi.JSONDeserializer().deserialize(res.body)))
def test_http_error(self):
@staticmethod
def _make_request_with_side_effect(side_effect, req_format=None):
controller = mock.MagicMock()
controller.test.side_effect = exc.HTTPGatewayTimeout()
controller.test.side_effect = side_effect
resource = webtest.TestApp(wsgi_resource.Resource(controller))
environ = {'wsgiorg.routing_args': (None, {'action': 'test'})}
routing_args = {'action': 'test'}
if req_format:
routing_args.update({'format': req_format})
environ = {'wsgiorg.routing_args': (None, routing_args)}
res = resource.get('', extra_environ=environ, expect_errors=True)
self.assertEqual(res.status_int, exc.HTTPGatewayTimeout.code)
return res
def test_http_error(self):
res = self._make_request_with_side_effect(exc.HTTPGatewayTimeout())
# verify that the exception structure is the one expected
# by the python-neutronclient
self.assertEqual(exc.HTTPGatewayTimeout().explanation,
res.json['NeutronError']['message'])
self.assertEqual('HTTPGatewayTimeout',
res.json['NeutronError']['type'])
self.assertEqual('', res.json['NeutronError']['detail'])
self.assertEqual(exc.HTTPGatewayTimeout.code, res.status_int)
def _test_unhandled_error(self, req_format='json'):
expected_res = {'body': {'NeutronError':
{'detail': '',
'message': _(
'Request Failed: internal server '
'error while processing your request.'),
'type': 'HTTPInternalServerError'}}}
res = self._make_request_with_side_effect(side_effect=Exception(),
req_format=req_format)
self.assertEqual(exc.HTTPInternalServerError.code,
res.status_int)
self.assertEqual(expected_res,
self._get_deserializer(
req_format).deserialize(res.body))
def test_unhandled_error_with_json(self):
expected_res = {'body': {'NeutronError':
_('Request Failed: internal server error '
'while processing your request.')}}
controller = mock.MagicMock()
controller.test.side_effect = Exception()
resource = webtest.TestApp(wsgi_resource.Resource(controller))
environ = {'wsgiorg.routing_args': (None, {'action': 'test',
'format': 'json'})}
res = resource.get('', extra_environ=environ, expect_errors=True)
self.assertEqual(res.status_int, exc.HTTPInternalServerError.code)
self.assertEqual(wsgi.JSONDeserializer().deserialize(res.body),
expected_res)
self._test_unhandled_error()
def test_unhandled_error_with_xml(self):
self._test_unhandled_error(req_format='xml')
def _test_not_implemented_error(self, req_format='json'):
expected_res = {'body': {'NeutronError':
_('Request Failed: internal server error '
'while processing your request.')}}
controller = mock.MagicMock()
controller.test.side_effect = Exception()
{'detail': '',
'message': _(
'The server has either erred or is '
'incapable of performing the requested '
'operation.'),
'type': 'HTTPNotImplemented'}}}
resource = webtest.TestApp(wsgi_resource.Resource(controller))
res = self._make_request_with_side_effect(exc.HTTPNotImplemented(),
req_format=req_format)
self.assertEqual(exc.HTTPNotImplemented.code, res.status_int)
self.assertEqual(expected_res,
self._get_deserializer(
req_format).deserialize(res.body))
environ = {'wsgiorg.routing_args': (None, {'action': 'test',
'format': 'xml'})}
res = resource.get('', extra_environ=environ, expect_errors=True)
self.assertEqual(res.status_int, exc.HTTPInternalServerError.code)
self.assertEqual(wsgi.XMLDeserializer().deserialize(res.body),
expected_res)
def test_not_implemented_error_with_json(self):
self._test_not_implemented_error()
def test_not_implemented_error_with_xml(self):
self._test_not_implemented_error(req_format='xml')
def test_status_200(self):
controller = mock.MagicMock()