Exemple #1
0
class MistralRunnerTest(DbTestCase):
    @classmethod
    def setUpClass(cls):
        super(MistralRunnerTest, cls).setUpClass()
        runners_registrar.register_runner_types()

        for _, fixture in six.iteritems(FIXTURES['actions']):
            instance = ActionAPI(**fixture)
            Action.add_or_update(ActionAPI.to_model(instance))

    def setUp(self):
        super(MistralRunnerTest, self).setUp()
        cfg.CONF.set_override('api_url', 'http://0.0.0.0:9101', group='auth')

    def tearDown(self):
        super(MistralRunnerTest, self).tearDown()
        cfg.CONF.set_default('max_attempts', 2, group='mistral')
        cfg.CONF.set_default('retry_wait', 1, group='mistral')

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workflows.WorkflowManager, 'get',
                       mock.MagicMock(return_value=WF1))
    @mock.patch.object(workflows.WorkflowManager, 'create',
                       mock.MagicMock(return_value=[WF1]))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC)))
    def test_launch_workflow(self):
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WF1_YAML_FILE_PATH)
        liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS)
        liveaction, execution = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status,
                         action_constants.LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'],
                         WF1_EXEC.get('workflow_name'))

        workflow_input = copy.deepcopy(ACTION_PARAMS)
        workflow_input.update({'count': '3'})

        env = {
            'st2_execution_id': str(execution.id),
            'st2_liveaction_id': str(liveaction.id),
            '__actions': {
                'st2.action': {
                    'st2_context': {
                        'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions',
                        'parent': {
                            'execution_id': str(execution.id)
                        },
                        'notify': {},
                        'skip_notify_tasks': []
                    }
                }
            }
        }

        executions.ExecutionManager.create.assert_called_with(
            WF1_NAME, workflow_input=workflow_input, env=env)

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workflows.WorkflowManager, 'get',
                       mock.MagicMock(return_value=WF1))
    @mock.patch.object(workflows.WorkflowManager, 'create',
                       mock.MagicMock(return_value=[WF1]))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC)))
    def test_launch_workflow_with_st2_https(self):
        cfg.CONF.set_override('api_url', 'https://0.0.0.0:9101', group='auth')

        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WF1_YAML_FILE_PATH)
        liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS)
        liveaction, execution = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status,
                         action_constants.LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'],
                         WF1_EXEC.get('workflow_name'))

        workflow_input = copy.deepcopy(ACTION_PARAMS)
        workflow_input.update({'count': '3'})

        env = {
            'st2_execution_id': str(execution.id),
            'st2_liveaction_id': str(liveaction.id),
            '__actions': {
                'st2.action': {
                    'st2_context': {
                        'endpoint': 'https://0.0.0.0:9101/v1/actionexecutions',
                        'parent': {
                            'execution_id': str(execution.id)
                        },
                        'notify': {},
                        'skip_notify_tasks': []
                    }
                }
            }
        }

        executions.ExecutionManager.create.assert_called_with(
            WF1_NAME, workflow_input=workflow_input, env=env)

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workflows.WorkflowManager, 'get',
                       mock.MagicMock(return_value=WF1))
    @mock.patch.object(workflows.WorkflowManager, 'create',
                       mock.MagicMock(return_value=[WF1]))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC)))
    def test_launch_workflow_with_notifications(self):
        notify_data = {
            'on_complete': {
                'routes': ['slack'],
                'message': '"@channel: Action succeeded."',
                'data': {}
            }
        }

        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WF1_YAML_FILE_PATH)
        liveaction = LiveActionDB(action=WF1_NAME,
                                  parameters=ACTION_PARAMS,
                                  notify=notify_data)
        liveaction, execution = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status,
                         action_constants.LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'],
                         WF1_EXEC.get('workflow_name'))

        workflow_input = copy.deepcopy(ACTION_PARAMS)
        workflow_input.update({'count': '3'})

        env = {
            'st2_execution_id': str(execution.id),
            'st2_liveaction_id': str(liveaction.id),
            '__actions': {
                'st2.action': {
                    'st2_context': {
                        'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions',
                        'parent': {
                            'execution_id': str(execution.id)
                        },
                        'notify':
                        NotificationsHelper.from_model(liveaction.notify),
                        'skip_notify_tasks': []
                    }
                }
            }
        }

        executions.ExecutionManager.create.assert_called_with(
            WF1_NAME, workflow_input=workflow_input, env=env)

    @mock.patch.object(
        workflows.WorkflowManager, 'list',
        mock.MagicMock(side_effect=requests.exceptions.ConnectionError()))
    def test_launch_workflow_mistral_offline(self):
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WF1_YAML_FILE_PATH)
        liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS)
        liveaction, execution = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status,
                         action_constants.LIVEACTION_STATUS_FAILED)
        self.assertIn('Failed to connect to mistral',
                      liveaction.result['error'])

    @mock.patch.object(
        workflows.WorkflowManager, 'list',
        mock.MagicMock(side_effect=[requests.exceptions.ConnectionError(), []])
    )
    @mock.patch.object(workflows.WorkflowManager, 'get',
                       mock.MagicMock(return_value=WF1))
    @mock.patch.object(workflows.WorkflowManager, 'create',
                       mock.MagicMock(return_value=[WF1]))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC)))
    def test_launch_workflow_mistral_retry(self):
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WF1_YAML_FILE_PATH)
        liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS)
        liveaction, execution = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status,
                         action_constants.LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'],
                         WF1_EXEC.get('workflow_name'))

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workflows.WorkflowManager, 'get',
                       mock.MagicMock(return_value=WF1))
    @mock.patch.object(
        workflows.WorkflowManager, 'create',
        mock.MagicMock(
            side_effect=[APIException(error_message='Duplicate entry.'), WF1]))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC)))
    def test_launch_workflow_duplicate_error(self):
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WF1_YAML_FILE_PATH)
        liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS)
        liveaction, execution = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status,
                         action_constants.LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'],
                         WF1_EXEC.get('workflow_name'))

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workflows.WorkflowManager, 'get',
                       mock.MagicMock(return_value=WF1_OLD))
    @mock.patch.object(workflows.WorkflowManager, 'create',
                       mock.MagicMock(return_value=[WF1]))
    @mock.patch.object(workflows.WorkflowManager, 'update',
                       mock.MagicMock(return_value=[WF1]))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC)))
    def test_launch_when_workflow_definition_changed(self):
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WF1_YAML_FILE_PATH)
        liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS)
        liveaction, execution = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status,
                         action_constants.LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'],
                         WF1_EXEC.get('workflow_name'))

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workflows.WorkflowManager, 'get',
                       mock.MagicMock(side_effect=Exception()))
    @mock.patch.object(workbooks.WorkbookManager, 'delete',
                       mock.MagicMock(side_effect=Exception()))
    @mock.patch.object(workflows.WorkflowManager, 'create',
                       mock.MagicMock(return_value=[WF1]))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC)))
    def test_launch_when_workflow_not_exists(self):
        liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS)
        liveaction, execution = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status,
                         action_constants.LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'],
                         WF1_EXEC.get('workflow_name'))

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workflows.WorkflowManager, 'get',
                       mock.MagicMock(return_value=WF2))
    def test_launch_workflow_with_many_workflows(self):
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WF2_YAML_FILE_PATH)
        liveaction = LiveActionDB(action=WF2_NAME, parameters=ACTION_PARAMS)
        liveaction, execution = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status,
                         action_constants.LIVEACTION_STATUS_FAILED)
        self.assertIn('Multiple workflows is not supported.',
                      liveaction.result['error'])

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workflows.WorkflowManager, 'get',
                       mock.MagicMock(side_effect=Exception()))
    def test_launch_workflow_name_mistmatch(self):
        action_ref = 'generic.workflow_v2_name_mismatch'
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WF1_YAML_FILE_PATH)
        liveaction = LiveActionDB(action=action_ref, parameters=ACTION_PARAMS)
        liveaction, execution = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status,
                         action_constants.LIVEACTION_STATUS_FAILED)
        self.assertIn('Name of the workflow must be the same',
                      liveaction.result['error'])

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workbooks.WorkbookManager, 'get',
                       mock.MagicMock(return_value=WB1))
    @mock.patch.object(workbooks.WorkbookManager, 'create',
                       mock.MagicMock(return_value=WB1))
    @mock.patch.object(workbooks.WorkbookManager, 'update',
                       mock.MagicMock(return_value=WB1))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WB1_EXEC)))
    def test_launch_workbook(self):
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WB1_YAML_FILE_PATH)
        liveaction = LiveActionDB(action=WB1_NAME, parameters=ACTION_PARAMS)
        liveaction, execution = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status,
                         action_constants.LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WB1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'],
                         WB1_EXEC.get('workflow_name'))

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workbooks.WorkbookManager, 'get',
                       mock.MagicMock(return_value=WB2))
    @mock.patch.object(workbooks.WorkbookManager, 'create',
                       mock.MagicMock(return_value=WB2))
    @mock.patch.object(workbooks.WorkbookManager, 'update',
                       mock.MagicMock(return_value=WB2))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WB2_EXEC)))
    def test_launch_workbook_with_many_workflows(self):
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WB2_YAML_FILE_PATH)
        liveaction = LiveActionDB(action=WB2_NAME, parameters=ACTION_PARAMS)
        liveaction, execution = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status,
                         action_constants.LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WB2_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'],
                         WB2_EXEC.get('workflow_name'))

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workbooks.WorkbookManager, 'get',
                       mock.MagicMock(return_value=WB3))
    @mock.patch.object(workbooks.WorkbookManager, 'create',
                       mock.MagicMock(return_value=WB3))
    @mock.patch.object(workbooks.WorkbookManager, 'update',
                       mock.MagicMock(return_value=WB3))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WB3_EXEC)))
    def test_launch_workbook_with_many_workflows_no_default(self):
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WB3_YAML_FILE_PATH)
        liveaction = LiveActionDB(action=WB3_NAME, parameters=ACTION_PARAMS)
        liveaction, execution = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status,
                         action_constants.LIVEACTION_STATUS_FAILED)
        self.assertIn('Default workflow cannot be determined.',
                      liveaction.result['error'])

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workbooks.WorkbookManager, 'get',
                       mock.MagicMock(return_value=WB1_OLD))
    @mock.patch.object(workbooks.WorkbookManager, 'create',
                       mock.MagicMock(return_value=WB1))
    @mock.patch.object(workbooks.WorkbookManager, 'update',
                       mock.MagicMock(return_value=WB1))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WB1_EXEC)))
    def test_launch_when_workbook_definition_changed(self):
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WB1_YAML_FILE_PATH)
        liveaction = LiveActionDB(action=WB1_NAME, parameters=ACTION_PARAMS)
        liveaction, execution = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status,
                         action_constants.LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WB1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'],
                         WB1_EXEC.get('workflow_name'))

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workbooks.WorkbookManager, 'get',
                       mock.MagicMock(side_effect=Exception()))
    @mock.patch.object(workflows.WorkflowManager, 'delete',
                       mock.MagicMock(side_effect=Exception()))
    @mock.patch.object(workbooks.WorkbookManager, 'create',
                       mock.MagicMock(return_value=WB1))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WB1_EXEC)))
    def test_launch_when_workbook_not_exists(self):
        liveaction = LiveActionDB(action=WB1_NAME, parameters=ACTION_PARAMS)
        liveaction, execution = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status,
                         action_constants.LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WB1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'],
                         WB1_EXEC.get('workflow_name'))

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workbooks.WorkbookManager, 'get',
                       mock.MagicMock(side_effect=Exception()))
    def test_launch_workbook_name_mismatch(self):
        action_ref = 'generic.workbook_v2_name_mismatch'
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WB1_YAML_FILE_PATH)
        liveaction = LiveActionDB(action=action_ref, parameters=ACTION_PARAMS)
        liveaction, execution = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status,
                         action_constants.LIVEACTION_STATUS_FAILED)
        self.assertIn('Name of the workbook must be the same',
                      liveaction.result['error'])

    @mock.patch.object(
        requests, 'request',
        mock.MagicMock(return_value=http.FakeResponse({}, 200, 'OK')))
    def test_callback_handler_with_result_as_text(self):
        MistralCallbackHandler.callback(
            'http://localhost:8989/v2/action_executions/12345', {},
            action_constants.LIVEACTION_STATUS_SUCCEEDED, '<html></html>')

    @mock.patch.object(
        requests, 'request',
        mock.MagicMock(return_value=http.FakeResponse({}, 200, 'OK')))
    def test_callback_handler_with_result_as_dict(self):
        MistralCallbackHandler.callback(
            'http://localhost:8989/v2/action_executions/12345', {},
            action_constants.LIVEACTION_STATUS_SUCCEEDED, {'a': 1})

    @mock.patch.object(
        requests, 'request',
        mock.MagicMock(return_value=http.FakeResponse({}, 200, 'OK')))
    def test_callback_handler_with_result_as_json_str(self):
        MistralCallbackHandler.callback(
            'http://localhost:8989/v2/action_executions/12345', {},
            action_constants.LIVEACTION_STATUS_SUCCEEDED, '{"a": 1}')
        MistralCallbackHandler.callback(
            'http://localhost:8989/v2/action_executions/12345', {},
            action_constants.LIVEACTION_STATUS_SUCCEEDED, "{'a': 1}")

    @mock.patch.object(
        requests, 'request',
        mock.MagicMock(return_value=http.FakeResponse({}, 200, 'OK')))
    def test_callback_handler_with_result_as_list(self):
        MistralCallbackHandler.callback(
            'http://localhost:8989/v2/action_executions/12345', {},
            action_constants.LIVEACTION_STATUS_SUCCEEDED, ["a", "b", "c"])

    @mock.patch.object(
        requests, 'request',
        mock.MagicMock(return_value=http.FakeResponse({}, 200, 'OK')))
    def test_callback_handler_with_result_as_list_str(self):
        MistralCallbackHandler.callback(
            'http://*****:*****@mock.patch.object(action_executions.ActionExecutionManager, 'update',
                       mock.MagicMock(return_value=None))
    def test_callback(self):
        liveaction = LiveActionDB(
            action='core.local',
            parameters={'cmd': 'uname -a'},
            callback={
                'source': 'mistral',
                'url': 'http://localhost:8989/v2/action_executions/12345'
            })

        liveaction, execution = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status,
                         action_constants.LIVEACTION_STATUS_SUCCEEDED)
        action_executions.ActionExecutionManager.update.assert_called_with(
            '12345', state='SUCCESS', output=NON_EMPTY_RESULT)

    @mock.patch.object(
        action_executions.ActionExecutionManager, 'update',
        mock.MagicMock(
            side_effect=[requests.exceptions.ConnectionError(), None]))
    def test_callback_retry(self):
        cfg.CONF.set_default('max_attempts', 3, group='mistral')
        cfg.CONF.set_default('retry_wait', 0, group='mistral')

        liveaction = LiveActionDB(
            action='core.local',
            parameters={'cmd': 'uname -a'},
            callback={
                'source': 'mistral',
                'url': 'http://*****:*****@mock.patch.object(action_executions.ActionExecutionManager, 'update',
                       mock.MagicMock(side_effect=[
                           requests.exceptions.ConnectionError(),
                           requests.exceptions.ConnectionError(),
                           requests.exceptions.ConnectionError(),
                           requests.exceptions.ConnectionError(), None
                       ]))
    def test_callback_retry_exhausted(self):
        cfg.CONF.set_default('max_attempts', 3, group='mistral')
        cfg.CONF.set_default('retry_wait', 0, group='mistral')

        liveaction = LiveActionDB(
            action='core.local',
            parameters={'cmd': 'uname -a'},
            callback={
                'source': 'mistral',
                'url': 'http://*****:*****@mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workflows.WorkflowManager, 'get',
                       mock.MagicMock(return_value=WF1))
    @mock.patch.object(workflows.WorkflowManager, 'create',
                       mock.MagicMock(return_value=[WF1]))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC)))
    @mock.patch.object(
        executions.ExecutionManager, 'update',
        mock.MagicMock(
            return_value=executions.Execution(None, WF1_EXEC_PAUSED)))
    def test_cancel(self):
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WF1_YAML_FILE_PATH)
        liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS)
        liveaction, execution = action_service.request(liveaction)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status,
                         action_constants.LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'],
                         WF1_EXEC.get('workflow_name'))

        requester = cfg.CONF.system_user.user
        liveaction, execution = action_service.request_cancellation(
            liveaction, requester)
        executions.ExecutionManager.update.assert_called_with(
            WF1_EXEC.get('id'), 'PAUSED')
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status,
                         action_constants.LIVEACTION_STATUS_CANCELED)

    def test_build_context(self):
        parent = {
            'mistral': {
                'workflow_name': 'foo',
                'workflow_execution_id':
                'b222b934-7473-4cd4-a2ec-e204a8c93848',
                'task_tags': None,
                'task_name': 'some_fancy_wf_task',
                'task_id': '6c7d4334-3e7d-49c6-918d-698e846affaf',
                'action_execution_id': '24da5c88-834c-4a65-8b56-4ddbd654eb68'
            }
        }

        current = {
            'workflow_name': 'foo.subwf',
            'workflow_execution_id': '135e3446-4c89-4afe-821f-6ec6a0849b27'
        }

        context = MistralRunner._build_mistral_context(parent, current)
        self.assertTrue(context is not None)
        self.assertTrue('parent' in context['mistral'].keys())

        parent_dict = {
            'workflow_name': parent['mistral']['workflow_name'],
            'workflow_execution_id': parent['mistral']['workflow_execution_id']
        }

        self.assertDictEqual(context['mistral']['parent'], parent_dict)
        self.assertEqual(context['mistral']['workflow_execution_id'],
                         current['workflow_execution_id'])

        parent = None
        context = MistralRunner._build_mistral_context(parent, current)
        self.assertDictEqual(context['mistral'], current)
