]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Port WSGI tests to Python 3
authorVictor Stinner <vstinner@redhat.com>
Wed, 7 Oct 2015 15:38:12 +0000 (17:38 +0200)
committerJohn Griffith <john.griffith8@gmail.com>
Tue, 13 Oct 2015 18:25:51 +0000 (18:25 +0000)
* Replace dict.keys()[0] with list(data.keys())[0]. On Python 3,
  dict.keys() now returns a view which is not indexable.
* Skip SSL tests on Python 3. Tests hang for an unknown reason, they
  must be fixed later.
* Fix unit tests: HTTP body type is bytes, not Unicode.
* Debug.print_generator(): on Python 3, write into sys.stdout.buffer
  instead of sys.stdout, because HTTP body type is bytes not Unicode.
* ResponseObject: encode serializer output to UTF-8 if it's Unicode.
* tox.ini: add the following tests to Python 3.4

  - cinder.tests.unit.api.openstack.test_wsgi
  - cinder.tests.unit.wsgi

Note: Ignore pylint error E1101 on sys.stdout.buffer. pylint on
Python 2 complains that the buffer attribute doesn't exist, whereas
the code is only executed on Python 3 and the attribute exists on
Python 3.

Related-Bug: #1505103
Partial-Implements: blueprint cinder-python3
Change-Id: I0db0e04010e41be71192a2e4db13829114ad6eef

cinder/api/openstack/wsgi.py
cinder/tests/unit/api/openstack/test_wsgi.py
cinder/tests/unit/wsgi/test_eventlet_server.py
cinder/tests/unit/wsgi/test_wsgi.py
cinder/wsgi/common.py
tests-py3.txt

index 54af9801eb959be287076f69bf6a28061dc2e1b0..f2b3215bb43b5670290aa64ef5e36963d31f335b 100644 (file)
@@ -425,7 +425,7 @@ class XMLDictSerializer(DictSerializer):
 
     def default(self, data):
         # We expect data to contain a single key which is the XML root.
-        root_key = data.keys()[0]
+        root_key = list(data.keys())[0]
         doc = minidom.Document()
         node = self._to_xml_node(doc, self.metadata, root_key, data[root_key])
 
@@ -678,7 +678,10 @@ class ResponseObject(object):
             response.headers[hdr] = value
         response.headers['Content-Type'] = content_type
         if self.obj is not None:
-            response.body = serializer.serialize(self.obj)
+            body = serializer.serialize(self.obj)
+            if isinstance(body, six.text_type):
+                body = body.encode('utf-8')
+            response.body = body
 
         return response
 
@@ -710,7 +713,7 @@ def action_peek_json(body):
         raise exception.MalformedRequestBody(reason=msg)
 
     # Return the action and the decoded body...
-    return decoded.keys()[0]
+    return list(decoded.keys())[0]
 
 
 def action_peek_xml(body):
index e462bbf03b106e1afc269c0ae74f48ae817ad3e9..e156007ee3959304e5f6ff6899df6be6dab29758 100644 (file)
@@ -23,13 +23,13 @@ from cinder.tests.unit.api import fakes
 class RequestTest(test.TestCase):
     def test_content_type_missing(self):
         request = wsgi.Request.blank('/tests/123', method='POST')
-        request.body = "<body />"
+        request.body = b"<body />"
         self.assertIsNone(request.get_content_type())
 
     def test_content_type_unsupported(self):
         request = wsgi.Request.blank('/tests/123', method='POST')
         request.headers["Content-Type"] = "text/html"
-        request.body = "asdf<br />"
+        request.body = b"asdf<br />"
         self.assertRaises(exception.InvalidContentType,
                           request.get_content_type)
 
@@ -206,10 +206,10 @@ class DictSerializerTest(test.TestCase):
 class XMLDictSerializerTest(test.TestCase):
     def test_xml(self):
         input_dict = dict(servers=dict(a=(2, 3)))
-        expected_xml = '<serversxmlns="asdf"><a>(2,3)</a></servers>'
+        expected_xml = b'<serversxmlns="asdf"><a>(2,3)</a></servers>'
         serializer = wsgi.XMLDictSerializer(xmlns="asdf")
         result = serializer.serialize(input_dict)
-        result = result.replace('\n', '').replace(' ', '')
+        result = result.replace(b'\n', b'').replace(b' ', b'')
         self.assertEqual(expected_xml, result)
 
 
@@ -317,7 +317,7 @@ class ResourceTest(test.TestCase):
         req = webob.Request.blank('/tests')
         app = fakes.TestRouter(Controller())
         response = req.get_response(app)
-        self.assertEqual('off', response.body)
+        self.assertEqual(b'off', response.body)
         self.assertEqual(200, response.status_int)
 
     def test_resource_not_authorized(self):
@@ -443,7 +443,7 @@ class ResourceTest(test.TestCase):
 
         request = wsgi.Request.blank('/', method='POST')
         request.headers['Content-Type'] = 'application/none'
-        request.body = 'foo'
+        request.body = b'foo'
 
         content_type, body = resource.get_body(request)
         self.assertIsNone(content_type)
@@ -458,7 +458,7 @@ class ResourceTest(test.TestCase):
         resource = wsgi.Resource(controller)
 
         request = wsgi.Request.blank('/', method='POST')
-        request.body = 'foo'
+        request.body = b'foo'
 
         content_type, body = resource.get_body(request)
         self.assertIsNone(content_type)
