From: Victor Stinner <vstinner@redhat.com>
Date: Tue, 9 Feb 2016 17:40:21 +0000 (+0100)
Subject: Port API contribs to Python 3
X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=ebf00a5de541bb5d51996f065db17c27b9a0bc70;p=openstack-build%2Fcinder-build.git

Port API contribs to Python 3

* Replace dict.iteritems() with dict.items(), dict.iteritems() was
  removed in Python 3.
* Replace dict.values() with list(dict.values()) to get a list on
  Python 3.
* HTTP body type must be bytes:

  - Fix unit tests to use bytes strings for HTTP body
  - Encode XML to UTF-8 on Python 3.

* Use "%r" instead of "%s" to format request and response in test to
  avoid BytesWarning on Python 3.
* tests-py3.txt: add cinder.tests.unit.api.contrib

Partial-Implements: blueprint cinder-python3
Change-Id: I65e412b2897635db5c8dfe13d61e71c52e0603e7
---

diff --git a/cinder/api/contrib/volume_actions.py b/cinder/api/contrib/volume_actions.py
index 225ad5e27..d2db66c36 100644
--- a/cinder/api/contrib/volume_actions.py
+++ b/cinder/api/contrib/volume_actions.py
@@ -15,6 +15,7 @@
 
 from oslo_log import log as logging
 import oslo_messaging as messaging
+from oslo_utils import encodeutils
 from oslo_utils import strutils
 import six
 import webob
@@ -261,7 +262,8 @@ class VolumeActionsController(wsgi.Controller):
         try:
             force = strutils.bool_from_string(force, strict=True)
         except ValueError as error:
-            msg = _("Invalid value for 'force': '%s'") % error.message
+            err_msg = encodeutils.exception_to_unicode(error)
+            msg = _("Invalid value for 'force': '%s'") % err_msg
             raise webob.exc.HTTPBadRequest(explanation=msg)
 
         try:
@@ -333,7 +335,8 @@ class VolumeActionsController(wsgi.Controller):
             readonly_flag = strutils.bool_from_string(readonly_flag,
                                                       strict=True)
         except ValueError as error:
-            msg = _("Invalid value for 'readonly': '%s'") % error.message
+            err_msg = encodeutils.exception_to_unicode(error)
+            msg = _("Invalid value for 'readonly': '%s'") % err_msg
             raise webob.exc.HTTPBadRequest(explanation=msg)
 
         self.volume_api.update_readonly_flag(context, volume, readonly_flag)
@@ -373,7 +376,8 @@ class VolumeActionsController(wsgi.Controller):
             bootable = strutils.bool_from_string(bootable,
                                                  strict=True)
         except ValueError as error:
-            msg = _("Invalid value for 'bootable': '%s'") % error.message
+            err_msg = encodeutils.exception_to_unicode(error)
+            msg = _("Invalid value for 'bootable': '%s'") % err_msg
             raise webob.exc.HTTPBadRequest(explanation=msg)
 
         update_dict = {'bootable': bootable}
diff --git a/cinder/api/contrib/volume_type_encryption.py b/cinder/api/contrib/volume_type_encryption.py
index c0aeb72bf..5ffc7d026 100644
--- a/cinder/api/contrib/volume_type_encryption.py
+++ b/cinder/api/contrib/volume_type_encryption.py
@@ -46,7 +46,7 @@ class VolumeTypeEncryptionController(wsgi.Controller):
         encryption_specs = {}
         if not encryption_ref:
             return encryption_specs
-        for key, value in encryption_ref.iteritems():
+        for key, value in encryption_ref.items():
             encryption_specs[key] = value
         return encryption_specs
 
diff --git a/cinder/tests/unit/api/contrib/test_backups.py b/cinder/tests/unit/api/contrib/test_backups.py
index 3016e4b5a..dcd0e54ad 100644
--- a/cinder/tests/unit/api/contrib/test_backups.py
+++ b/cinder/tests/unit/api/contrib/test_backups.py
@@ -693,10 +693,14 @@ class BackupsAPITestCase(test.TestCase):
 
         volume_id = utils.create_volume(self.context, size=2)['id']
 
