From 49a630d23126b12b4dc53bfd0371d3eb22fed838 Mon Sep 17 00:00:00 2001 From: Winson Chan Date: Fri, 4 Dec 2015 05:19:11 +0000 Subject: [PATCH] Fix state_info details for with-items task error For workflow with error in a with-items task, the workflow state_info should only include the output for action executions that erred. Change-Id: Iad1a1af1d68d7810d56bcb5335fe31f54593aba4 Closes-Bug: #1522647 --- mistral/tests/unit/engine/test_state_info.py | 50 ++++++++++++++++++++ mistral/workflow/utils.py | 17 ++++--- 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/mistral/tests/unit/engine/test_state_info.py b/mistral/tests/unit/engine/test_state_info.py index d00e25d96..d2d1eac6c 100644 --- a/mistral/tests/unit/engine/test_state_info.py +++ b/mistral/tests/unit/engine/test_state_info.py @@ -1,4 +1,5 @@ # Copyright 2014 - Mirantis, Inc. +# Copyright 2015 - StackStorm, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,12 +13,17 @@ # See the License for the specific language governing permissions and # limitations under the License. +import mock + from oslo_config import cfg from oslo_log import log as logging +from mistral.actions import std_actions from mistral.db.v2 import api as db_api +from mistral import exceptions as exc from mistral.services import workflows as wf_service from mistral.tests.unit.engine import base +from mistral.workflow import states LOG = logging.getLogger(__name__) # Use the set_default method to set value otherwise in certain test cases @@ -99,3 +105,47 @@ class ExecutionStateInfoTest(base.EngineTestCase): wf_ex = db_api.get_workflow_execution(wf_ex.id) self.assertIn("error in tasks: task1", wf_ex.state_info) + + @mock.patch.object( + std_actions.EchoAction, + 'run', + mock.MagicMock( + side_effect=[ + exc.ActionException(), # Mock task1 exception for initial run. + 'Task 1.1', # Mock task1 success for initial run. + exc.ActionException(), # Mock task1 exception for initial run. + 'Task 1.0', # Mock task1 success for rerun. + 'Task 1.2' # Mock task1 success for rerun. + ] + ) + ) + def test_state_info_with_items(self): + workflow = """--- + version: '2.0' + wf: + type: direct + tasks: + t1: + with-items: i in <% list(range(0, 3)) %> + action: std.echo output="Task 1.<% $.i %>" + """ + + wf_service.create_workflows(workflow) + + wf_ex = self.engine.start_workflow('wf', {}) + self._await(lambda: self.is_execution_error(wf_ex.id)) + wf_ex = db_api.get_workflow_execution(wf_ex.id) + + self.assertEqual(states.ERROR, wf_ex.state) + + task_1_ex = self._assert_single_item(wf_ex.task_executions, name='t1') + + self.assertEqual(states.ERROR, task_1_ex.state) + + task_1_action_exs = db_api.get_action_executions( + task_execution_id=task_1_ex.id) + + self.assertEqual(3, len(task_1_action_exs)) + self.assertIn(task_1_action_exs[0].id, wf_ex.state_info) + self.assertNotIn(task_1_action_exs[1].id, wf_ex.state_info) + self.assertIn(task_1_action_exs[2].id, wf_ex.state_info) diff --git a/mistral/workflow/utils.py b/mistral/workflow/utils.py index 7c499501d..411e3a5f1 100644 --- a/mistral/workflow/utils.py +++ b/mistral/workflow/utils.py @@ -1,4 +1,5 @@ # Copyright 2014 - Mirantis, Inc. +# Copyright 2015 - StackStorm, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -121,13 +122,17 @@ def construct_fail_info_message(wf_ctrl, wf_ex): ', '.join([t.name for t in failed_tasks])) for t in failed_tasks: - msg += '\n %s -> ' % t.name + msg += '\n %s [task_ex_id=%s] -> %s\n' % (t.name, t.id, t.state_info) - if t.state_info: - msg += t.state_info + '\n' - else: - for i, ex in enumerate(t.executions): + for i, ex in enumerate(t.executions): + if ex.state == states.ERROR: output = (ex.output or dict()).get('result', 'Unknown') - msg += ' action execution #%s: %s\n' % (i + 1, str(output)) + msg += ( + ' [action_ex_id=%s, idx=%s]: %s\n' % ( + ex.id, + i, + str(output) + ) + ) return msg