]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Return unicode for object in json and xml serializer
authorHe Jie Xu <xuhj@linux.vnet.ibm.com>
Tue, 26 Mar 2013 23:42:20 +0000 (07:42 +0800)
committerHe Jie Xu <xuhj@linux.vnet.ibm.com>
Mon, 1 Apr 2013 09:51:10 +0000 (17:51 +0800)
Fix bug 1160644
Fix bug 1119790

When try to serialize an exception object as json, it failed
with 'ValueError: Circular reference detected' that is same error
as bug 119790. So this patch fixes bug 119790 too.

Change-Id: I0da2616f4ec59da31be054b8be2f7a140f59d63a

quantum/api/v2/resource.py
quantum/tests/unit/test_api_v2_resource.py
quantum/tests/unit/test_wsgi.py
quantum/wsgi.py

index be710963022fc681f0150873047ddb5218c9fccd..97fc8a8adafa62921b6c6e385240338a78f5f543 100644 (file)
@@ -83,7 +83,7 @@ def Resource(controller, faults=None, deserializers=None, serializers=None):
         except (exceptions.QuantumException,
                 netaddr.AddrFormatError) as e:
             LOG.exception(_('%s failed'), action)
-            body = serializer.serialize({'QuantumError': str(e)})
+            body = serializer.serialize({'QuantumError': e})
             kwargs = {'body': body, 'content_type': content_type}
             for fault in faults:
                 if isinstance(e, fault):
@@ -91,7 +91,7 @@ def Resource(controller, faults=None, deserializers=None, serializers=None):
             raise webob.exc.HTTPInternalServerError(**kwargs)
         except webob.exc.HTTPException as e:
             LOG.exception(_('%s failed'), action)
-            e.body = serializer.serialize({'QuantumError': str(e)})
+            e.body = serializer.serialize({'QuantumError': e})
             e.content_type = content_type
             raise
         except Exception as e:
index 7328c1c6d092e26bae93b3388f581d21ea3ea19e..f4580de4d00dbdfc0deaeb38ccd1b116327e1db5 100644 (file)
@@ -100,27 +100,81 @@ class RequestTestCase(base.BaseTestCase):
 
 
 class ResourceTestCase(base.BaseTestCase):
-    def test_unmapped_quantum_error(self):
+    def test_unmapped_quantum_error_with_json(self):
+        msg = u'\u7f51\u7edc'
+
+        class TestException(q_exc.QuantumException):
+            message = msg
+        expected_res = {'body': {'QuantumError': msg}}
         controller = mock.MagicMock()
-        controller.test.side_effect = q_exc.QuantumException()
+        controller.test.side_effect = TestException()
 
         resource = webtest.TestApp(wsgi_resource.Resource(controller))
 
-        environ = {'wsgiorg.routing_args': (None, {'action': 'test'})}
+        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)
 
-    def test_mapped_quantum_error(self):
+    def test_unmapped_quantum_error_with_xml(self):
+        msg = u'\u7f51\u7edc'
+
+        class TestException(q_exc.QuantumException):
+            message = msg
+        expected_res = {'body': {'QuantumError': msg}}
         controller = mock.MagicMock()
-        controller.test.side_effect = q_exc.QuantumException()
+        controller.test.side_effect = TestException()
+
+        resource = webtest.TestApp(wsgi_resource.Resource(controller))
+
+        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)
 
-        faults = {q_exc.QuantumException: exc.HTTPGatewayTimeout}
+    def test_mapped_quantum_error_with_json(self):
+        msg = u'\u7f51\u7edc'
+
+        class TestException(q_exc.QuantumException):
+            message = msg
+        expected_res = {'body': {'QuantumError': msg}}
+        controller = mock.MagicMock()
+        controller.test.side_effect = TestException()
+
+        faults = {TestException: exc.HTTPGatewayTimeout}
         resource = webtest.TestApp(wsgi_resource.Resource(controller,
                                                           faults=faults))
 
-        environ = {'wsgiorg.routing_args': (None, {'action': 'test'})}
+        environ = {'wsgiorg.routing_args': (None, {'action': 'test',
+                                                   'format': 'json'})}
+        res = resource.get('', extra_environ=environ, expect_errors=True)
+        self.assertEqual(res.status_int, exc.HTTPGatewayTimeout.code)
+        self.assertEqual(wsgi.JSONDeserializer().deserialize(res.body),
+                         expected_res)
+
+    def test_mapped_quantum_error_with_xml(self):
+        msg = u'\u7f51\u7edc'
+
+        class TestException(q_exc.QuantumException):
+            message = msg
+        expected_res = {'body': {'QuantumError': msg}}
+        controller = mock.MagicMock()
+        controller.test.side_effect = TestException()
+
+        faults = {TestException: exc.HTTPGatewayTimeout}
+        resource = webtest.TestApp(wsgi_resource.Resource(controller,
+                                                          faults=faults))
+
+        environ = {'wsgiorg.routing_args': (None, {'action': 'test',
+                                                   'format': 'xml'})}
         res = resource.get('', extra_environ=environ, expect_errors=True)
         self.assertEqual(res.status_int, exc.HTTPGatewayTimeout.code)
+        self.assertEqual(wsgi.XMLDeserializer().deserialize(res.body),
+                         expected_res)
 
     def test_http_error(self):
         controller = mock.MagicMock()
@@ -132,15 +186,37 @@ class ResourceTestCase(base.BaseTestCase):
         res = resource.get('', extra_environ=environ, expect_errors=True)
         self.assertEqual(res.status_int, exc.HTTPGatewayTimeout.code)
 