+        body = ('<backup display_name="backup-001" '
+                'display_description="Nightly Backup" '
+                'volume_id="%s" container="Container001"/>' % volume_id)
+        if isinstance(body, six.text_type):
+            body = body.encode('utf-8')
+
         req = webob.Request.blank('/v2/fake/backups')
-        req.body = ('<backup display_name="backup-001" '
-                    'display_description="Nightly Backup" '
-                    'volume_id="%s" container="Container001"/>' % volume_id)
+        req.body = body
         req.method = 'POST'
         req.headers['Content-Type'] = 'application/xml'
         req.headers['Accept'] = 'application/xml'
@@ -1165,8 +1169,12 @@ class BackupsAPITestCase(test.TestCase):
                                         size=2,
                                         display_name=volume_name)['id']
 
+        body = '<restore volume_id="%s"/>' % volume_id
+        if isinstance(body, six.text_type):
+            body = body.encode('utf-8')
+
         req = webob.Request.blank('/v2/fake/backups/%s/restore' % backup_id)
-        req.body = '<restore volume_id="%s"/>' % volume_id
+        req.body = body
         req.method = 'POST'
         req.headers['Content-Type'] = 'application/xml'
         req.headers['Accept'] = 'application/xml'
@@ -1792,14 +1800,17 @@ class BackupsAPITestCase(test.TestCase):
         _mock_import_record_rpc.return_value = None
         _mock_list_services.return_value = [backup_service]
 
-        req = webob.Request.blank('/v2/fake/backups/import_record')
         if six.PY2:
             backup_url = backup_url.encode('utf-8')
-        req.body = ('<backup-record backup_service="%(backup_service)s" '
-                    'backup_url="%(backup_url)s"/>') \
-            % {'backup_url': backup_url,
-               'backup_service': backup_service}
+        body = ('<backup-record backup_service="%(backup_service)s" '
+                'backup_url="%(backup_url)s"/>'
+                % {'backup_url': backup_url,
+                   'backup_service': backup_service})
+        if isinstance(body, six.text_type):
+            body = body.encode('utf-8')
 
+        req = webob.Request.blank('/v2/fake/backups/import_record')
+        req.body = body
         req.method = 'POST'
         req.headers['Content-Type'] = 'application/xml'
         req.headers['Accept'] = 'application/xml'
diff --git a/cinder/tests/unit/api/contrib/test_volume_image_metadata.py b/cinder/tests/unit/api/contrib/test_volume_image_metadata.py
index 207f2ac2d..be986750c 100644
--- a/cinder/tests/unit/api/contrib/test_volume_image_metadata.py
+++ b/cinder/tests/unit/api/contrib/test_volume_image_metadata.py
@@ -341,5 +341,7 @@ class VolumeImageMetadataXMLTest(VolumeImageMetadataTest):
                 volume, 'volume_image_metadata'
             )
             for volume in volume_list]
-        return map(wsgi.MetadataXMLDeserializer().extract_metadata,
-                   image_metadata_list)
+
+        metadata_deserializer = wsgi.MetadataXMLDeserializer()
+        return [metadata_deserializer.extract_metadata(image_metadata)
+                for image_metadata in image_metadata_list]
diff --git a/cinder/tests/unit/api/contrib/test_volume_replication.py b/cinder/tests/unit/api/contrib/test_volume_replication.py
index 20e688461..3a0385782 100644
--- a/cinder/tests/unit/api/contrib/test_volume_replication.py
+++ b/cinder/tests/unit/api/contrib/test_volume_replication.py
@@ -19,6 +19,7 @@ Tests for volume replication API code.
 import mock
 from oslo_config import cfg
 from oslo_serialization import jsonutils
+import six
 import webob
 
 from cinder import context
