diff --git a/nova/test.py b/nova/test.py index ea8c13505f10..2e3012ffcd51 100644 --- a/nova/test.py +++ b/nova/test.py @@ -226,6 +226,8 @@ class TestCase(testtools.TestCase): objects_base.NovaObjectRegistry._registry._obj_classes) self.addCleanup(self._restore_obj_registry) + self.useFixture(nova_fixtures.StableObjectJsonFixture()) + # NOTE(mnaser): All calls to utils.is_neutron() are cached in # nova.utils._IS_NEUTRON. We set it to None to avoid any # caching of that value. diff --git a/nova/tests/fixtures.py b/nova/tests/fixtures.py index 39467cccca32..2607eae11f13 100644 --- a/nova/tests/fixtures.py +++ b/nova/tests/fixtures.py @@ -446,3 +446,31 @@ class BannedDBSchemaOperations(fixtures.Fixture): self.useFixture(fixtures.MonkeyPatch( 'sqlalchemy.%s.alter' % thing, lambda *a, **k: self._explode(thing, 'alter'))) + + +class StableObjectJsonFixture(fixtures.Fixture): + """Fixture that makes sure we get stable JSON object representations. + + Since objects contain things like set(), which can't be converted to + JSON, we have some situations where the representation isn't fully + deterministic. This doesn't matter at all at runtime, but does to + unit tests that try to assert things at a low level. + + This fixture mocks the obj_to_primitive() call and makes sure to + sort the list of changed fields (which came from a set) before + returning it to the caller. + """ + def __init__(self): + self._original_otp = obj_base.NovaObject.obj_to_primitive + + def setUp(self): + super(StableObjectJsonFixture, self).setUp() + + def _doit(obj, *args, **kwargs): + result = self._original_otp(obj, *args, **kwargs) + if 'nova_object.changes' in result: + result['nova_object.changes'].sort() + return result + + self.useFixture(fixtures.MonkeyPatch( + 'nova.objects.base.NovaObject.obj_to_primitive', _doit)) diff --git a/nova/tests/unit/test_fixtures.py b/nova/tests/unit/test_fixtures.py index 16b87cea4795..f0764fada563 100644 --- a/nova/tests/unit/test_fixtures.py +++ b/nova/tests/unit/test_fixtures.py @@ -331,3 +331,17 @@ class TestBannedDBSchemaOperations(testtools.TestCase): table.drop) self.assertRaises(exception.DBNotAllowed, table.alter) + + +class TestStableObjectJsonFixture(testtools.TestCase): + def test_changes_sort(self): + class TestObject(obj_base.NovaObject): + def obj_what_changed(self): + return ['z', 'a'] + + obj = TestObject() + self.assertEqual(['z', 'a'], + obj.obj_to_primitive()['nova_object.changes']) + with fixtures.StableObjectJsonFixture(): + self.assertEqual(['a', 'z'], + obj.obj_to_primitive()['nova_object.changes'])