summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nova/objects/base.py26
-rw-r--r--nova/tests/objects/test_objects.py37
2 files changed, 61 insertions, 2 deletions
diff --git a/nova/objects/base.py b/nova/objects/base.py
index f5fc37e03..6f2b6c81f 100644
--- a/nova/objects/base.py
+++ b/nova/objects/base.py
@@ -425,13 +425,35 @@ class NovaObjectSerializer(nova.openstack.common.rpc.serializer.Serializer):
that needs to accept or return NovaObjects as arguments or result values
should pass this to its RpcProxy and RpcDispatcher objects.
"""
+ def _process_iterable(self, context, action_fn, values):
+ """Process an iterable, taking an action on each value.
+ :param:context: Request context
+ :param:action_fn: Action to take on each item in values
+ :param:values: Iterable container of things to take action on
+ :returns: A new container of the same type (except set) with
+ items from values having had action applied.
+ """
+ iterable = values.__class__
+ if iterable == set:
+ # NOTE(danms): A set can't have an unhashable value inside, such as
+ # a dict. Convert sets to tuples, which is fine, since we can't
+ # send them over RPC anyway.
+ iterable = tuple
+ return iterable([action_fn(context, value) for value in values])
+
def serialize_entity(self, context, entity):
- if (hasattr(entity, 'obj_to_primitive') and
- callable(entity.obj_to_primitive)):
+ if isinstance(entity, (tuple, list, set)):
+ entity = self._process_iterable(context, self.serialize_entity,
+ entity)
+ elif (hasattr(entity, 'obj_to_primitive') and
+ callable(entity.obj_to_primitive)):
entity = entity.obj_to_primitive()
return entity
def deserialize_entity(self, context, entity):
if isinstance(entity, dict) and 'nova_object.name' in entity:
entity = NovaObject.obj_from_primitive(entity, context=context)
+ elif isinstance(entity, (tuple, list, set)):
+ entity = self._process_iterable(context, self.deserialize_entity,
+ entity)
return entity
diff --git a/nova/tests/objects/test_objects.py b/nova/tests/objects/test_objects.py
index 332833cb0..00aaf1781 100644
--- a/nova/tests/objects/test_objects.py
+++ b/nova/tests/objects/test_objects.py
@@ -502,3 +502,40 @@ class TestObjectListBase(test.TestCase):
self.assertFalse(obj is obj2)
self.assertEqual([x.foo for x in obj],
[y.foo for y in obj2])
+
+
+class TestObjectSerializer(test.TestCase):
+ def test_serialize_entity_primitive(self):
+ ser = base.NovaObjectSerializer()
+ for thing in (1, 'foo', [1, 2], {'foo': 'bar'}):
+ self.assertEqual(thing, ser.serialize_entity(None, thing))
+
+ def test_deserialize_entity_primitive(self):
+ ser = base.NovaObjectSerializer()
+ for thing in (1, 'foo', [1, 2], {'foo': 'bar'}):
+ self.assertEqual(thing, ser.deserialize_entity(None, thing))
+
+ def test_object_serialization(self):
+ ser = base.NovaObjectSerializer()
+ ctxt = context.get_admin_context()
+ obj = MyObj()
+ primitive = ser.serialize_entity(ctxt, obj)
+ self.assertTrue('nova_object.name' in primitive)
+ obj2 = ser.deserialize_entity(ctxt, primitive)
+ self.assertTrue(isinstance(obj2, MyObj))
+ self.assertEqual(ctxt, obj2._context)
+
+ def test_object_serialization_iterables(self):
+ ser = base.NovaObjectSerializer()
+ ctxt = context.get_admin_context()
+ obj = MyObj()
+ for iterable in (list, tuple, set):
+ thing = iterable([obj])
+ primitive = ser.serialize_entity(ctxt, thing)
+ self.assertEqual(1, len(primitive))
+ for item in primitive:
+ self.assertFalse(isinstance(item, base.NovaObject))
+ thing2 = ser.deserialize_entity(ctxt, primitive)
+ self.assertEqual(1, len(thing2))
+ for item in thing2:
+ self.assertTrue(isinstance(item, MyObj))