@@ -55,6 +56,8 @@ class VolumeReplicationAPITestCase(test.TestCase):
             body = '<os-%s-replica/>' % operation
             req.headers['Content-Type'] = 'application/xml'
             req.headers['Accept'] = 'application/xml'
+            if isinstance(body, six.text_type):
+                body = body.encode('utf-8')
             req.body = body
         else:
             body = {'os-%s-replica' % operation: ''}
@@ -68,12 +71,12 @@ class VolumeReplicationAPITestCase(test.TestCase):
 
     def test_promote_bad_id(self):
         (req, res) = self._get_resp('promote', 'fake')
-        msg = ("request: %s\nresult: %s" % (req, res))
+        msg = ("request: %r\nresult: %r" % (req, res))
         self.assertEqual(404, res.status_int, msg)
 
     def test_promote_bad_id_xml(self):
         (req, res) = self._get_resp('promote', 'fake', xml=True)
-        msg = ("request: %s\nresult: %s" % (req, res))
+        msg = ("request: %r\nresult: %r" % (req, res))
         self.assertEqual(404, res.status_int, msg)
 
     def test_promote_volume_not_replicated(self):
@@ -81,7 +84,7 @@ class VolumeReplicationAPITestCase(test.TestCase):
             self.ctxt,
             **self.volume_params)
         (req, res) = self._get_resp('promote', volume['id'])
-        msg = ("request: %s\nresult: %s" % (req, res))
+        msg = ("request: %r\nresult: %r" % (req, res))
         self.assertEqual(400, res.status_int, msg)
 
     def test_promote_volume_not_replicated_xml(self):
@@ -89,7 +92,7 @@ class VolumeReplicationAPITestCase(test.TestCase):
             self.ctxt,
             **self.volume_params)
         (req, res) = self._get_resp('promote', volume['id'], xml=True)
-        msg = ("request: %s\nresult: %s" % (req, res))
+        msg = ("request: %r\nresult: %r" % (req, res))
         self.assertEqual(400, res.status_int, msg)
 
     @mock.patch('cinder.volume.rpcapi.VolumeAPI.promote_replica')
@@ -101,7 +104,7 @@ class VolumeReplicationAPITestCase(test.TestCase):
                                                replication_status = 'active',
                                                **self.volume_params)
             (req, res) = self._get_resp('promote', volume['id'])
-            msg = ("request: %s\nresult: %s" % (req, res))
+            msg = ("request: %r\nresult: %r" % (req, res))
             self.assertEqual(400, res.status_int, msg)
 
         for status in ['available']:
@@ -110,7 +113,7 @@ class VolumeReplicationAPITestCase(test.TestCase):
                                                replication_status = 'active',
                                                **self.volume_params)
             (req, res) = self._get_resp('promote', volume['id'])
-            msg = ("request: %s\nresult: %s" % (req, res))
+            msg = ("request: %r\nresult: %r" % (req, res))
             self.assertEqual(202, res.status_int, msg)
 
     @mock.patch('cinder.volume.rpcapi.VolumeAPI.promote_replica')
@@ -122,7 +125,7 @@ class VolumeReplicationAPITestCase(test.TestCase):
                                                replication_status = 'active',
                                                **self.volume_params)
             (req, res) = self._get_resp('promote', volume['id'], xml=True)
-            msg = ("request: %s\nresult: %s" % (req, res))
+            msg = ("request: %r\nresult: %r" % (req, res))
             self.assertEqual(400, res.status_int, msg)
 
         for status in ['available']:
@@ -131,7 +134,7 @@ class VolumeReplicationAPITestCase(test.TestCase):
                                                replication_status = 'active',
                                                **self.volume_params)
             (req, res) = self._get_resp('promote', volume['id'], xml=True)
-            msg = ("request: %s\nresult: %s" % (req, res))
+            msg = ("request: %r\nresult: %r" % (req, res))
             self.assertEqual(202, res.status_int, msg)
 
     @mock.patch('cinder.volume.rpcapi.VolumeAPI.promote_replica')
