Fix translation of CinderExceptions in REST API

When creating a Fault from a CinderException wrapped in an
HTTPException, we were converting the inner explanation to unicode
before it was able to reach the Fault's call() method which is where
translation occurs, and unicode objects can't be translated.

This patch preserves the CinderException's Message object and puts it in
another Message object as the explanation to the HTTPException so it can
be translated.

Fixes bug: #1229967

Change-Id: Ida71908b639da32b4b85846a117ef21da2fe685b
This commit is contained in:
Luis A. Garcia 2013-09-24 22:07:55 +00:00
parent 1094467f9b
commit a1a898c466
2 changed files with 53 additions and 3 deletions

View File

@ -20,6 +20,7 @@ import webob.dec
import webob.exc
from cinder.api.openstack import wsgi
from cinder import exception
from cinder.openstack.common import log as logging
from cinder import utils
from cinder import wsgi as base_wsgi
@ -63,8 +64,11 @@ class FaultWrapper(base_wsgi.Middleware):
# inconsistent with the EC2 API to hide every exception,
# including those that are safe to expose, see bug 1021373
if safe:
outer.explanation = '%s: %s' % (inner.__class__.__name__,
unicode(inner))
msg = (inner.msg if isinstance(inner, exception.CinderException)
else unicode(inner))
params = {'exception': inner.__class__.__name__,
'explanation': msg}
outer.explanation = _('%(exception)s: %(explanation)s') % params
return wsgi.Fault(outer)
@webob.dec.wsgify(RequestClass=wsgi.Request)

View File

@ -18,6 +18,7 @@
"""Unit tests for `cinder.wsgi`."""
import mock
import os.path
import ssl
import tempfile
@ -28,8 +29,8 @@ import testtools
import webob
import webob.dec
from cinder.api.middleware import fault
from cinder import exception
from cinder.openstack.common import gettextutils
from cinder import test
from cinder import utils
import cinder.wsgi
@ -188,6 +189,13 @@ class TestWSGIServer(test.TestCase):
class ExceptionTest(test.TestCase):
def _wsgi_app(self, inner_app):
# NOTE(luisg): In order to test localization, we need to
# make sure the lazy _() is installed in the 'fault' module
# also we don't want to install the _() system-wide and
# potentially break other test cases, so we do it here for this
# test suite only.
gettextutils.install('', lazy=True)
from cinder.api.middleware import fault
return fault.FaultWrapper(inner_app)
def _do_test_exception_safety_reflected_in_faults(self, expose):
@ -258,3 +266,41 @@ class ExceptionTest(test.TestCase):
api = self._wsgi_app(fail)
resp = webob.Request.blank('/').get_response(api)
self.assertEqual(500, resp.status_int)
@mock.patch('cinder.openstack.common.gettextutils.get_localized_message')
def test_cinder_exception_with_localized_explanation(self, mock_t9n):
msg = 'My Not Found'
msg_translation = 'Mi No Encontrado'
message = gettextutils.Message(msg, '')
@webob.dec.wsgify
def fail(req):
class MyVolumeNotFound(exception.NotFound):
def __init__(self):
self.msg = message
self.safe = True
raise MyVolumeNotFound()
# Test response without localization
def mock_get_non_localized_message(msgid, locale):
return msg
mock_t9n.side_effect = mock_get_non_localized_message
api = self._wsgi_app(fail)
resp = webob.Request.blank('/').get_response(api)
self.assertEqual(404, resp.status_int)
self.assertIn(msg, resp.body)
# Test response with localization
def mock_get_localized_message(msgid, locale):
if isinstance(msgid, gettextutils.Message):
return msg_translation
return msgid
mock_t9n.side_effect = mock_get_localized_message
api = self._wsgi_app(fail)
resp = webob.Request.blank('/').get_response(api)
self.assertEqual(404, resp.status_int)
self.assertIn(msg_translation, resp.body)