From a1a898c4667b8e99d733f1391e0d325c8ce6e187 Mon Sep 17 00:00:00 2001 From: "Luis A. Garcia" Date: Tue, 24 Sep 2013 22:07:55 +0000 Subject: [PATCH] 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 --- cinder/api/middleware/fault.py | 8 ++++-- cinder/tests/test_wsgi.py | 48 +++++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/cinder/api/middleware/fault.py b/cinder/api/middleware/fault.py index dddd166ac..0a500094c 100644 --- a/cinder/api/middleware/fault.py +++ b/cinder/api/middleware/fault.py @@ -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) diff --git a/cinder/tests/test_wsgi.py b/cinder/tests/test_wsgi.py index de30e02fa..ba7f15d16 100644 --- a/cinder/tests/test_wsgi.py +++ b/cinder/tests/test_wsgi.py @@ -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) -- 2.45.2