@@ -143,7 +146,7 @@ class VolumeReplicationAPITestCase(test.TestCase):
                                                replication_status = status,
                                                **self.volume_params)
             (req, res) = self._get_resp('promote', volume['id'])
-            msg = ("request: %s\nresult: %s" % (req, res))
+            msg = ("request: %r\nresult: %r" % (req, res))
             self.assertEqual(400, res.status_int, msg)
 
         for status in ['active', 'active-stopped']:
@@ -152,7 +155,7 @@ class VolumeReplicationAPITestCase(test.TestCase):
                                                replication_status = status,
                                                **self.volume_params)
             (req, res) = self._get_resp('promote', volume['id'])
-            msg = ("request: %s\nresult: %s" % (req, res))
+            msg = ("request: %r\nresult: %r" % (req, res))
             self.assertEqual(202, res.status_int, msg)
 
     @mock.patch('cinder.volume.rpcapi.VolumeAPI.promote_replica')
@@ -164,7 +167,7 @@ class VolumeReplicationAPITestCase(test.TestCase):
                                                replication_status = status,
                                                **self.volume_params)
             (req, res) = self._get_resp('promote', volume['id'], xml=True)
-            msg = ("request: %s\nresult: %s" % (req, res))
+            msg = ("request: %r\nresult: %r" % (req, res))
             self.assertEqual(400, res.status_int, msg)
 
         for status in ['active', 'active-stopped']:
@@ -173,17 +176,17 @@ class VolumeReplicationAPITestCase(test.TestCase):
                                                replication_status = status,
                                                **self.volume_params)
             (req, res) = self._get_resp('promote', volume['id'], xml=True)
-            msg = ("request: %s\nresult: %s" % (req, res))
+            msg = ("request: %r\nresult: %r" % (req, res))
             self.assertEqual(202, res.status_int, msg)
 
     def test_reenable_bad_id(self):
         (req, res) = self._get_resp('reenable', 'fake')
-        msg = ("request: %s\nresult: %s" % (req, res))
+        msg = ("request: %r\nresult: %r" % (req, res))
         self.assertEqual(404, res.status_int, msg)
 
     def test_reenable_bad_id_xml(self):
         (req, res) = self._get_resp('reenable', 'fake', xml=True)
-        msg = ("request: %s\nresult: %s" % (req, res))
+        msg = ("request: %r\nresult: %r" % (req, res))
         self.assertEqual(404, res.status_int, msg)
 
     def test_reenable_volume_not_replicated(self):
@@ -191,7 +194,7 @@ class VolumeReplicationAPITestCase(test.TestCase):
             self.ctxt,
             **self.volume_params)
         (req, res) = self._get_resp('reenable', volume['id'])
-        msg = ("request: %s\nresult: %s" % (req, res))
+        msg = ("request: %r\nresult: %r" % (req, res))
         self.assertEqual(400, res.status_int, msg)
 
     def test_reenable_volume_not_replicated_xml(self):
@@ -199,7 +202,7 @@ class VolumeReplicationAPITestCase(test.TestCase):
             self.ctxt,
             **self.volume_params)
         (req, res) = self._get_resp('reenable', volume['id'], xml=True)
-        msg = ("request: %s\nresult: %s" % (req, res))
+        msg = ("request: %r\nresult: %r" % (req, res))
         self.assertEqual(400, res.status_int, msg)
 
     @mock.patch('cinder.volume.rpcapi.VolumeAPI.reenable_replication')
@@ -211,7 +214,7 @@ class VolumeReplicationAPITestCase(test.TestCase):
                                                replication_status = status,
                                                **self.volume_params)
             (req, res) = self._get_resp('reenable', volume['id'])
-            msg = ("request: %s\nresult: %s" % (req, res))
+            msg = ("request: %r\nresult: %r" % (req, res))
             self.assertEqual(400, res.status_int, msg)
 
         for status in ['inactive', 'active-stopped', 'error']:
