diff --git a/glance_store/exceptions.py b/glance_store/exceptions.py index 79af2987..ef4a363d 100644 --- a/glance_store/exceptions.py +++ b/glance_store/exceptions.py @@ -15,7 +15,8 @@ """Glance Store exception subclasses""" -from six.moves import urllib +import six +import six.moves.urllib.parse as urlparse from glance_store import i18n @@ -32,7 +33,7 @@ class UnsupportedBackend(BackendException): class RedirectException(Exception): def __init__(self, url): - self.url = urllib.parse.urlparse(url) + self.url = urlparse.urlparse(url) class GlanceStoreException(Exception): @@ -43,11 +44,24 @@ class GlanceStoreException(Exception): a 'message' property. That message will get printf'd with the keyword arguments provided to the constructor. """ - message = '' + message = _("An unknown exception occurred") - def __init__(self, **kwargs): - self.msg = kwargs.pop('message', None) or self.message % kwargs - super(Exception, self).__init__(self.msg) + def __init__(self, message=None, **kwargs): + if not message: + message = self.message + try: + if kwargs: + message = message % kwargs + except Exception: + pass + self.msg = message + super(GlanceStoreException, self).__init__(message) + + def __unicode__(self): + # NOTE(flwang): By default, self.msg is an instance of Message, which + # can't be converted by str(). Based on the definition of + # __unicode__, it should return unicode always. + return six.text_type(self.msg) class MissingCredentialError(GlanceStoreException): diff --git a/glance_store/tests/unit/test_exceptions.py b/glance_store/tests/unit/test_exceptions.py new file mode 100644 index 00000000..d9fe1e18 --- /dev/null +++ b/glance_store/tests/unit/test_exceptions.py @@ -0,0 +1,57 @@ +# Copyright 2015 OpenStack Foundation +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +from oslo_utils import encodeutils +from oslotest import base +import six + +import glance_store + + +class TestExceptions(base.BaseTestCase): + """Test routines in glance_store.common.utils.""" + def test_backend_exception(self): + msg = glance_store.BackendException() + self.assertIn(u'', encodeutils.exception_to_unicode(msg)) + + def test_unsupported_backend_exception(self): + msg = glance_store.UnsupportedBackend() + self.assertIn(u'', encodeutils.exception_to_unicode(msg)) + + def test_redirect_exception(self): + # Just checks imports work ok + glance_store.RedirectException(url='http://localhost') + + def test_exception_no_message(self): + msg = glance_store.NotFound() + self.assertIn('Image %(image)s not found', + encodeutils.exception_to_unicode(msg)) + + def test_exception_not_found_with_image(self): + msg = glance_store.NotFound(image='123') + self.assertIn('Image 123 not found', + encodeutils.exception_to_unicode(msg)) + + def test_exception_with_message(self): + msg = glance_store.NotFound('Some message') + self.assertIn('Some message', encodeutils.exception_to_unicode(msg)) + + def test_exception_with_kwargs(self): + msg = glance_store.NotFound('Message: %(foo)s', foo='bar') + self.assertIn('Message: bar', encodeutils.exception_to_unicode(msg)) + + def test_non_unicode_error_msg(self): + exc = glance_store.NotFound(str('test')) + self.assertIsInstance(encodeutils.exception_to_unicode(exc), + six.text_type)