diff --git a/nova/test.py b/nova/test.py index ea8c13505..2e3012ffc 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 39467cccc..2607eae11 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))