diff --git a/mistral/tests/unit/workbook/v2/test_dsl_specs_v2.py b/mistral/tests/unit/workbook/v2/test_dsl_specs_v2.py index 2a8ad374..cb6cedc2 100644 --- a/mistral/tests/unit/workbook/v2/test_dsl_specs_v2.py +++ b/mistral/tests/unit/workbook/v2/test_dsl_specs_v2.py @@ -196,12 +196,15 @@ class DSLv2ModelTest(base.BaseTest): self.assertEqual('wf2', wf2_spec.get_name()) self.assertEqual('direct', wf2_spec.get_type()) self.assertEqual(6, len(wf2_spec.get_tasks())) - self.assertDictEqual( - {'fail': '$.my_val = 0'}, + self.assertListEqual( + [('fail', '$.my_val = 0')], wf2_spec.get_on_task_error() ) - self.assertDictEqual({'pause': ''}, wf2_spec.get_on_task_success()) - self.assertDictEqual({'succeed': ''}, wf2_spec.get_on_task_complete()) + self.assertListEqual([('pause', '')], wf2_spec.get_on_task_success()) + self.assertListEqual( + [('succeed', '')], + wf2_spec.get_on_task_complete() + ) task3_spec = wf2_spec.get_tasks().get('task3') @@ -219,16 +222,16 @@ class DSLv2ModelTest(base.BaseTest): }, task3_spec.get_parameters() ) - self.assertDictEqual( - {'task4': '$.my_val = 1'}, + self.assertListEqual( + [('task4', '$.my_val = 1')], task3_spec.get_on_error() ) - self.assertDictEqual( - {'task5': '$.my_val = 2'}, + self.assertListEqual( + [('task5', '$.my_val = 2')], task3_spec.get_on_success() ) - self.assertDictEqual( - {'task6': '$.my_val = 3'}, + self.assertListEqual( + [('task6', '$.my_val = 3')], task3_spec.get_on_complete() ) diff --git a/mistral/workbook/base.py b/mistral/workbook/base.py index 8af44b0b..e3f39278 100644 --- a/mistral/workbook/base.py +++ b/mistral/workbook/base.py @@ -56,7 +56,7 @@ class BaseSpec(object): if isinstance(prop_data, dict): prop_data['version'] = self._version - def _get_as_dict(self, prop_name): + def _as_dict(self, prop_name): prop_val = self._data.get(prop_name) if not prop_val: @@ -72,6 +72,18 @@ class BaseSpec(object): elif isinstance(prop_val, six.string_types): return {prop_val: ''} + def _as_list_of_tuples(self, prop_name): + prop_val = self._data.get(prop_name) + + if not prop_val: + return [] + + return [self._as_tuple(item) for item in prop_val] + + @staticmethod + def _as_tuple(val): + return val.items()[0] if isinstance(val, dict) else (val, '') + @staticmethod def _parse_cmd_and_params(cmd_str): # TODO(rakhmerov): Try to find a way with one expression. diff --git a/mistral/workbook/v1/tasks.py b/mistral/workbook/v1/tasks.py index 88613dfd..b24d7ce2 100644 --- a/mistral/workbook/v1/tasks.py +++ b/mistral/workbook/v1/tasks.py @@ -58,16 +58,16 @@ class TaskSpec(base.BaseSpec): return self._data.get(property_name, default) def get_requires(self): - return self._get_as_dict('requires').keys() + return self._as_dict('requires').keys() def get_on_error(self): - return self._get_as_dict("on-error") + return self._as_dict("on-error") def get_on_success(self): - return self._get_as_dict("on-success") + return self._as_dict("on-success") def get_on_finish(self): - return self._get_as_dict("on-finish") + return self._as_dict("on-finish") def get_action_namespace(self): return self.action.split('.')[0] diff --git a/mistral/workbook/v2/tasks.py b/mistral/workbook/v2/tasks.py index d2564222..47a59b24 100644 --- a/mistral/workbook/v2/tasks.py +++ b/mistral/workbook/v2/tasks.py @@ -112,13 +112,13 @@ class TaskSpec(base.BaseSpec): return self._requires def get_on_complete(self): - return self._get_as_dict("on-complete") + return self._as_list_of_tuples('on-complete') def get_on_success(self): - return self._get_as_dict("on-success") + return self._as_list_of_tuples('on-success') def get_on_error(self): - return self._get_as_dict("on-error") + return self._as_list_of_tuples('on-error') class TaskSpecList(base.BaseSpecList): diff --git a/mistral/workbook/v2/workflows.py b/mistral/workbook/v2/workflows.py index 6ce9cd40..39a28c58 100644 --- a/mistral/workbook/v2/workflows.py +++ b/mistral/workbook/v2/workflows.py @@ -71,13 +71,13 @@ class WorkflowSpec(base.BaseSpec): return self._policies def get_on_task_complete(self): - return self._get_as_dict("on-task-complete") + return self._as_list_of_tuples("on-task-complete") def get_on_task_success(self): - return self._get_as_dict("on-task-success") + return self._as_list_of_tuples("on-task-success") def get_on_task_error(self): - return self._get_as_dict("on-task-error") + return self._as_list_of_tuples("on-task-error") def get_tasks(self): return self._tasks diff --git a/mistral/workflow/direct_workflow.py b/mistral/workflow/direct_workflow.py index 7e8d79d8..bb57c6b0 100644 --- a/mistral/workflow/direct_workflow.py +++ b/mistral/workflow/direct_workflow.py @@ -56,18 +56,26 @@ class DirectWorkflowHandler(base.WorkflowHandler): return [commands.RunTask(t_s) for t_s in start_task_specs] def _has_inbound_transitions(self, task_spec): - task_name = task_spec.get_name() - for t_s in self.wf_spec.get_tasks(): - t_n = t_s.get_name() - - if task_name in self.get_on_error_clause(t_n) \ - or task_name in self.get_on_success_clause(t_n) \ - or task_name in self.get_on_complete_clause(t_n): + if self._transition_exists(t_s.get_name(), task_spec.get_name()): return True return False + def _transition_exists(self, from_task_name, to_task_name): + t_names = set() + + for tup in self.get_on_error_clause(from_task_name): + t_names.add(tup[0]) + + for tup in self.get_on_success_clause(from_task_name): + t_names.add(tup[0]) + + for tup in self.get_on_complete_clause(from_task_name): + t_names.add(tup[0]) + + return to_task_name in t_names + def _find_next_commands(self, task_db): """Finds commands that should run after completing given task. @@ -120,7 +128,7 @@ class DirectWorkflowHandler(base.WorkflowHandler): def _get_next_commands(self, cmd_conditions, ctx): commands = [] - for t_name, condition in cmd_conditions.iteritems(): + for t_name, condition in cmd_conditions: if not condition or expr.evaluate(condition, ctx): commands.append(self.build_command(t_name))