]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Fix translation of CinderExceptions in REST API
authorLuis A. Garcia <luis@linux.vnet.ibm.com>
Tue, 24 Sep 2013 22:07:55 +0000 (22:07 +0000)
committerLuis A. Garcia <luis@linux.vnet.ibm.com>
Wed, 25 Sep 2013 20:07:38 +0000 (20:07 +0000)
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

cinder/api/middleware/fault.py
cinder/tests/test_wsgi.py

index dddd166ac509c71238c8dee5cbe085ad2c7ba266..0a500094c2f2fd1830f0aa9509bcace0c828d28a 100644 (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)
index de30e02fa552e126e22fa3d3509587212822f0b7..ba7f15d16b969171f5f98a3507dee455d3d91fa8 100644 (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)