Exemple #2
0
class TestMistralRunner(DbTestCase):

    @classmethod
    def setUpClass(cls):
        super(TestMistralRunner, cls).setUpClass()
        runners_registrar.register_runner_types()

        for _, fixture in six.iteritems(FIXTURES['actions']):
            instance = ActionAPI(**fixture)
            Action.add_or_update(ActionAPI.to_model(instance))

    @mock.patch.object(
        workflows.WorkflowManager, 'list',
        mock.MagicMock(return_value=[]))
    @mock.patch.object(
        workflows.WorkflowManager, 'get',
        mock.MagicMock(return_value=WF1))
    @mock.patch.object(
        workflows.WorkflowManager, 'create',
        mock.MagicMock(return_value=[WF1]))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC)))
    def test_launch_workflow(self):
        MistralRunner.entry_point = mock.PropertyMock(return_value=WF1_YAML_FILE_PATH)
        execution = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.request(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'], WF1_EXEC.get('workflow_name'))

        workflow_input = copy.deepcopy(ACTION_PARAMS)
        workflow_input.update({'count': '3'})

        env = {
            '__actions': {
                'st2.action': {
                    'st2_context': {
                        'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions',
                        'parent': str(liveaction.id),
                        'notify': {},
                        'skip_notify_tasks': []
                    }
                }
            }
        }

        executions.ExecutionManager.create.assert_called_with(
            WF1_NAME, workflow_input=workflow_input, env=env)

    @mock.patch.object(
        workflows.WorkflowManager, 'list',
        mock.MagicMock(return_value=[]))
    @mock.patch.object(
        workflows.WorkflowManager, 'get',
        mock.MagicMock(return_value=WF1))
    @mock.patch.object(
        workflows.WorkflowManager, 'create',
        mock.MagicMock(return_value=[WF1]))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC)))
    @mock.patch.object(
        access_service, 'create_token',
        mock.MagicMock(return_value=TOKEN_DB))
    def test_launch_workflow_with_auth(self):
        MistralRunner.entry_point = mock.PropertyMock(return_value=WF1_YAML_FILE_PATH)
        execution = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS, context=ACTION_CONTEXT)
        liveaction, _ = action_service.request(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'], WF1_EXEC.get('workflow_name'))

        workflow_input = copy.deepcopy(ACTION_PARAMS)
        workflow_input.update({'count': '3'})

        env = {
            '__actions': {
                'st2.action': {
                    'st2_context': {
                        'auth_token': TOKEN_DB.token,
                        'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions',
                        'parent': str(liveaction.id),
                        'notify': {},
                        'skip_notify_tasks': []
                    }
                }
            }
        }

        executions.ExecutionManager.create.assert_called_with(
            WF1_NAME, workflow_input=workflow_input, env=env)

    @mock.patch.object(
        workflows.WorkflowManager, 'list',
        mock.MagicMock(return_value=[]))
    @mock.patch.object(
        workflows.WorkflowManager, 'get',
        mock.MagicMock(return_value=WF1))
    @mock.patch.object(
        workflows.WorkflowManager, 'create',
        mock.MagicMock(return_value=[WF1]))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC)))
    def test_launch_workflow_with_notifications(self):
        notify_data = {'on_complete': {'channels': ['slack'],
                       'message': '"@channel: Action succeeded."', 'data': {}}}

        MistralRunner.entry_point = mock.PropertyMock(return_value=WF1_YAML_FILE_PATH)
        execution = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS, notify=notify_data)
        liveaction, _ = action_service.request(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'], WF1_EXEC.get('workflow_name'))

        workflow_input = copy.deepcopy(ACTION_PARAMS)
        workflow_input.update({'count': '3'})

        env = {
            '__actions': {
                'st2.action': {
                    'st2_context': {
                        'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions',
                        'parent': str(liveaction.id),
                        'notify': NotificationsHelper.from_model(liveaction.notify),
                        'skip_notify_tasks': []
                    }
                }
            }
        }

        executions.ExecutionManager.create.assert_called_with(
            WF1_NAME, workflow_input=workflow_input, env=env)

    @mock.patch.object(
        workflows.WorkflowManager, 'list',
        mock.MagicMock(side_effect=requests.exceptions.ConnectionError()))
    def test_launch_workflow_mistral_offline(self):
        MistralRunner.entry_point = mock.PropertyMock(return_value=WF1_YAML_FILE_PATH)
        execution = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.request(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_FAILED)
        self.assertIn('Failed to connect to mistral', liveaction.result['message'])

    @mock.patch.object(
        workflows.WorkflowManager, 'list',
        mock.MagicMock(side_effect=[requests.exceptions.ConnectionError(), []]))
    @mock.patch.object(
        workflows.WorkflowManager, 'get',
        mock.MagicMock(return_value=WF1))
    @mock.patch.object(
        workflows.WorkflowManager, 'create',
        mock.MagicMock(return_value=[WF1]))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC)))
    def test_launch_workflow_mistral_retry(self):
        MistralRunner.entry_point = mock.PropertyMock(return_value=WF1_YAML_FILE_PATH)
        execution = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.request(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'], WF1_EXEC.get('workflow_name'))

    @mock.patch.object(
        workflows.WorkflowManager, 'list',
        mock.MagicMock(return_value=[]))
    @mock.patch.object(
        workflows.WorkflowManager, 'get',
        mock.MagicMock(return_value=WF1))
    @mock.patch.object(
        workflows.WorkflowManager, 'create',
        mock.MagicMock(side_effect=[APIException(error_message='Duplicate entry.'), WF1]))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC)))
    def test_launch_workflow_duplicate_error(self):
        MistralRunner.entry_point = mock.PropertyMock(return_value=WF1_YAML_FILE_PATH)
        execution = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.request(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'], WF1_EXEC.get('workflow_name'))

    @mock.patch.object(
        workflows.WorkflowManager, 'list',
        mock.MagicMock(return_value=[]))
    @mock.patch.object(
        workflows.WorkflowManager, 'get',
        mock.MagicMock(return_value=WF1_OLD))
    @mock.patch.object(
        workflows.WorkflowManager, 'create',
        mock.MagicMock(return_value=[WF1]))
    @mock.patch.object(
        workflows.WorkflowManager, 'update',
        mock.MagicMock(return_value=[WF1]))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC)))
    def test_launch_when_workflow_definition_changed(self):
        MistralRunner.entry_point = mock.PropertyMock(return_value=WF1_YAML_FILE_PATH)
        execution = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.request(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'], WF1_EXEC.get('workflow_name'))

    @mock.patch.object(
        workflows.WorkflowManager, 'list',
        mock.MagicMock(return_value=[]))
    @mock.patch.object(
        workflows.WorkflowManager, 'get',
        mock.MagicMock(side_effect=Exception()))
    @mock.patch.object(
        workbooks.WorkbookManager, 'delete',
        mock.MagicMock(side_effect=Exception()))
    @mock.patch.object(
        workflows.WorkflowManager, 'create',
        mock.MagicMock(return_value=[WF1]))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC)))
    def test_launch_when_workflow_not_exists(self):
        execution = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.request(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'], WF1_EXEC.get('workflow_name'))

    @mock.patch.object(
        workflows.WorkflowManager, 'list',
        mock.MagicMock(return_value=[]))
    @mock.patch.object(
        workflows.WorkflowManager, 'get',
        mock.MagicMock(return_value=WF2))
    def test_launch_workflow_with_many_workflows(self):
        MistralRunner.entry_point = mock.PropertyMock(return_value=WF2_YAML_FILE_PATH)
        execution = LiveActionDB(action=WF2_NAME, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.request(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_FAILED)
        self.assertIn('Multiple workflows is not supported.', liveaction.result['message'])

    @mock.patch.object(
        workflows.WorkflowManager, 'list',
        mock.MagicMock(return_value=[]))
    @mock.patch.object(
        workflows.WorkflowManager, 'get',
        mock.MagicMock(side_effect=Exception()))
    def test_launch_workflow_name_mistmatch(self):
        action_ref = 'generic.workflow_v2_name_mismatch'
        MistralRunner.entry_point = mock.PropertyMock(return_value=WF1_YAML_FILE_PATH)
        execution = LiveActionDB(action=action_ref, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.request(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_FAILED)
        self.assertIn('Name of the workflow must be the same', liveaction.result['message'])

    @mock.patch.object(
        workflows.WorkflowManager, 'list',
        mock.MagicMock(return_value=[]))
    @mock.patch.object(
        workbooks.WorkbookManager, 'get',
        mock.MagicMock(return_value=WB1))
    @mock.patch.object(
        workbooks.WorkbookManager, 'create',
        mock.MagicMock(return_value=WB1))
    @mock.patch.object(
        workbooks.WorkbookManager, 'update',
        mock.MagicMock(return_value=WB1))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WB1_EXEC)))
    def test_launch_workbook(self):
        MistralRunner.entry_point = mock.PropertyMock(return_value=WB1_YAML_FILE_PATH)
        execution = LiveActionDB(action=WB1_NAME, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.request(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WB1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'], WB1_EXEC.get('workflow_name'))

    @mock.patch.object(
        workflows.WorkflowManager, 'list',
        mock.MagicMock(return_value=[]))
    @mock.patch.object(
        workbooks.WorkbookManager, 'get',
        mock.MagicMock(return_value=WB2))
    @mock.patch.object(
        workbooks.WorkbookManager, 'create',
        mock.MagicMock(return_value=WB2))
    @mock.patch.object(
        workbooks.WorkbookManager, 'update',
        mock.MagicMock(return_value=WB2))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WB2_EXEC)))
    def test_launch_workbook_with_many_workflows(self):
        MistralRunner.entry_point = mock.PropertyMock(return_value=WB2_YAML_FILE_PATH)
        execution = LiveActionDB(action=WB2_NAME, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.request(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WB2_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'], WB2_EXEC.get('workflow_name'))

    @mock.patch.object(
        workflows.WorkflowManager, 'list',
        mock.MagicMock(return_value=[]))
    @mock.patch.object(
        workbooks.WorkbookManager, 'get',
        mock.MagicMock(return_value=WB3))
    @mock.patch.object(
        workbooks.WorkbookManager, 'create',
        mock.MagicMock(return_value=WB3))
    @mock.patch.object(
        workbooks.WorkbookManager, 'update',
        mock.MagicMock(return_value=WB3))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WB3_EXEC)))
    def test_launch_workbook_with_many_workflows_no_default(self):
        MistralRunner.entry_point = mock.PropertyMock(return_value=WB3_YAML_FILE_PATH)
        execution = LiveActionDB(action=WB3_NAME, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.request(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_FAILED)
        self.assertIn('Default workflow cannot be determined.', liveaction.result['message'])

    @mock.patch.object(
        workflows.WorkflowManager, 'list',
        mock.MagicMock(return_value=[]))
    @mock.patch.object(
        workbooks.WorkbookManager, 'get',
        mock.MagicMock(return_value=WB1_OLD))
    @mock.patch.object(
        workbooks.WorkbookManager, 'create',
        mock.MagicMock(return_value=WB1))
    @mock.patch.object(
        workbooks.WorkbookManager, 'update',
        mock.MagicMock(return_value=WB1))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WB1_EXEC)))
    def test_launch_when_workbook_definition_changed(self):
        MistralRunner.entry_point = mock.PropertyMock(return_value=WB1_YAML_FILE_PATH)
        execution = LiveActionDB(action=WB1_NAME, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.request(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WB1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'], WB1_EXEC.get('workflow_name'))

    @mock.patch.object(
        workflows.WorkflowManager, 'list',
        mock.MagicMock(return_value=[]))
    @mock.patch.object(
        workbooks.WorkbookManager, 'get',
        mock.MagicMock(side_effect=Exception()))
    @mock.patch.object(
        workflows.WorkflowManager, 'delete',
        mock.MagicMock(side_effect=Exception()))
    @mock.patch.object(
        workbooks.WorkbookManager, 'create',
        mock.MagicMock(return_value=WB1))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WB1_EXEC)))
    def test_launch_when_workbook_not_exists(self):
        execution = LiveActionDB(action=WB1_NAME, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.request(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WB1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'], WB1_EXEC.get('workflow_name'))

    @mock.patch.object(
        workflows.WorkflowManager, 'list',
        mock.MagicMock(return_value=[]))
    @mock.patch.object(
        workbooks.WorkbookManager, 'get',
        mock.MagicMock(side_effect=Exception()))
    def test_launch_workbook_name_mismatch(self):
        action_ref = 'generic.workbook_v2_name_mismatch'
        MistralRunner.entry_point = mock.PropertyMock(return_value=WB1_YAML_FILE_PATH)
        execution = LiveActionDB(action=action_ref, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.request(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_FAILED)
        self.assertIn('Name of the workbook must be the same', liveaction.result['message'])

    @mock.patch.object(
        requests, 'request',
        mock.MagicMock(return_value=http.FakeResponse({}, 200, 'OK')))
    def test_callback_handler_with_result_as_text(self):
        MistralCallbackHandler.callback('http://localhost:8989/v2/action_executions/12345', {},
                                        action_constants.LIVEACTION_STATUS_SUCCEEDED,
                                        '<html></html>')

    @mock.patch.object(
        requests, 'request',
        mock.MagicMock(return_value=http.FakeResponse({}, 200, 'OK')))
    def test_callback_handler_with_result_as_dict(self):
        MistralCallbackHandler.callback('http://localhost:8989/v2/action_executions/12345', {},
                                        action_constants.LIVEACTION_STATUS_SUCCEEDED, {'a': 1})

    @mock.patch.object(
        requests, 'request',
        mock.MagicMock(return_value=http.FakeResponse({}, 200, 'OK')))
    def test_callback_handler_with_result_as_json_str(self):
        MistralCallbackHandler.callback('http://localhost:8989/v2/action_executions/12345', {},
                                        action_constants.LIVEACTION_STATUS_SUCCEEDED, '{"a": 1}')
        MistralCallbackHandler.callback('http://localhost:8989/v2/action_executions/12345', {},
                                        action_constants.LIVEACTION_STATUS_SUCCEEDED, "{'a': 1}")

    @mock.patch.object(
        requests, 'request',
        mock.MagicMock(return_value=http.FakeResponse({}, 200, 'OK')))
    def test_callback_handler_with_result_as_list(self):
        MistralCallbackHandler.callback('http://localhost:8989/v2/action_executions/12345', {},
                                        action_constants.LIVEACTION_STATUS_SUCCEEDED,
                                        ["a", "b", "c"])

    @mock.patch.object(
        requests, 'request',
        mock.MagicMock(return_value=http.FakeResponse({}, 200, 'OK')))
    def test_callback_handler_with_result_as_list_str(self):
        MistralCallbackHandler.callback('http://localhost:8989/v2/action_executions/12345', {},
                                        action_constants.LIVEACTION_STATUS_SUCCEEDED,
                                        '["a", "b", "c"]')

    @mock.patch.object(
        requests, 'request',
        mock.MagicMock(return_value=http.FakeResponse({}, 200, 'OK')))
    def test_callback(self):
        execution = LiveActionDB(
            action='core.local', parameters={'cmd': 'uname -a'},
            callback={
                'source': 'mistral',
                'url': 'http://localhost:8989/v2/action_executions/12345'
            }
        )

        liveaction, _ = action_service.request(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_SUCCEEDED)
        requests.request.assert_called_with('PUT', liveaction.callback['url'],
                                            data=json.dumps({'state': 'SUCCESS',
                                                             'output': NON_EMPTY_RESULT}),
                                            headers={'content-type': 'application/json'})

    def test_build_context(self):
        parent = {
            'mistral': {
                'workflow_name': 'foo',
                'workflow_execution_id': 'b222b934-7473-4cd4-a2ec-e204a8c93848',
                'task_tags': None,
                'task_name': 'some_fancy_wf_task',
                'task_id': '6c7d4334-3e7d-49c6-918d-698e846affaf',
                'action_execution_id': '24da5c88-834c-4a65-8b56-4ddbd654eb68'
            }
        }

        current = {
            'workflow_name': 'foo.subwf',
            'workflow_execution_id': '135e3446-4c89-4afe-821f-6ec6a0849b27'
        }

        context = MistralRunner._build_mistral_context(parent, current)
        self.assertTrue(context is not None)
        self.assertTrue('parent' in context['mistral'].keys())

        parent_dict = {
            'workflow_name': parent['mistral']['workflow_name'],
            'workflow_execution_id': parent['mistral']['workflow_execution_id']
        }

        self.assertDictEqual(context['mistral']['parent'], parent_dict)
        self.assertEqual(context['mistral']['workflow_execution_id'],
                         current['workflow_execution_id'])

        parent = None
        context = MistralRunner._build_mistral_context(parent, current)
        self.assertDictEqual(context['mistral'], current)
Exemple #3
0
class TestMistralRunner(DbTestCase):
    @classmethod
    def setUpClass(cls):
        super(TestMistralRunner, cls).setUpClass()
        runners_registrar.register_runner_types()
        metadata = fixture.ARTIFACTS['metadata']
        action_local = ActionAPI(**copy.deepcopy(metadata['actions']['local']))
        Action.add_or_update(ActionAPI.to_model(action_local))
        action_wkflow = ActionAPI(
            **copy.deepcopy(metadata['actions']['workflow-v2']))
        Action.add_or_update(ActionAPI.to_model(action_wkflow))

    @mock.patch.object(workbooks.WorkbookManager, 'get',
                       mock.MagicMock(return_value=WORKBOOK))
    @mock.patch.object(executions.ExecutionManager, 'create',
                       mock.MagicMock(return_value=EXECUTION))
    def test_launch_workflow(self):
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WORKFLOW_YAML)
        execution = ActionExecutionDB(action='core.workflow-v2',
                                      parameters={'friend': 'Rocky'})
        execution = action_service.schedule(execution)
        execution = ActionExecution.get_by_id(str(execution.id))
        self.assertEqual(execution.status, ACTIONEXEC_STATUS_RUNNING)

    @mock.patch.object(workbooks.WorkbookManager, 'get',
                       mock.MagicMock(return_value=WORKBOOK_OLD))
    @mock.patch.object(workbooks.WorkbookManager, 'update',
                       mock.MagicMock(return_value=WORKBOOK))
    @mock.patch.object(executions.ExecutionManager, 'create',
                       mock.MagicMock(return_value=EXECUTION))
    def test_launch_workflow_when_definition_changed(self):
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WORKFLOW_YAML)
        execution = ActionExecutionDB(action='core.workflow-v2',
                                      parameters={'friend': 'Rocky'})
        execution = action_service.schedule(execution)
        execution = ActionExecution.get_by_id(str(execution.id))
        self.assertEqual(execution.status, ACTIONEXEC_STATUS_RUNNING)

    @mock.patch.object(workbooks.WorkbookManager, 'get',
                       mock.MagicMock(return_value=Exception()))
    @mock.patch.object(workbooks.WorkbookManager, 'create',
                       mock.MagicMock(return_value=None))
    @mock.patch.object(executions.ExecutionManager, 'create',
                       mock.MagicMock(return_value=EXECUTION))
    def test_launch_workflow_when_workbook_not_exists(self):
        execution = ActionExecutionDB(action='core.workflow-v2',
                                      parameters={'friend': 'Rocky'})
        execution = action_service.schedule(execution)
        execution = ActionExecution.get_by_id(str(execution.id))
        self.assertEqual(execution.status, ACTIONEXEC_STATUS_RUNNING)

    @mock.patch.object(
        requests, 'request',
        mock.MagicMock(return_value=http.FakeResponse({}, 200, 'OK')))
    def test_callback(self):
        execution = ActionExecutionDB(
            action='core.local',
            parameters={'cmd': 'uname -a'},
            callback={
                'source': 'mistral',
                'url': 'http://localhost:8989/v2/tasks/12345'
            })
        execution = action_service.schedule(execution)
        execution = ActionExecution.get_by_id(str(execution.id))
        self.assertEqual(execution.status, ACTIONEXEC_STATUS_SUCCEEDED)
        requests.request.assert_called_with(
            'PUT',
            execution.callback['url'],
            data=json.dumps({
                'state': 'SUCCESS',
                'result': '{}'
            }),
            headers={'content-type': 'application/json'})
Exemple #4
0
class TestMistralRunner(DbTestCase):
    @classmethod
    def setUpClass(cls):
        super(TestMistralRunner, cls).setUpClass()
        runners_registrar.register_runner_types()

        for _, fixture in six.iteritems(FIXTURES['actions']):
            instance = ActionAPI(**fixture)
            Action.add_or_update(ActionAPI.to_model(instance))

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workflows.WorkflowManager, 'get',
                       mock.MagicMock(return_value=WF1))
    @mock.patch.object(workflows.WorkflowManager, 'create',
                       mock.MagicMock(return_value=[WF1]))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC)))
    def test_launch_workflow(self):
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WF1_YAML_FILE_PATH)
        execution = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.schedule(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'],
                         WF1_EXEC.get('workflow_name'))

    @mock.patch.object(
        workflows.WorkflowManager, 'list',
        mock.MagicMock(side_effect=requests.exceptions.ConnectionError()))
    def test_launch_workflow_mistral_offline(self):
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WF1_YAML_FILE_PATH)
        execution = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.schedule(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, LIVEACTION_STATUS_FAILED)
        self.assertIn('Failed to connect to mistral',
                      liveaction.result['message'])

    @mock.patch.object(
        workflows.WorkflowManager, 'list',
        mock.MagicMock(side_effect=[requests.exceptions.ConnectionError(), []])
    )
    @mock.patch.object(workflows.WorkflowManager, 'get',
                       mock.MagicMock(return_value=WF1))
    @mock.patch.object(workflows.WorkflowManager, 'create',
                       mock.MagicMock(return_value=[WF1]))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC)))
    def test_launch_workflow_mistral_retry(self):
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WF1_YAML_FILE_PATH)
        execution = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.schedule(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'],
                         WF1_EXEC.get('workflow_name'))

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workflows.WorkflowManager, 'get',
                       mock.MagicMock(return_value=WF1))
    @mock.patch.object(
        workflows.WorkflowManager, 'create',
        mock.MagicMock(
            side_effect=[APIException(error_message='Duplicate entry.'), WF1]))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC)))
    def test_launch_workflow_duplicate_error(self):
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WF1_YAML_FILE_PATH)
        execution = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.schedule(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'],
                         WF1_EXEC.get('workflow_name'))

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workflows.WorkflowManager, 'get',
                       mock.MagicMock(return_value=WF1_OLD))
    @mock.patch.object(workflows.WorkflowManager, 'create',
                       mock.MagicMock(return_value=[WF1]))
    @mock.patch.object(workflows.WorkflowManager, 'update',
                       mock.MagicMock(return_value=[WF1]))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC)))
    def test_launch_when_workflow_definition_changed(self):
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WF1_YAML_FILE_PATH)
        execution = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.schedule(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'],
                         WF1_EXEC.get('workflow_name'))

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workflows.WorkflowManager, 'get',
                       mock.MagicMock(side_effect=Exception()))
    @mock.patch.object(workbooks.WorkbookManager, 'delete',
                       mock.MagicMock(side_effect=Exception()))
    @mock.patch.object(workflows.WorkflowManager, 'create',
                       mock.MagicMock(return_value=[WF1]))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC)))
    def test_launch_when_workflow_not_exists(self):
        execution = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.schedule(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'],
                         WF1_EXEC.get('workflow_name'))

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workflows.WorkflowManager, 'get',
                       mock.MagicMock(return_value=WF2))
    def test_launch_workflow_with_many_workflows(self):
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WF2_YAML_FILE_PATH)
        execution = LiveActionDB(action=WF2_NAME, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.schedule(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, LIVEACTION_STATUS_FAILED)
        self.assertIn('Multiple workflows is not supported.',
                      liveaction.result['message'])

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workflows.WorkflowManager, 'get',
                       mock.MagicMock(side_effect=Exception()))
    def test_launch_workflow_name_mistmatch(self):
        action_ref = 'generic.workflow_v2_name_mismatch'
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WF1_YAML_FILE_PATH)
        execution = LiveActionDB(action=action_ref, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.schedule(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, LIVEACTION_STATUS_FAILED)
        self.assertIn('Name of the workflow must be the same',
                      liveaction.result['message'])

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workbooks.WorkbookManager, 'get',
                       mock.MagicMock(return_value=WB1))
    @mock.patch.object(workbooks.WorkbookManager, 'create',
                       mock.MagicMock(return_value=WB1))
    @mock.patch.object(workbooks.WorkbookManager, 'update',
                       mock.MagicMock(return_value=WB1))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WB1_EXEC)))
    def test_launch_workbook(self):
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WB1_YAML_FILE_PATH)
        execution = LiveActionDB(action=WB1_NAME, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.schedule(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WB1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'],
                         WB1_EXEC.get('workflow_name'))

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workbooks.WorkbookManager, 'get',
                       mock.MagicMock(return_value=WB2))
    @mock.patch.object(workbooks.WorkbookManager, 'create',
                       mock.MagicMock(return_value=WB2))
    @mock.patch.object(workbooks.WorkbookManager, 'update',
                       mock.MagicMock(return_value=WB2))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WB2_EXEC)))
    def test_launch_workbook_with_many_workflows(self):
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WB2_YAML_FILE_PATH)
        execution = LiveActionDB(action=WB2_NAME, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.schedule(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WB2_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'],
                         WB2_EXEC.get('workflow_name'))

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workbooks.WorkbookManager, 'get',
                       mock.MagicMock(return_value=WB3))
    @mock.patch.object(workbooks.WorkbookManager, 'create',
                       mock.MagicMock(return_value=WB3))
    @mock.patch.object(workbooks.WorkbookManager, 'update',
                       mock.MagicMock(return_value=WB3))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WB3_EXEC)))
    def test_launch_workbook_with_many_workflows_no_default(self):
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WB3_YAML_FILE_PATH)
        execution = LiveActionDB(action=WB3_NAME, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.schedule(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, LIVEACTION_STATUS_FAILED)
        self.assertIn('Default workflow cannot be determined.',
                      liveaction.result['message'])

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workbooks.WorkbookManager, 'get',
                       mock.MagicMock(return_value=WB1_OLD))
    @mock.patch.object(workbooks.WorkbookManager, 'create',
                       mock.MagicMock(return_value=WB1))
    @mock.patch.object(workbooks.WorkbookManager, 'update',
                       mock.MagicMock(return_value=WB1))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WB1_EXEC)))
    def test_launch_when_workbook_definition_changed(self):
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WB1_YAML_FILE_PATH)
        execution = LiveActionDB(action=WB1_NAME, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.schedule(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WB1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'],
                         WB1_EXEC.get('workflow_name'))

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workbooks.WorkbookManager, 'get',
                       mock.MagicMock(side_effect=Exception()))
    @mock.patch.object(workflows.WorkflowManager, 'delete',
                       mock.MagicMock(side_effect=Exception()))
    @mock.patch.object(workbooks.WorkbookManager, 'create',
                       mock.MagicMock(return_value=WB1))
    @mock.patch.object(
        executions.ExecutionManager, 'create',
        mock.MagicMock(return_value=executions.Execution(None, WB1_EXEC)))
    def test_launch_when_workbook_not_exists(self):
        execution = LiveActionDB(action=WB1_NAME, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.schedule(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, LIVEACTION_STATUS_RUNNING)

        mistral_context = liveaction.context.get('mistral', None)
        self.assertIsNotNone(mistral_context)
        self.assertEqual(mistral_context['execution_id'], WB1_EXEC.get('id'))
        self.assertEqual(mistral_context['workflow_name'],
                         WB1_EXEC.get('workflow_name'))

    @mock.patch.object(workflows.WorkflowManager, 'list',
                       mock.MagicMock(return_value=[]))
    @mock.patch.object(workbooks.WorkbookManager, 'get',
                       mock.MagicMock(side_effect=Exception()))
    def test_launch_workbook_name_mismatch(self):
        action_ref = 'generic.workbook_v2_name_mismatch'
        MistralRunner.entry_point = mock.PropertyMock(
            return_value=WB1_YAML_FILE_PATH)
        execution = LiveActionDB(action=action_ref, parameters=ACTION_PARAMS)
        liveaction, _ = action_service.schedule(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, LIVEACTION_STATUS_FAILED)
        self.assertIn('Name of the workbook must be the same',
                      liveaction.result['message'])

    @mock.patch.object(
        requests, 'request',
        mock.MagicMock(return_value=http.FakeResponse({}, 200, 'OK')))
    def test_callback_handler_with_result_as_text(self):
        MistralCallbackHandler.callback('http://localhost:8989/v2/tasks/12345',
                                        {}, LIVEACTION_STATUS_SUCCEEDED,
                                        '<html></html>')

    @mock.patch.object(
        requests, 'request',
        mock.MagicMock(return_value=http.FakeResponse({}, 200, 'OK')))
    def test_callback_handler_with_result_as_dict(self):
        MistralCallbackHandler.callback('http://localhost:8989/v2/tasks/12345',
                                        {}, LIVEACTION_STATUS_SUCCEEDED,
                                        {'a': 1})

    @mock.patch.object(
        requests, 'request',
        mock.MagicMock(return_value=http.FakeResponse({}, 200, 'OK')))
    def test_callback_handler_with_result_as_json_str(self):
        MistralCallbackHandler.callback('http://localhost:8989/v2/tasks/12345',
                                        {}, LIVEACTION_STATUS_SUCCEEDED,
                                        '{"a": 1}')
        MistralCallbackHandler.callback('http://localhost:8989/v2/tasks/12345',
                                        {}, LIVEACTION_STATUS_SUCCEEDED,
                                        "{'a': 1}")

    @mock.patch.object(
        requests, 'request',
        mock.MagicMock(return_value=http.FakeResponse({}, 200, 'OK')))
    def test_callback_handler_with_result_as_list(self):
        MistralCallbackHandler.callback('http://localhost:8989/v2/tasks/12345',
                                        {}, LIVEACTION_STATUS_SUCCEEDED,
                                        ["a", "b", "c"])

    @mock.patch.object(
        requests, 'request',
        mock.MagicMock(return_value=http.FakeResponse({}, 200, 'OK')))
    def test_callback_handler_with_result_as_list_str(self):
        MistralCallbackHandler.callback('http://localhost:8989/v2/tasks/12345',
                                        {}, LIVEACTION_STATUS_SUCCEEDED,
                                        '["a", "b", "c"]')

    @mock.patch.object(
        requests, 'request',
        mock.MagicMock(return_value=http.FakeResponse({}, 200, 'OK')))
    def test_callback(self):
        execution = LiveActionDB(action='core.local',
                                 parameters={'cmd': 'uname -a'},
                                 callback={
                                     'source': 'mistral',
                                     'url':
                                     'http://localhost:8989/v2/tasks/12345'
                                 })
        liveaction, _ = action_service.schedule(execution)
        liveaction = LiveAction.get_by_id(str(liveaction.id))
        self.assertEqual(liveaction.status, LIVEACTION_STATUS_SUCCEEDED)
        requests.request.assert_called_with(
            'PUT',
            liveaction.callback['url'],
            data=json.dumps({
                'state': 'SUCCESS',
                'result': NON_EMPTY_RESULT
            }),
            headers={'content-type': 'application/json'})

    def test_build_context(self):
        parent = {
            'mistral': {
                'workflow_name': 'foo',
                'execution_id': 'zbbjb-r87t84-bbjd',
                'task_tags': None,
                'task_name': 'some_fancy_wf_task',
                'task_id': '6c7d4334-3e7d-49c6-918d-698e846affaf'
            }
        }
        current = {
            'workflow_name': 'foo.subwf',
            'execution_id': 'cbjhv-csvhjvsh-vvshvc'
        }
        context = MistralRunner._build_mistral_context(parent, current)
        self.assertTrue(context is not None)
        self.assertTrue('parent' in context['mistral'].keys())
        parent_dict = {
            'workflow_name': parent['mistral']['workflow_name'],
            'execution_id': parent['mistral']['execution_id']
        }
        self.assertDictEqual(context['mistral']['parent'], parent_dict)
        self.assertEqual(context['mistral']['execution_id'],
                         current['execution_id'])

        parent = None
        context = MistralRunner._build_mistral_context(parent, current)
        self.assertDictEqual(context['mistral'], current)