From: Victor Stinner Date: Tue, 26 Jan 2016 14:48:34 +0000 (+0100) Subject: Port objects unit tests to Python 3 X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=f3dc1a0c54e78a4948acbdd3b94b2b2b2eb9ae78;p=openstack-build%2Fcinder-build.git Port objects unit tests to Python 3 * BaseObjectsTestCase._compare(): replace hasattr() with getattr() and a white list of expected exceptions. On Python 2, hasattr() ignores *all* exceptions and so may hide real bugs. * Mocks: except a call to obj.__bool__() rather than obj.__nonzero__() on Python 3. bool(obj) now calls obj.__bool__() on Python 3. * Replace dict.keys() with list(dict.keys()) to get a list on Python 3. On Python 3, dict.keys() now returns a view. * JSON/base64: * Replace jsonutils.dumps() with jsonutils.dump_as_bytes() to get JSON as bytes * Replace base64.encodestring() with oslo_serialization.base64.encode_as_text() to get base64 as bytes * Replace base64.decodestring() with oslo_serialization.base64.decode_as_text() to accept Unicode and return Unicode * tests-py3.txt: add cinder.tests.unit.objects.test_* (11 files) Partial-Implements: blueprint cinder-python3 Change-Id: I9ce7753eb947bf9a5c91e643f5c65156c8e3f7cc --- diff --git a/cinder/objects/backup.py b/cinder/objects/backup.py index d3df6f05e..6193d118a 100644 --- a/cinder/objects/backup.py +++ b/cinder/objects/backup.py @@ -12,15 +12,12 @@ # License for the specific language governing permissions and limitations # under the License. -import base64 -import binascii - from oslo_config import cfg from oslo_log import log as logging +from oslo_serialization import base64 from oslo_serialization import jsonutils from oslo_utils import versionutils from oslo_versionedobjects import fields -import six from cinder import db from cinder import exception @@ -136,8 +133,8 @@ class Backup(base.CinderPersistentObject, base.CinderObject, :raises: InvalidInput """ try: - return jsonutils.loads(base64.decodestring(backup_url)) - except binascii.Error: + return jsonutils.loads(base64.decode_as_text(backup_url)) + except TypeError: msg = _("Can't decode backup record.") except ValueError: msg = _("Can't parse backup record.") @@ -153,10 +150,8 @@ class Backup(base.CinderPersistentObject, base.CinderObject, # We must update kwargs instead of record to ensure we don't overwrite # "real" data from the backup kwargs.update(record) - retval = jsonutils.dumps(kwargs) - if six.PY3: - retval = retval.encode('utf-8') - return base64.encodestring(retval) + retval = jsonutils.dump_as_bytes(kwargs) + return base64.encode_as_text(retval) @base.CinderObjectRegistry.register diff --git a/cinder/tests/unit/api/contrib/test_backups.py b/cinder/tests/unit/api/contrib/test_backups.py index 36290ecb7..d12017e76 100644 --- a/cinder/tests/unit/api/contrib/test_backups.py +++ b/cinder/tests/unit/api/contrib/test_backups.py @@ -23,6 +23,7 @@ from xml.dom import minidom import ddt import mock from oslo_utils import timeutils +import six import webob # needed for stubs to work @@ -1792,6 +1793,8 @@ class BackupsAPITestCase(test.TestCase): _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_url': backup_url, diff --git a/cinder/tests/unit/objects/__init__.py b/cinder/tests/unit/objects/__init__.py index c697b391d..7a5066ca9 100644 --- a/cinder/tests/unit/objects/__init__.py +++ b/cinder/tests/unit/objects/__init__.py @@ -15,6 +15,7 @@ from oslo_utils import timeutils from cinder import context +from cinder import exception from cinder.objects import base as obj_base from cinder import test @@ -36,7 +37,12 @@ class BaseObjectsTestCase(test.TestCase): @staticmethod def _compare(test, db, obj): for field, value in db.items(): - if not hasattr(obj, field): + try: + getattr(obj, field) + except (AttributeError, exception.CinderException, + NotImplementedError): + # NotImplementedError: ignore "Cannot load 'projects' in the + # base class" error continue if field in ('modified_at', 'created_at', diff --git a/cinder/tests/unit/objects/test_backup.py b/cinder/tests/unit/objects/test_backup.py index bb3901aa0..4b9a48bc7 100644 --- a/cinder/tests/unit/objects/test_backup.py +++ b/cinder/tests/unit/objects/test_backup.py @@ -13,6 +13,7 @@ # under the License. import mock +import six from cinder.db.sqlalchemy import models from cinder import exception @@ -164,8 +165,12 @@ class TestBackup(test_objects.BaseObjectsTestCase): # for that field backup.refresh() self._compare(self, db_backup2, backup) + if six.PY3: + call_bool = mock.call.__bool__() + else: + call_bool = mock.call.__nonzero__() backup_get.assert_has_calls([mock.call(self.context, '1'), - mock.call.__nonzero__(), + call_bool, mock.call(self.context, '1')]) diff --git a/cinder/tests/unit/objects/test_base.py b/cinder/tests/unit/objects/test_base.py index 7f53518ef..70e2da302 100644 --- a/cinder/tests/unit/objects/test_base.py +++ b/cinder/tests/unit/objects/test_base.py @@ -173,7 +173,7 @@ class TestCinderObjectConditionalUpdate(test.TestCase): self.assertEqual(status, volume.status) self.assertEqual(size, volume.size) dirty = volume.cinder_obj_get_changes() - self.assertEqual(list(dirty_keys), dirty.keys()) + self.assertEqual(list(dirty_keys), list(dirty.keys())) for key, value in kwargs.items(): self.assertEqual(value, getattr(volume, key)) diff --git a/cinder/tests/unit/objects/test_cgsnapshot.py b/cinder/tests/unit/objects/test_cgsnapshot.py index 5d8cc97f5..086b2743e 100644 --- a/cinder/tests/unit/objects/test_cgsnapshot.py +++ b/cinder/tests/unit/objects/test_cgsnapshot.py @@ -13,6 +13,7 @@ # under the License. import mock +import six from cinder import exception from cinder import objects @@ -123,8 +124,12 @@ class TestCGSnapshot(test_objects.BaseObjectsTestCase): # value for that field cgsnapshot.refresh() self._compare(self, db_cgsnapshot2, cgsnapshot) + if six.PY3: + call_bool = mock.call.__bool__() + else: + call_bool = mock.call.__nonzero__() cgsnapshot_get.assert_has_calls([mock.call(self.context, '1'), - mock.call.__nonzero__(), + call_bool, mock.call(self.context, '1')]) diff --git a/cinder/tests/unit/objects/test_consistencygroup.py b/cinder/tests/unit/objects/test_consistencygroup.py index c5125c031..1ed731afe 100644 --- a/cinder/tests/unit/objects/test_consistencygroup.py +++ b/cinder/tests/unit/objects/test_consistencygroup.py @@ -13,6 +13,7 @@ # under the License. import mock +import six from cinder import exception from cinder import objects @@ -162,8 +163,12 @@ class TestConsistencyGroup(test_objects.BaseObjectsTestCase): # new value for that field cg.refresh() self._compare(self, db_cg2, cg) + if six.PY3: + call_bool = mock.call.__bool__() + else: + call_bool = mock.call.__nonzero__() consistencygroup_get.assert_has_calls([mock.call(self.context, '1'), - mock.call.__nonzero__(), + call_bool, mock.call(self.context, '1')]) diff --git a/cinder/tests/unit/objects/test_service.py b/cinder/tests/unit/objects/test_service.py index 923cffc21..e7b3eec32 100644 --- a/cinder/tests/unit/objects/test_service.py +++ b/cinder/tests/unit/objects/test_service.py @@ -13,6 +13,7 @@ # under the License. import mock +import six from cinder import objects from cinder.tests.unit import fake_service @@ -93,8 +94,12 @@ class TestService(test_objects.BaseObjectsTestCase): # new value for that field service.refresh() self._compare(self, db_service2, service) + if six.PY3: + call_bool = mock.call.__bool__() + else: + call_bool = mock.call.__nonzero__() service_get.assert_has_calls([mock.call(self.context, 123), - mock.call.__nonzero__(), + call_bool, mock.call(self.context, 123)]) @mock.patch('cinder.db.service_get_all_by_binary') diff --git a/cinder/tests/unit/objects/test_snapshot.py b/cinder/tests/unit/objects/test_snapshot.py index 021e1b83f..fa74b8174 100644 --- a/cinder/tests/unit/objects/test_snapshot.py +++ b/cinder/tests/unit/objects/test_snapshot.py @@ -14,6 +14,7 @@ import copy import mock +import six from oslo_log import log as logging @@ -183,8 +184,12 @@ class TestSnapshot(test_objects.BaseObjectsTestCase): # value for that field snapshot.refresh() self._compare(self, db_snapshot2, snapshot) + if six.PY3: + call_bool = mock.call.__bool__() + else: + call_bool = mock.call.__nonzero__() snapshot_get.assert_has_calls([mock.call(self.context, '1'), - mock.call.__nonzero__(), + call_bool, mock.call(self.context, '1')]) diff --git a/cinder/tests/unit/objects/test_volume.py b/cinder/tests/unit/objects/test_volume.py index d9f1dc2ec..e2af749f5 100644 --- a/cinder/tests/unit/objects/test_volume.py +++ b/cinder/tests/unit/objects/test_volume.py @@ -13,6 +13,7 @@ # under the License. import mock +import six from cinder import context from cinder import exception @@ -291,8 +292,12 @@ class TestVolume(test_objects.BaseObjectsTestCase): # for that field volume.refresh() self._compare(self, db_volume2, volume) + if six.PY3: + call_bool = mock.call.__bool__() + else: + call_bool = mock.call.__nonzero__() volume_get.assert_has_calls([mock.call(self.context, '1'), - mock.call.__nonzero__(), + call_bool, mock.call(self.context, '1')]) def test_metadata_aliases(self): diff --git a/cinder/tests/unit/objects/test_volume_attachment.py b/cinder/tests/unit/objects/test_volume_attachment.py index ed6325eef..8b7fb78b4 100644 --- a/cinder/tests/unit/objects/test_volume_attachment.py +++ b/cinder/tests/unit/objects/test_volume_attachment.py @@ -13,6 +13,7 @@ # under the License. import mock +import six from cinder import objects from cinder.tests.unit import fake_volume @@ -52,8 +53,12 @@ class TestVolumeAttachment(test_objects.BaseObjectsTestCase): # new value for that field attachment.refresh() self._compare(self, db_attachment2, attachment) + if six.PY3: + call_bool = mock.call.__bool__() + else: + call_bool = mock.call.__nonzero__() attachment_get.assert_has_calls([mock.call(self.context, '1'), - mock.call.__nonzero__(), + call_bool, mock.call(self.context, '1')]) diff --git a/cinder/tests/unit/objects/test_volume_type.py b/cinder/tests/unit/objects/test_volume_type.py index be2075579..e7484301d 100644 --- a/cinder/tests/unit/objects/test_volume_type.py +++ b/cinder/tests/unit/objects/test_volume_type.py @@ -13,6 +13,7 @@ # under the License. import mock +import six from cinder import objects from cinder.tests.unit import fake_volume @@ -86,8 +87,12 @@ class TestVolumeType(test_objects.BaseObjectsTestCase): # value for that field volume_type.refresh() self._compare(self, db_type2, volume_type) + if six.PY3: + call_bool = mock.call.__bool__() + else: + call_bool = mock.call.__nonzero__() volume_type_get.assert_has_calls([mock.call(self.context, '1'), - mock.call.__nonzero__(), + call_bool, mock.call(self.context, '1')]) diff --git a/tests-py3.txt b/tests-py3.txt index 2e21480c1..b275f5734 100644 --- a/tests-py3.txt +++ b/tests-py3.txt @@ -36,6 +36,17 @@ cinder.tests.unit.keymgr.test_key cinder.tests.unit.keymgr.test_key_mgr cinder.tests.unit.keymgr.test_mock_key_mgr cinder.tests.unit.keymgr.test_not_implemented_key_mgr +cinder.tests.unit.objects.test_backup +cinder.tests.unit.objects.test_base +cinder.tests.unit.objects.test_cgsnapshot +cinder.tests.unit.objects.test_consistencygroup +cinder.tests.unit.objects.test_fields +cinder.tests.unit.objects.test_objects +cinder.tests.unit.objects.test_service +cinder.tests.unit.objects.test_snapshot +cinder.tests.unit.objects.test_volume +cinder.tests.unit.objects.test_volume_attachment +cinder.tests.unit.objects.test_volume_type cinder.tests.unit.scheduler.test_allocated_capacity_weigher cinder.tests.unit.scheduler.test_capacity_weigher cinder.tests.unit.scheduler.test_chance_weigher