-    def test_unhandled_error(self):
+    def test_unhandled_error_with_json(self):
+        expected_res = {'body': {'QuantumError':
+                                 _('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'})}
+        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)
+
+    def test_unhandled_error_with_xml(self):
+        expected_res = {'body': {'QuantumError':
+                                 _('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': '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_status_200(self):
         controller = mock.MagicMock()
index c3d7561023be413e20b38d7f65ed91b8eadb6c5e..b775a83eca92d244272720702401c50121ba433d 100644 (file)
@@ -614,6 +614,24 @@ class JSONDictSerializerTest(base.BaseTestCase):
 
         self.assertEqual(result, expected_json)
 
+    def test_json_with_utf8(self):
+        input_dict = dict(servers=dict(a=(2, '\xe7\xbd\x91\xe7\xbb\x9c')))
+        expected_json = '{"servers":{"a":[2,"\\u7f51\\u7edc"]}}'
+        serializer = wsgi.JSONDictSerializer()
+        result = serializer.serialize(input_dict)
+        result = result.replace('\n', '').replace(' ', '')
+
+        self.assertEqual(result, expected_json)
+
+    def test_json_with_unicode(self):
+        input_dict = dict(servers=dict(a=(2, u'\u7f51\u7edc')))
+        expected_json = '{"servers":{"a":[2,"\\u7f51\\u7edc"]}}'
+        serializer = wsgi.JSONDictSerializer()
+        result = serializer.serialize(input_dict)
+        result = result.replace('\n', '').replace(' ', '')
+
+        self.assertEqual(result, expected_json)
+
 
 class TextDeserializerTest(base.BaseTestCase):
 
@@ -654,6 +672,20 @@ class JSONDeserializerTest(base.BaseTestCase):
         self.assertRaises(
             exception.MalformedRequestBody, deserializer.default, data_string)
 
+    def test_json_with_utf8(self):
+        data = '{"a": "\xe7\xbd\x91\xe7\xbb\x9c"}'
+        as_dict = {'body': {'a': u'\u7f51\u7edc'}}
+        deserializer = wsgi.JSONDeserializer()
+        self.assertEqual(
+            deserializer.deserialize(data), as_dict)
+
+    def test_json_with_unicode(self):
+        data = '{"a": "\u7f51\u7edc"}'
+        as_dict = {'body': {'a': u'\u7f51\u7edc'}}
+        deserializer = wsgi.JSONDeserializer()
+        self.assertEqual(
+            deserializer.deserialize(data), as_dict)
+
 
 class XMLDeserializerTest(base.BaseTestCase):
     def test_xml_empty(self):
@@ -681,6 +713,14 @@ class XMLDeserializerTest(base.BaseTestCase):
         self.assertRaises(
             exception.MalformedRequestBody, deserializer.default, data_string)
 
+    def test_xml_with_utf8(self):
+        xml = '<a>\xe7\xbd\x91\xe7\xbb\x9c</a>'
+        as_dict = {'body': {'a': u'\u7f51\u7edc'}}
+        deserializer = wsgi.XMLDeserializer()
+
+        self.assertEqual(
+            deserializer.deserialize(xml), as_dict)
+
 
 class RequestHeadersDeserializerTest(base.BaseTestCase):
 
@@ -1044,6 +1084,34 @@ class XMLDictSerializerTest(base.BaseTestCase):
         result = result.replace('\n', '').replace(' ', '')
         self.assertEqual(expected, result)
 
+    def test_xml_with_utf8(self):
+        data = {'servers': '\xe7\xbd\x91\xe7\xbb\x9c'}
+        serializer = wsgi.XMLDictSerializer()
+        expected = (
+            '<?xmlversion=\'1.0\'encoding=\'UTF-8\'?>'
+            '<serversxmlns="http://openstack.org/quantum/api/v2.0"'
+            'xmlns:quantum="http://openstack.org/quantum/api/v2.0"'
+            'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
+            '\xe7\xbd\x91\xe7\xbb\x9c</servers>'
+        )
+        result = serializer(data)
+        result = result.replace('\n', '').replace(' ', '')
+        self.assertEqual(expected, result)
+
+    def test_xml_with_unicode(self):
+        data = {'servers': u'\u7f51\u7edc'}
+        serializer = wsgi.XMLDictSerializer()
+        expected = (
+            '<?xmlversion=\'1.0\'encoding=\'UTF-8\'?>'
+            '<serversxmlns="http://openstack.org/quantum/api/v2.0"'
+            'xmlns:quantum="http://openstack.org/quantum/api/v2.0"'
+            'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
+            '\xe7\xbd\x91\xe7\xbb\x9c</servers>'
+        )
+        result = serializer(data)
+        result = result.replace('\n', '').replace(' ', '')
+        self.assertEqual(expected, result)
+
 
 class TestWSGIServerWithSSL(base.BaseTestCase):
     """WSGI server tests."""
index 5daec8b5847f7f28c53b27fa01f1ef5996d4db19..8558729f8553ae50a4daa555755132561fd6c225 100644 (file)
@@ -334,7 +334,9 @@ class JSONDictSerializer(DictSerializer):
     """Default JSON request body serialization"""
 
     def default(self, data):
-        return jsonutils.dumps(data)
+        def sanitizer(obj):
+            return unicode(obj)
+        return jsonutils.dumps(data, default=sanitizer)
 
 
 class XMLDictSerializer(DictSerializer):
@@ -467,7 +469,10 @@ class XMLDictSerializer(DictSerializer):
             LOG.debug(_("Data %(data)s type is %(type)s"),
                       {'data': data,
                        'type': type(data)})
-            result.text = str(data)
+            if isinstance(data, str):
+                result.text = unicode(data, 'utf-8')
+            else:
+                result.text = unicode(data)
         return result
 
     def _create_link_nodes(self, xml_doc, links):