@@ -220,7 +223,7 @@ class VolumeReplicationAPITestCase(test.TestCase):
                                                replication_status = status,
                                                **self.volume_params)
             (req, res) = self._get_resp('reenable', volume['id'])
-            msg = ("request: %s\nresult: %s" % (req, res))
+            msg = ("request: %r\nresult: %r" % (req, res))
             self.assertEqual(202, res.status_int, msg)
 
     @mock.patch('cinder.volume.rpcapi.VolumeAPI.reenable_replication')
@@ -232,7 +235,7 @@ class VolumeReplicationAPITestCase(test.TestCase):
                                                replication_status = status,
                                                **self.volume_params)
             (req, res) = self._get_resp('reenable', volume['id'], xml=True)
-            msg = ("request: %s\nresult: %s" % (req, res))
+            msg = ("request: %r\nresult: %r" % (req, res))
             self.assertEqual(400, res.status_int, msg)
 
         for status in ['inactive', 'active-stopped', 'error']:
@@ -241,5 +244,5 @@ class VolumeReplicationAPITestCase(test.TestCase):
                                                replication_status = status,
                                                **self.volume_params)
             (req, res) = self._get_resp('reenable', volume['id'], xml=True)
-            msg = ("request: %s\nresult: %s" % (req, res))
+            msg = ("request: %r\nresult: %r" % (req, res))
             self.assertEqual(202, res.status_int, msg)
