Add metadata to the result of action serialization
In addition to action name, now title, description and help text also appear in the serialized action, if corresponding metaclasses are attached to the method. If no title specified by metadata, it is equal to method name in serialization result. Tests are updated to check new functionality. All test cases for actions serialization are now gathered in one place. Change-Id: I00c46677ed6bef3c8fcf93f07a1abc004c7304d3 Partially-implements: blueprint static-actions
This commit is contained in:
@@ -225,7 +225,7 @@ class TaskExecutor(object):
|
||||
self.session.finish()
|
||||
|
||||
try:
|
||||
action_result = serializer.serialize(action_result)
|
||||
action_result = serializer.serialize(action_result, executor)
|
||||
except Exception as e:
|
||||
return self.exception_result(e, None, '<result>')
|
||||
|
||||
|
||||
@@ -25,17 +25,18 @@ class ObjRef(object):
|
||||
self.ref_obj = obj
|
||||
|
||||
|
||||
def serialize(obj):
|
||||
return serialize_model(obj, None, True)[0]['Objects']
|
||||
def serialize(obj, executor):
|
||||
return serialize_model(obj, executor, True)[0]['Objects']
|
||||
|
||||
|
||||
def _serialize_object(root_object, designer_attributes, allow_refs):
|
||||
def _serialize_object(root_object, designer_attributes, allow_refs,
|
||||
executor):
|
||||
serialized_objects = set()
|
||||
|
||||
obj = root_object
|
||||
while True:
|
||||
obj, need_another_pass = _pass12_serialize(
|
||||
obj, None, serialized_objects, designer_attributes)
|
||||
obj, None, serialized_objects, designer_attributes, executor)
|
||||
if not need_another_pass:
|
||||
break
|
||||
tree = [obj]
|
||||
@@ -44,10 +45,7 @@ def _serialize_object(root_object, designer_attributes, allow_refs):
|
||||
|
||||
|
||||
def serialize_model(root_object, executor, allow_refs=False):
|
||||
if executor is not None:
|
||||
designer_attributes = executor.object_store.designer_attributes
|
||||
else:
|
||||
designer_attributes = None
|
||||
designer_attributes = executor.object_store.designer_attributes
|
||||
|
||||
if root_object is None:
|
||||
tree = None
|
||||
@@ -56,12 +54,10 @@ def serialize_model(root_object, executor, allow_refs=False):
|
||||
serialized_objects = set()
|
||||
else:
|
||||
tree, serialized_objects = _serialize_object(
|
||||
root_object, designer_attributes, allow_refs)
|
||||
tree_copy, _ = _serialize_object(root_object, None, allow_refs)
|
||||
if executor is not None:
|
||||
attributes = executor.attribute_store.serialize(serialized_objects)
|
||||
else:
|
||||
attributes = []
|
||||
root_object, designer_attributes, allow_refs, executor)
|
||||
tree_copy, _ = _serialize_object(root_object, None, allow_refs,
|
||||
executor)
|
||||
attributes = executor.attribute_store.serialize(serialized_objects)
|
||||
|
||||
return {
|
||||
'Objects': tree,
|
||||
@@ -70,19 +66,33 @@ def serialize_model(root_object, executor, allow_refs=False):
|
||||
}, serialized_objects
|
||||
|
||||
|
||||
def _serialize_available_action(obj, current_actions):
|
||||
def _serialize_available_action(obj, current_actions, executor):
|
||||
result = {}
|
||||
actions = obj.type.find_methods(lambda m: m.is_action)
|
||||
for action in actions:
|
||||
action_id = '{0}_{1}'.format(obj.object_id, action.name)
|
||||
entry = current_actions.get(action_id, {'enabled': True})
|
||||
entry['name'] = action.name
|
||||
context = executor.create_type_context(action.declaring_type)
|
||||
meta = action.get_meta(context)
|
||||
meta_dict = {item.type.name: item for item in meta}
|
||||
title = meta_dict.get('io.murano.metadata.Title')
|
||||
if title:
|
||||
entry['title'] = title.get_property('text')
|
||||
else:
|
||||
entry['title'] = action.name
|
||||
description = meta_dict.get('io.murano.metadata.Description')
|
||||
if description:
|
||||
entry['description'] = description.get_property('text')
|
||||
help_text = meta_dict.get('io.murano.metadata.HelpText')
|
||||
if help_text:
|
||||
entry['helpText'] = help_text.get_property('text')
|
||||
result[action_id] = entry
|
||||
return result
|
||||
|
||||
|
||||
def _pass12_serialize(value, parent, serialized_objects,
|
||||
designer_attributes_getter):
|
||||
designer_attributes_getter, executor):
|
||||
if isinstance(value, dsl.MuranoObjectInterface):
|
||||
value = value.object
|
||||
if isinstance(value, (six.string_types,
|
||||
@@ -103,10 +113,11 @@ def _pass12_serialize(value, parent, serialized_objects,
|
||||
result['?'].update(designer_attributes_getter(value.object_id))
|
||||
# deserialize and merge list of actions
|
||||
result['?']['_actions'] = _serialize_available_action(
|
||||
value, result['?'].get('_actions', {}))
|
||||
value, result['?'].get('_actions', {}), executor)
|
||||
serialized_objects.add(value.object_id)
|
||||
return _pass12_serialize(
|
||||
result, value, serialized_objects, designer_attributes_getter)
|
||||
result, value, serialized_objects, designer_attributes_getter,
|
||||
executor)
|
||||
elif isinstance(value, utils.MappingType):
|
||||
result = {}
|
||||
need_another_pass = False
|
||||
@@ -115,7 +126,7 @@ def _pass12_serialize(value, parent, serialized_objects,
|
||||
result_key = str(d_key)
|
||||
result_value = _pass12_serialize(
|
||||
d_value, parent, serialized_objects,
|
||||
designer_attributes_getter)
|
||||
designer_attributes_getter, executor)
|
||||
result[result_key] = result_value[0]
|
||||
if result_value[1]:
|
||||
need_another_pass = True
|
||||
@@ -125,7 +136,8 @@ def _pass12_serialize(value, parent, serialized_objects,
|
||||
result = []
|
||||
for t in value:
|
||||
v, nmp = _pass12_serialize(
|
||||
t, parent, serialized_objects, designer_attributes_getter)
|
||||
t, parent, serialized_objects, designer_attributes_getter,
|
||||
executor)
|
||||
if nmp:
|
||||
need_another_pass = True
|
||||
result.append(v)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
Name: ContractExamples
|
||||
|
||||
Extends: CommonParent
|
||||
|
||||
Properties:
|
||||
sampleClass:
|
||||
Contract: $.class(SampleClass1)
|
||||
@@ -146,3 +148,18 @@ Methods:
|
||||
Body:
|
||||
Return: $arg
|
||||
|
||||
testActionMeta:
|
||||
Scope: Public
|
||||
Meta:
|
||||
- io.murano.metadata.Title:
|
||||
text: "Title of the method"
|
||||
- io.murano.metadata.Description:
|
||||
text: "Description of the method"
|
||||
- io.murano.metadata.HelpText:
|
||||
text: "HelpText of the method"
|
||||
|
||||
notAction:
|
||||
Scope: Session
|
||||
|
||||
testAction:
|
||||
Scope: Public
|
||||
|
||||
@@ -32,7 +32,8 @@ class TestConstruction(test_case.DslTestCase):
|
||||
self.traces)
|
||||
|
||||
def test_new_with_ownership(self):
|
||||
obj = serializer.serialize(self._runner.testNewWithOwnership())
|
||||
obj = serializer.serialize(self._runner.testNewWithOwnership(),
|
||||
self._runner.executor)
|
||||
self.assertEqual('STRING', obj.get('property1'))
|
||||
self.assertIsNotNone('string', obj.get('xxx'))
|
||||
self.assertEqual('STR', obj['xxx'].get('property1'))
|
||||
|
||||
@@ -89,14 +89,28 @@ class TestResultsSerializer(test_case.DslTestCase):
|
||||
|
||||
"""
|
||||
serialized = self._runner.serialized_model
|
||||
self.assertIsInstance(
|
||||
serialized['Objects']['?'].get('_actions'), dict)
|
||||
for action in serialized['Objects']['?']['_actions'].values():
|
||||
actions = serialized['Objects']['?'].get('_actions')
|
||||
self.assertIsInstance(actions, dict)
|
||||
action_names = [action['name'] for action in actions.values()]
|
||||
self.assertIn('testAction', action_names)
|
||||
self.assertNotIn('notAction', action_names)
|
||||
self.assertIn('testRootMethod', action_names)
|
||||
action_meta = None
|
||||
for action in actions.values():
|
||||
self.assertIsInstance(action.get('enabled'), bool)
|
||||
self.assertIsInstance(action.get('name'), six.string_types)
|
||||
self.assertThat(
|
||||
action['name'],
|
||||
matchers.StartsWith('test'))
|
||||
if action['name'] == 'testActionMeta':
|
||||
action_meta = action
|
||||
else:
|
||||
self.assertEqual(action['title'], action['name'])
|
||||
self.assertIsNotNone(action_meta)
|
||||
self.assertEqual(action_meta['title'], "Title of the method")
|
||||
self.assertEqual(action_meta['description'],
|
||||
"Description of the method")
|
||||
self.assertEqual(action_meta['helpText'], "HelpText of the method")
|
||||
|
||||
def test_attribute_serialization(self):
|
||||
"""Test that attributes produced by MuranoPL code are persisted
|
||||
@@ -152,4 +166,4 @@ class TestResultsSerializer(test_case.DslTestCase):
|
||||
'key5': {'x': 'y'},
|
||||
'key6': [{'w': 'q'}]
|
||||
},
|
||||
serializer.serialize(result))
|
||||
serializer.serialize(result, runner.executor))
|
||||
|
||||
@@ -12,79 +12,10 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
|
||||
from murano.dsl import dsl_types
|
||||
from murano.dsl import serializer
|
||||
from murano.services import actions
|
||||
from murano.tests.unit import base
|
||||
|
||||
|
||||
class TestActionsSerializer(base.MuranoTestCase):
|
||||
def setUp(self):
|
||||
super(TestActionsSerializer, self).setUp()
|
||||
|
||||
def _get_mocked_obj(self):
|
||||
method1 = mock.Mock()
|
||||
method1.scope = dsl_types.MethodScopes.Public
|
||||
method1.name = 'method1'
|
||||
method2 = mock.Mock()
|
||||
method2.usage = dsl_types.MethodUsages.Runtime
|
||||
method2.name = 'method2'
|
||||
method3 = mock.Mock()
|
||||
method3.scope = dsl_types.MethodScopes.Public
|
||||
method3.name = 'method3'
|
||||
method4 = mock.Mock()
|
||||
method4.usage = dsl_types.MethodUsages.Action
|
||||
method4.name = 'method4'
|
||||
|
||||
for method in [method1, method2, method3, method4]:
|
||||
method.is_action = (method.scope ==
|
||||
dsl_types.MethodScopes.Public or
|
||||
method.usage == dsl_types.MethodUsages.Action)
|
||||
|
||||
obj2_type = mock.Mock()
|
||||
obj2_type.declared_parents = []
|
||||
obj2_type.methods = {'method3': method3}
|
||||
obj2_type.type.find_methods = lambda p: filter(p, [method3])
|
||||
|
||||
obj = mock.Mock()
|
||||
obj.object_id = 'id1'
|
||||
obj.type.declared_parents = [obj2_type]
|
||||
obj.type.methods = {'method1': method1, 'method2': method2,
|
||||
'method4': method4}
|
||||
obj.type.find_methods = lambda p: filter(
|
||||
p, [method1, method2, method3, method4])
|
||||
|
||||
return obj
|
||||
|
||||
def test_object_actions_serialization(self):
|
||||
obj = self._get_mocked_obj()
|
||||
|
||||
obj_actions = serializer._serialize_available_action(obj, {})
|
||||
|
||||
self.assertIn('id1_method1', obj_actions)
|
||||
self.assertIn('id1_method4', obj_actions)
|
||||
expected_result = {'name': 'method1', 'enabled': True}
|
||||
self.assertEqual(expected_result, obj_actions['id1_method1'])
|
||||
expected_result = {'name': 'method4', 'enabled': True}
|
||||
self.assertEqual(expected_result, obj_actions['id1_method4'])
|
||||
|
||||
def test_that_only_actions_are_serialized(self):
|
||||
obj = self._get_mocked_obj()
|
||||
obj_actions = serializer._serialize_available_action(obj, {})
|
||||
self.assertNotIn('id1_method2', obj_actions)
|
||||
|
||||
def test_parent_actions_are_serialized(self):
|
||||
obj = self._get_mocked_obj()
|
||||
|
||||
obj_actions = serializer._serialize_available_action(obj, {})
|
||||
|
||||
expected_result = {'name': 'method3', 'enabled': True}
|
||||
self.assertIn('id1_method3', obj_actions)
|
||||
self.assertEqual(expected_result, obj_actions['id1_method3'])
|
||||
|
||||
|
||||
class TestActionFinder(base.MuranoTestCase):
|
||||
def setUp(self):
|
||||
super(TestActionFinder, self).setUp()
|
||||
|
||||
Reference in New Issue
Block a user