@@ -474,7 +474,7 @@ class ResourceTest(test.TestCase):
 
         request = wsgi.Request.blank('/', method='POST')
         request.headers['Content-Type'] = 'application/json'
-        request.body = ''
+        request.body = b''
 
         content_type, body = resource.get_body(request)
         self.assertIsNone(content_type)
@@ -490,11 +490,11 @@ class ResourceTest(test.TestCase):
 
         request = wsgi.Request.blank('/', method='POST')
         request.headers['Content-Type'] = 'application/json'
-        request.body = 'foo'
+        request.body = b'foo'
 
         content_type, body = resource.get_body(request)
         self.assertEqual('application/json', content_type)
-        self.assertEqual('foo', body)
+        self.assertEqual(b'foo', body)
 
     def test_deserialize_badtype(self):
         class Controller(object):
@@ -952,7 +952,7 @@ class ResponseObjectTest(test.TestCase):
             self.assertEqual('header1', response.headers['X-header1'])
             self.assertEqual('header2', response.headers['X-header2'])
             self.assertEqual(202, response.status_int)
-            self.assertEqual(mtype, response.body)
+            self.assertEqual(mtype, response.body.decode('utf-8'))
 
 
 class ValidBodyTest(test.TestCase):
index 600cd7e68cfaf924e4c02d47df3ab7554c593ffb..f14a0bb257f4e8b5eb101c2151548e109a299552 100644 (file)
@@ -205,6 +205,7 @@ class TestWSGIServer(test.TestCase):
         self.assertFalse(buf)
         server.stop()
 
+    @testtools.skipIf(six.PY3, "bug/1505103: test hangs on Python 3")
     def test_app_using_ssl(self):
         CONF.set_default("ssl_cert_file",
                          os.path.join(TEST_VAR_DIR, 'certificate.crt'))
@@ -229,6 +230,7 @@ class TestWSGIServer(test.TestCase):
 
     @testtools.skipIf(not _ipv6_configured(),
                       "Test requires an IPV6 configured interface")
+    @testtools.skipIf(six.PY3, "bug/1505103: test hangs on Python 3")
     def test_app_using_ipv6_and_ssl(self):
         CONF.set_default("ssl_cert_file",
                          os.path.join(TEST_VAR_DIR, 'certificate.crt'))
index 63f0550165a5a4fc86374aa71afefe91a84f85f6..9444ace6b205a39c4245a3fd5d44e8988466fe63 100644 (file)
@@ -39,12 +39,13 @@ class Test(test.TestCase):
 
             def __call__(self, environ, start_response):
                 start_response("200", [("X-Test", "checking")])
-                return ['Test result']
+                return [b'Test result']
 
-        with mock.patch('sys.stdout', new=six.StringIO()):
+        with mock.patch('sys.stdout', new=six.StringIO()) as mock_stdout:
+            mock_stdout.buffer = six.BytesIO()
             application = wsgi.Debug(Application())
             result = webob.Request.blank('/').get_response(application)
-            self.assertEqual("Test result", result.body)
+            self.assertEqual(b"Test result", result.body)
 
     def test_router(self):
 
@@ -53,7 +54,7 @@ class Test(test.TestCase):
 
             def __call__(self, environ, start_response):
                 start_response("200", [])
-                return ['Router result']
+                return [b'Router result']
 
         class Router(wsgi.Router):
             """Test router."""
@@ -64,6 +65,6 @@ class Test(test.TestCase):
                 super(Router, self).__init__(mapper)
 
         result = webob.Request.blank('/test').get_response(Router())
-        self.assertEqual("Router result", result.body)
+        self.assertEqual(b"Router result", result.body)
         result = webob.Request.blank('/bad').get_response(Router())
-        self.assertNotEqual("Router result", result.body)
+        self.assertNotEqual(b"Router result", result.body)
index 2fd4e6abedf0965f0daf4eeead3cadfa99449cb9..0c2db6bc7eb7e5fd4e56e3de0a73758dff97b97e 100644 (file)
@@ -20,6 +20,7 @@ from oslo_config import cfg
 from oslo_log import log as logging
 from paste import deploy
 import routes.middleware
+import six
 import webob.dec
 import webob.exc
 
@@ -193,8 +194,13 @@ class Debug(Middleware):
         """Iterator that prints the contents of a wrapper string."""
         print(('*' * 40) + ' BODY')  # noqa
         for part in app_iter:
-            sys.stdout.write(part)
-            sys.stdout.flush()
+            if six.PY3:
+                sys.stdout.flush()
+                sys.stdout.buffer.write(part)   # pylint: disable=E1101
+                sys.stdout.buffer.flush()       # pylint: disable=E1101
+            else:
+                sys.stdout.write(part)
+                sys.stdout.flush()
             yield part
         print()  # noqa
 
index aaf5e2456d206da2ad955a24b0ba11d96f51535d..0e3d34319515df98c65cd10c9f780288204430a5 100644 (file)
@@ -1,3 +1,4 @@
+cinder.tests.unit.api.openstack.test_wsgi
 cinder.tests.unit.image.test_cache
 cinder.tests.unit.image.test_glance
 cinder.tests.unit.keymgr.test_mock_key_mgr
@@ -106,3 +107,4 @@ cinder.tests.unit.windows.test_vhdutils
 cinder.tests.unit.windows.test_windows
 cinder.tests.unit.windows.test_windows_remotefs
 cinder.tests.unit.windows.test_windows_utils
+cinder.tests.unit.wsgi