diff --git a/cinder/tests/unit/api/contrib/test_volume_transfer.py b/cinder/tests/unit/api/contrib/test_volume_transfer.py
index 3407c28f8..685905e93 100644
--- a/cinder/tests/unit/api/contrib/test_volume_transfer.py
+++ b/cinder/tests/unit/api/contrib/test_volume_transfer.py
@@ -17,10 +17,11 @@
 Tests for volume transfer code.
 """
 
+import mock
 from xml.dom import minidom
 
-import mock
 from oslo_serialization import jsonutils
+import six
 import webob
 
 from cinder.api.contrib import volume_transfer
@@ -285,9 +286,12 @@ class VolumeTransferAPITestCase(test.TestCase):
         volume_size = 2
         volume_id = self._create_volume(status='available', size=volume_size)
 
+        body = '<transfer name="transfer-001" volume_id="%s"/>' % volume_id
+        if isinstance(body, six.text_type):
+            body = body.encode('utf-8')
+
         req = webob.Request.blank('/v2/fake/os-volume-transfer')
-        req.body = ('<transfer name="transfer-001" '
-                    'volume_id="%s"/>' % volume_id)
+        req.body = body
         req.method = 'POST'
         req.headers['Content-Type'] = 'application/xml'
         req.headers['Accept'] = 'application/xml'
@@ -434,9 +438,13 @@ class VolumeTransferAPITestCase(test.TestCase):
         transfer = self._create_transfer(volume_id)
         svc = self.start_service('volume', host='fake_host')
 
+        body = '<accept auth_key="%s"/>' % transfer['auth_key']
+        if isinstance(body, six.text_type):
+            body = body.encode('utf-8')
+
         req = webob.Request.blank('/v2/fake/os-volume-transfer/%s/accept' %
                                   transfer['id'])
-        req.body = '<accept auth_key="%s"/>' % transfer['auth_key']
+        req.body = body
         req.method = 'POST'
         req.headers['Content-Type'] = 'application/xml'
         req.headers['Accept'] = 'application/xml'
diff --git a/cinder/tests/unit/api/contrib/test_volume_type_access.py b/cinder/tests/unit/api/contrib/test_volume_type_access.py
index f39bb802a..4fe3f214b 100644
--- a/cinder/tests/unit/api/contrib/test_volume_type_access.py
+++ b/cinder/tests/unit/api/contrib/test_volume_type_access.py
@@ -72,7 +72,7 @@ def fake_volume_type_get_all(context, inactive=False, filters=None,
                              sort_dirs=None, offset=None, list_result=False):
     if filters is None or filters['is_public'] is None:
         if list_result:
-            return VOLUME_TYPES.values()
+            return list(VOLUME_TYPES.values())
         return VOLUME_TYPES
     res = {}
     for k, v in VOLUME_TYPES.items():
@@ -82,7 +82,7 @@ def fake_volume_type_get_all(context, inactive=False, filters=None,
         if v['is_public'] == filters['is_public']:
             res.update({k: v})
     if list_result:
-        return res.values()
+        return list(res.values())
     return res
 
 
diff --git a/cinder/tests/unit/api/contrib/test_volume_type_encryption.py b/cinder/tests/unit/api/contrib/test_volume_type_encryption.py
index 369589fe5..9cf51cf19 100644
--- a/cinder/tests/unit/api/contrib/test_volume_type_encryption.py
+++ b/cinder/tests/unit/api/contrib/test_volume_type_encryption.py
@@ -166,7 +166,7 @@ class VolumeTypeEncryptionTest(test.TestCase):
         self.assertEqual(200, res.status_code)
         # Confirm that volume type has no encryption information
         # before create.
-        self.assertEqual('{}', res.body)
+        self.assertEqual(b'{}', res.body)
 
         # Create encryption specs for the volume type
         # with the defined body.
@@ -214,8 +214,8 @@ class VolumeTypeEncryptionTest(test.TestCase):
         req = webob.Request.blank('/v2/fake/types/%s/encryption'
                                   % volume_type['id'])
         req.method = 'POST'
-        req.body = ('<encryption provider="test_provider" '
-                    'cipher="cipher" control_location="front-end" />')
+        req.body = (b'<encryption provider="test_provider" '
+                    b'cipher="cipher" control_location="front-end" />')
         req.headers['Content-Type'] = 'application/xml'
         req.headers['Accept'] = 'application/xml'
         res = req.get_response(fakes.wsgi_app(fake_auth_context=ctxt))
diff --git a/tests-py3.txt b/tests-py3.txt
index b275f5734..29e8324cd 100644
--- a/tests-py3.txt
+++ b/tests-py3.txt
@@ -1,27 +1,4 @@
-cinder.tests.unit.api.contrib.test_admin_actions
-cinder.tests.unit.api.contrib.test_availability_zones
-cinder.tests.unit.api.contrib.test_capabilities
-cinder.tests.unit.api.contrib.test_cgsnapshots
-cinder.tests.unit.api.contrib.test_extended_snapshot_attributes
-cinder.tests.unit.api.contrib.test_hosts
-cinder.tests.unit.api.contrib.test_qos_specs_manage
-cinder.tests.unit.api.contrib.test_quotas
-cinder.tests.unit.api.contrib.test_quotas_classes
-cinder.tests.unit.api.contrib.test_scheduler_hints
-cinder.tests.unit.api.contrib.test_scheduler_stats
-cinder.tests.unit.api.contrib.test_services
-cinder.tests.unit.api.contrib.test_snapshot_actions
-cinder.tests.unit.api.contrib.test_snapshot_manage
-cinder.tests.unit.api.contrib.test_snapshot_unmanage
-cinder.tests.unit.api.contrib.test_types_extra_specs
-cinder.tests.unit.api.contrib.test_types_manage
-cinder.tests.unit.api.contrib.test_used_limits
-cinder.tests.unit.api.contrib.test_volume_encryption_metadata
-cinder.tests.unit.api.contrib.test_volume_host_attribute
-cinder.tests.unit.api.contrib.test_volume_manage
-cinder.tests.unit.api.contrib.test_volume_unmanage
-cinder.tests.unit.api.contrib.test_volume_migration_status_attribute
-cinder.tests.unit.api.contrib.test_volume_tenant_attribute
+cinder.tests.unit.api.contrib
 cinder.tests.unit.api.openstack.test_wsgi
 cinder.tests.unit.api.test_common
 cinder.tests.unit.api.test_extensions