Move compare_obj to the fixture module for external consumption
Nova has a copy of compare_obj and Cinder needs to start using the same thing, so move compare_obj to the fixture module so other projects that are already using oslo.versionedobjects fixtures can re-use this. The if check at the beginning of the function was changed over because one of the unit tests uncovered a case with undesirable failing. Co-Authored-By: Ryan Rossiter <rlrossit@us.ibm.com> Change-Id: I0bcfa7d4f501bd69b6343e4d719e98eb32a5a5cd
This commit is contained in:
parent
686585fd64
commit
bca1f6059b
oslo_versionedobjects
@ -21,6 +21,7 @@
|
||||
"""
|
||||
|
||||
from collections import OrderedDict
|
||||
import datetime
|
||||
import hashlib
|
||||
import inspect
|
||||
import logging
|
||||
@ -36,6 +37,55 @@ from oslo_versionedobjects import fields
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def compare_obj(test, obj, db_obj, subs=None, allow_missing=None,
|
||||
comparators=None):
|
||||
"""Compare a VersionedObject and a dict-like database object.
|
||||
|
||||
This automatically converts TZ-aware datetimes and iterates over
|
||||
the fields of the object.
|
||||
|
||||
:param test: The TestCase doing the comparison
|
||||
:param obj: The VersionedObject to examine
|
||||
:param db_obj: The dict-like database object to use as reference
|
||||
:param subs: A dict of objkey=dbkey field substitutions
|
||||
:param allow_missing: A list of fields that may not be in db_obj
|
||||
:param comparators: Map of comparator functions to use for certain fields
|
||||
"""
|
||||
|
||||
if subs is None:
|
||||
subs = {}
|
||||
if allow_missing is None:
|
||||
allow_missing = []
|
||||
if comparators is None:
|
||||
comparators = {}
|
||||
|
||||
for key in obj.fields:
|
||||
# We'll raise a NotImplementedError if we try to compare against
|
||||
# against something that isn't set in the object, but is not
|
||||
# in the allow_missing. This will replace that exception
|
||||
# with an AssertionError (because that is a better way of saying
|
||||
# "these objects arent the same").
|
||||
if not obj.obj_attr_is_set(key):
|
||||
if key in allow_missing:
|
||||
continue
|
||||
else:
|
||||
raise AssertionError(("%s is not set on the object, so "
|
||||
"the objects are not equal") % key)
|
||||
if key in allow_missing and not obj.obj_attr_is_set(key):
|
||||
continue
|
||||
obj_val = getattr(obj, key)
|
||||
db_key = subs.get(key, key)
|
||||
db_val = db_obj[db_key]
|
||||
if isinstance(obj_val, datetime.datetime):
|
||||
obj_val = obj_val.replace(tzinfo=None)
|
||||
|
||||
if key in comparators:
|
||||
comparator = comparators[key]
|
||||
comparator(db_val, obj_val)
|
||||
else:
|
||||
test.assertEqual(db_val, obj_val)
|
||||
|
||||
|
||||
class FakeIndirectionAPI(base.VersionedObjectIndirectionAPI):
|
||||
def __init__(self, serializer=None):
|
||||
super(FakeIndirectionAPI, self).__init__()
|
||||
|
@ -14,8 +14,10 @@
|
||||
|
||||
import collections
|
||||
import copy
|
||||
import datetime
|
||||
import hashlib
|
||||
|
||||
import iso8601
|
||||
import mock
|
||||
import six
|
||||
|
||||
@ -53,6 +55,91 @@ class MyExtraObject(base.VersionedObject):
|
||||
pass
|
||||
|
||||
|
||||
class TestObjectComparators(test.TestCase):
|
||||
@base.VersionedObjectRegistry.register_if(False)
|
||||
class MyComparedObject(base.VersionedObject):
|
||||
fields = {'foo': fields.IntegerField(),
|
||||
'bar': fields.IntegerField()}
|
||||
|
||||
@base.VersionedObjectRegistry.register_if(False)
|
||||
class MyComparedObjectWithTZ(base.VersionedObject):
|
||||
fields = {'tzfield': fields.DateTimeField()}
|
||||
|
||||
def test_compare_obj(self):
|
||||
mock_test = mock.Mock()
|
||||
mock_test.assertEqual = mock.Mock()
|
||||
my_obj = self.MyComparedObject(foo=1, bar=2)
|
||||
my_db_obj = {'foo': 1, 'bar': 2}
|
||||
|
||||
fixture.compare_obj(mock_test, my_obj, my_db_obj)
|
||||
|
||||
expected_calls = [(1, 1), (2, 2)]
|
||||
actual_calls = [c[0] for c in mock_test.assertEqual.call_args_list]
|
||||
for call in expected_calls:
|
||||
self.assertIn(call, actual_calls)
|
||||
|
||||
def test_compare_obj_with_unset(self):
|
||||
mock_test = mock.Mock()
|
||||
my_obj = self.MyComparedObject()
|
||||
my_db_obj = {}
|
||||
|
||||
self.assertRaises(AssertionError, fixture.compare_obj,
|
||||
mock_test, my_obj, my_db_obj)
|
||||
|
||||
def test_compare_obj_with_subs(self):
|
||||
mock_test = mock.Mock()
|
||||
mock_test.assertEqual = mock.Mock()
|
||||
my_obj = self.MyComparedObject(foo=1, bar=2)
|
||||
my_db_obj = {'doo': 1, 'bar': 2}
|
||||
subs = {'foo': 'doo'}
|
||||
|
||||
fixture.compare_obj(mock_test, my_obj, my_db_obj, subs=subs)
|
||||
|
||||
expected_calls = [(1, 1), (2, 2)]
|
||||
actual_calls = [c[0] for c in mock_test.assertEqual.call_args_list]
|
||||
for call in expected_calls:
|
||||
self.assertIn(call, actual_calls)
|
||||
|
||||
def test_compare_obj_with_allow_missing(self):
|
||||
mock_test = mock.Mock()
|
||||
mock_test.assertEqual = mock.Mock()
|
||||
my_obj = self.MyComparedObject(foo=1)
|
||||
my_db_obj = {'foo': 1, 'bar': 2}
|
||||
ignores = ['bar']
|
||||
|
||||
fixture.compare_obj(mock_test, my_obj, my_db_obj,
|
||||
allow_missing=ignores)
|
||||
|
||||
mock_test.assertEqual.assert_called_once_with(1, 1)
|
||||
|
||||
def test_compare_obj_with_comparators(self):
|
||||
mock_test = mock.Mock()
|
||||
mock_test.assertEqual = mock.Mock()
|
||||
comparator = mock.Mock()
|
||||
comp_dict = {'foo': comparator}
|
||||
my_obj = self.MyComparedObject(foo=1, bar=2)
|
||||
my_db_obj = {'foo': 1, 'bar': 2}
|
||||
|
||||
fixture.compare_obj(mock_test, my_obj, my_db_obj,
|
||||
comparators=comp_dict)
|
||||
|
||||
comparator.assert_called_once_with(1, 1)
|
||||
mock_test.assertEqual.assert_called_once_with(2, 2)
|
||||
|
||||
def test_compare_obj_with_dt(self):
|
||||
mock_test = mock.Mock()
|
||||
mock_test.assertEqual = mock.Mock()
|
||||
dt = datetime.datetime(1955, 11, 5, tzinfo=iso8601.iso8601.Utc())
|
||||
replaced_dt = dt.replace(tzinfo=None)
|
||||
my_obj = self.MyComparedObjectWithTZ(tzfield=dt)
|
||||
my_db_obj = {'tzfield': replaced_dt}
|
||||
|
||||
fixture.compare_obj(mock_test, my_obj, my_db_obj)
|
||||
|
||||
mock_test.assertEqual.assert_called_once_with(replaced_dt,
|
||||
replaced_dt)
|
||||
|
||||
|
||||
class TestObjectVersionChecker(test.TestCase):
|
||||
def setUp(self):
|
||||
super(TestObjectVersionChecker, self).setUp()
|
||||
|
@ -459,44 +459,6 @@ class TestDoSubobjectBackport(test.TestCase):
|
||||
m.assert_called_once_with(mock.ANY, '1.0', mock.sentinel.manifest)
|
||||
|
||||
|
||||
def compare_obj(test, obj, db_obj, subs=None, allow_missing=None,
|
||||
comparators=None):
|
||||
"""Compare a VersionedObject and a dict-like database object.
|
||||
|
||||
This automatically converts TZ-aware datetimes and iterates over
|
||||
the fields of the object.
|
||||
|
||||
:param:test: The TestCase doing the comparison
|
||||
:param:obj: The VersionedObject to examine
|
||||
:param:db_obj: The dict-like database object to use as reference
|
||||
:param:subs: A dict of objkey=dbkey field substitutions
|
||||
:param:allow_missing: A list of fields that may not be in db_obj
|
||||
:param:comparators: Map of comparator functions to use for certain fields
|
||||
"""
|
||||
|
||||
if subs is None:
|
||||
subs = {}
|
||||
if allow_missing is None:
|
||||
allow_missing = []
|
||||
if comparators is None:
|
||||
comparators = {}
|
||||
|
||||
for key in obj.fields:
|
||||
if key in allow_missing and not obj.obj_attr_is_set(key):
|
||||
continue
|
||||
obj_val = getattr(obj, key)
|
||||
db_key = subs.get(key, key)
|
||||
db_val = db_obj[db_key]
|
||||
if isinstance(obj_val, datetime.datetime):
|
||||
obj_val = obj_val.replace(tzinfo=None)
|
||||
|
||||
if key in comparators:
|
||||
comparator = comparators[key]
|
||||
comparator(db_val, obj_val)
|
||||
else:
|
||||
test.assertEqual(db_val, obj_val)
|
||||
|
||||
|
||||
class _BaseTestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(_BaseTestCase, self).setUp()
|
||||
@ -504,11 +466,6 @@ class _BaseTestCase(test.TestCase):
|
||||
self.project_id = 'fake-project'
|
||||
self.context = context.RequestContext(self.user_id, self.project_id)
|
||||
|
||||
def compare_obj(self, obj, db_obj, subs=None, allow_missing=None,
|
||||
comparators=None):
|
||||
compare_obj(self, obj, db_obj, subs=subs, allow_missing=allow_missing,
|
||||
comparators=comparators)
|
||||
|
||||
def json_comparator(self, expected, obj_val):
|
||||
# json-ify an object field for comparison with its db str
|
||||
# equivalent
|
||||
|
Loading…
x
Reference in New Issue
Block a user