From 8b2f63cbdf84c908e31408575cf87ad565479b0b Mon Sep 17 00:00:00 2001 From: Bob Haddleton Date: Fri, 1 Sep 2017 11:18:16 -0500 Subject: [PATCH] Catch DBEntityNotFoundError exceptions for invalid AdHoc Actions This patch will catch the DBEntityNotFoundError exception that is raised when an AdHoc Action has an invalid base action defined. The exception is converted to an InvalidActionException which will halt the task/workflow and cause them to enter the ERROR state. Change-Id: I115b8243641da100474e8c8b34a724978078978b Closes-Bug: 1714548 --- mistral/engine/actions.py | 20 ++++-- .../tests/unit/engine/test_adhoc_actions.py | 65 +++++++++++++++++++ mistral/tests/unit/engine/test_run_action.py | 16 ++++- 3 files changed, 96 insertions(+), 5 deletions(-) diff --git a/mistral/engine/actions.py b/mistral/engine/actions.py index 602e5ddbc..2f11d5892 100644 --- a/mistral/engine/actions.py +++ b/mistral/engine/actions.py @@ -361,9 +361,16 @@ class AdHocAction(PythonAction): wf_ctx=None): self.action_spec = spec_parser.get_action_spec(action_def.spec) - base_action_def = db_api.get_action_definition( - self.action_spec.get_base() - ) + try: + base_action_def = db_api.get_action_definition( + self.action_spec.get_base() + ) + except exc.DBEntityNotFoundError: + raise exc.InvalidActionException( + "Failed to find action [action_name=%s]" % + self.action_spec.get_base() + ) + base_action_def = self._gather_base_actions( action_def, base_action_def ) @@ -477,7 +484,12 @@ class AdHocAction(PythonAction): self.adhoc_action_defs.append(base) base_name = base.spec['base'] - base = db_api.get_action_definition(base_name) + try: + base = db_api.get_action_definition(base_name) + except exc.DBEntityNotFoundError: + raise exc.InvalidActionException( + "Failed to find action [action_name=%s]" % base_name + ) # if the action is repeated if base.name in action_names: diff --git a/mistral/tests/unit/engine/test_adhoc_actions.py b/mistral/tests/unit/engine/test_adhoc_actions.py index a8f0c051e..713026c84 100644 --- a/mistral/tests/unit/engine/test_adhoc_actions.py +++ b/mistral/tests/unit/engine/test_adhoc_actions.py @@ -55,6 +55,16 @@ actions: output: nested_concat: '{{ _ }}' + missing_base: + base: wrong + input: + - some_input + + nested_missing_base: + base: missing_base + input: + - some_input + workflows: wf1: type: direct @@ -118,6 +128,32 @@ workflows: action: nested_concat publish: nested_result: '{{ task().result }}' + + wf6: + type: direct + output: + workflow_result: '{{ _.missing_result }}' + tasks: + missing_action: + action: missing_base + on-complete: + - next_action + next_action: + publish: + missing_result: 'Finished' + + wf7: + type: direct + output: + workflow_result: '{{ _.missing_result }}' + tasks: + nested_missing_action: + action: nested_missing_base + on-complete: + - next_action + next_action: + publish: + missing_result: 'Finished' """ @@ -205,3 +241,32 @@ class AdhocActionsTest(base.EngineTestCase): }, wf_ex.output ) + + def test_missing_adhoc_action_definition(self): + wf_ex = self.engine.start_workflow( + 'my_wb.wf6', '') + self.await_workflow_error(wf_ex.id) + with db_api.transaction(): + # Note: We need to reread execution to access related tasks. + wf_ex = db_api.get_workflow_execution(wf_ex.id) + + tasks = wf_ex.task_executions + + task1 = self._assert_single_item(tasks, name='missing_action') + + self.assertEqual(states.ERROR, task1.state) + + def test_nested_missing_adhoc_action_definition(self): + wf_ex = self.engine.start_workflow( + 'my_wb.wf7', '') + self.await_workflow_error(wf_ex.id) + with db_api.transaction(): + # Note: We need to reread execution to access related tasks. + wf_ex = db_api.get_workflow_execution(wf_ex.id) + + tasks = wf_ex.task_executions + + task1 = self._assert_single_item(tasks, + name='nested_missing_action') + + self.assertEqual(states.ERROR, task1.state) diff --git a/mistral/tests/unit/engine/test_run_action.py b/mistral/tests/unit/engine/test_run_action.py index bb87b72ee..040ab4412 100644 --- a/mistral/tests/unit/engine/test_run_action.py +++ b/mistral/tests/unit/engine/test_run_action.py @@ -72,6 +72,11 @@ class RunActionEngineTest(base.EngineTestCase): input: - some_input + nested_missing_base: + base: missing_base + input: + - some_input + loop_action: base: loop_action base-input: @@ -235,12 +240,21 @@ class RunActionEngineTest(base.EngineTestCase): def test_run_action_with_missing_base(self): # Start action and see the result. self.assertRaises( - exc.DBEntityNotFoundError, + exc.InvalidActionException, self.engine.start_action, 'missing_base', {'some_input': 'Hi'} ) + def test_run_action_with_missing_nested_base(self): + # Start action and see the result. + self.assertRaises( + exc.InvalidActionException, + self.engine.start_action, + 'nested_missing_base', + {'some_input': 'Hi'} + ) + def test_run_loop_action(self): # Start action and see the result. self.assertRaises(