External object IDs couldn't be used in template() contracts
Due to the bug in object serializer, when template() contract serialized the template to a dictionary, instead of object IDs for the objects outside of serialized tree it put the object body. Thus when new objects were created from the template, they all had copies of that object with different IDs rather than copies of the ID string (i.e. references to the same object). Also template() contract tried to serialize the template on each of the 2 object model load passes even though the result from the first pass is never used. However, during first pass the model could contain forward-references to objects that are not loaded yet so attempt to serialize such model could fail. Change-Id: I9d81f10c160c44e6405b54f5470904064c1d4852 Closes-Bug: #1689769
This commit is contained in:
parent
b85d5c1592
commit
fb593ab439
|
@ -176,6 +176,8 @@ class Template(contracts.ContractMethod):
|
|||
if self.value is None:
|
||||
return None
|
||||
object_store = helpers.get_object_store()
|
||||
if object_store.initializing:
|
||||
return {}
|
||||
passkey = getattr(self.value, '__passkey__', None)
|
||||
with helpers.thread_local_attribute(
|
||||
constants.TL_CONTRACT_PASSKEY, passkey):
|
||||
|
|
|
@ -27,10 +27,11 @@ class ObjRef(object):
|
|||
|
||||
|
||||
def serialize(obj, executor,
|
||||
serialization_type=dsl_types.DumpTypes.Serializable):
|
||||
serialization_type=dsl_types.DumpTypes.Serializable,
|
||||
allow_refs=True):
|
||||
with helpers.with_object_store(executor.object_store):
|
||||
return serialize_model(
|
||||
obj, executor, True,
|
||||
obj, executor, allow_refs,
|
||||
make_copy=False,
|
||||
serialize_attributes=False,
|
||||
serialize_actions=False,
|
||||
|
@ -45,9 +46,12 @@ def _serialize_object(root_object, designer_attributes, allow_refs,
|
|||
serialized_objects = set()
|
||||
|
||||
obj = root_object
|
||||
if isinstance(obj, dsl.MuranoObjectInterface):
|
||||
obj = obj.object
|
||||
parent = obj.owner if isinstance(obj, dsl_types.MuranoObject) else None
|
||||
while True:
|
||||
obj, need_another_pass = _pass12_serialize(
|
||||
obj, None, serialized_objects, designer_attributes, executor,
|
||||
obj, parent, serialized_objects, designer_attributes, executor,
|
||||
serialize_actions, serialization_type, allow_refs,
|
||||
with_destruction_dependencies)
|
||||
if not need_another_pass:
|
||||
|
@ -130,8 +134,11 @@ def _pass12_serialize(value, parent, serialized_objects,
|
|||
if value.owner is not parent or value.object_id in serialized_objects:
|
||||
return ObjRef(value), True
|
||||
elif isinstance(value, ObjRef):
|
||||
if (value.ref_obj.object_id not in serialized_objects and
|
||||
is_nested_in(value.ref_obj.owner, parent)):
|
||||
can_move = value.ref_obj.object_id not in serialized_objects
|
||||
if can_move and allow_refs and value.ref_obj.owner is not None:
|
||||
can_move = (is_nested_in(parent, value.ref_obj.owner) and
|
||||
value.ref_obj.owner.object_id in serialized_objects)
|
||||
if can_move:
|
||||
value = value.ref_obj
|
||||
else:
|
||||
return value, False
|
||||
|
|
|
@ -271,4 +271,18 @@ Name: TemplateTestChild
|
|||
|
||||
Properties:
|
||||
bar:
|
||||
Contract: $.int().notNull()
|
||||
Contract: $.int().notNull()
|
||||
|
||||
---
|
||||
|
||||
Name: TemplatePropertyClass
|
||||
Properties:
|
||||
owned:
|
||||
Contract: $.class(Node)
|
||||
template:
|
||||
Contract: $.template(Node)
|
||||
|
||||
Methods:
|
||||
testTemplateWithExternallyOwnedObject:
|
||||
Body:
|
||||
- Return: new($.template).nodes.select(id($))
|
||||
|
|
|
@ -34,7 +34,7 @@ class TestConstruction(test_case.DslTestCase):
|
|||
|
||||
def test_new_with_ownership(self):
|
||||
obj = serializer.serialize(self._runner.testNewWithOwnership(),
|
||||
self._runner.executor)
|
||||
self._runner.executor, allow_refs=False)
|
||||
self.assertEqual('STRING', obj.get('property1'))
|
||||
self.assertIsNotNone('string', obj.get('xxx'))
|
||||
self.assertEqual('STR', obj['xxx'].get('property1'))
|
||||
|
|
|
@ -327,6 +327,15 @@ class TestContracts(test_case.DslTestCase):
|
|||
self.assertEqual('PROPERTY', self._runner.testDefaultExpression())
|
||||
self.assertEqual('value', self._runner.testDefaultExpression('value'))
|
||||
|
||||
def test_template_with_externally_owned_object(self):
|
||||
node = om.Object('Node', 'OBJ_ID')
|
||||
node_template = om.Object('Node', nodes=['OBJ_ID'])
|
||||
model = om.Object(
|
||||
'TemplatePropertyClass', owned=node, template=node_template)
|
||||
runner = self.new_runner(model)
|
||||
self.assertEqual(
|
||||
['OBJ_ID'], runner.testTemplateWithExternallyOwnedObject())
|
||||
|
||||
|
||||
class TestContractsTransform(test_case.DslTestCase):
|
||||
def setUp(self):
|
||||
|
|
Loading…
Reference in New Issue