Merge "Move compare_obj to the fixture module for external consumption"

This commit is contained in:
Jenkins 2016-01-18 04:45:12 +00:00 committed by Gerrit Code Review
commit 43fbf9b110
3 changed files with 137 additions and 43 deletions

@ -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