class MistralRunnerTest(ExecutionDbTestCase): @classmethod def setUpClass(cls): super(MistralRunnerTest, cls).setUpClass() cfg.CONF.set_override('api_url', 'http://0.0.0.0:9101', group='auth') # Register runners. runnersregistrar.register_runners() # Register test pack(s). actions_registrar = actionsregistrar.ActionsRegistrar( use_pack_cache=False, fail_on_failure=True) for pack in PACKS: actions_registrar.register_from_pack(pack) @classmethod def get_runner_class(cls, runner_name): return runners.get_runner(runner_name, runner_name).__class__ 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 list(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) @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): liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS) liveaction, execution = action_service.request(liveaction) liveaction = self._wait_on_status( liveaction, 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), 'st2_action_api_url': 'http://0.0.0.0:9101/v1', '__actions': { 'st2.action': { 'st2_context': { 'api_url': 'http://0.0.0.0:9101/v1', 'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions', 'parent': { 'pack': 'mistral_tests', 'execution_id': str(execution.id) }, 'notify': {}, 'skip_notify_tasks': [] } } } } executions.ExecutionManager.create.assert_called_with( WF1_NAME, workflow_input=workflow_input, env=env, notify=NOTIFY) @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_under_parent_chain_with_jinja_params(self): ac_ctx = { 'chain': { 'params': { 'var1': 'foobar', 'var2': '{{foobar}}', 'var3': ['{{foo}}', '{{bar}}'], 'var4': { 'foobar': '{{foobar}}' }, 'var5': { 'foobar': '{% for item in items %}foobar{% end for %}' } } } } liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS, context=ac_ctx) liveaction, execution = action_service.request(liveaction) liveaction = self._wait_on_status( liveaction, 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), 'st2_action_api_url': 'http://0.0.0.0:9101/v1', '__actions': { 'st2.action': { 'st2_context': { 'api_url': 'http://0.0.0.0:9101/v1', 'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions', 'parent': { 'pack': 'mistral_tests', 'execution_id': str(execution.id), 'chain': { 'params': { 'var1': 'foobar', 'var2': '{% raw %}{{foobar}}{% endraw %}', 'var3': [ '{% raw %}{{foo}}{% endraw %}', '{% raw %}{{bar}}{% endraw %}' ], 'var4': { 'foobar': '{% raw %}{{foobar}}{% endraw %}' }, 'var5': { 'foobar': ('{% raw %}{% for item in items %}' 'foobar{% end for %}{% endraw %}') } } } }, 'notify': {}, 'skip_notify_tasks': [] } } } } executions.ExecutionManager.create.assert_called_with( WF1_NAME, workflow_input=workflow_input, env=env, notify=NOTIFY) @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_under_parent_chain_with_jinja_parameters(self): ac_ctx = { 'chain': { 'parameters': { 'var1': 'foobar', 'var2': '{{foobar}}', 'var3': ['{{foo}}', '{{bar}}'], 'var4': { 'foobar': '{{foobar}}' }, } } } liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS, context=ac_ctx) liveaction, execution = action_service.request(liveaction) liveaction = self._wait_on_status( liveaction, 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), 'st2_action_api_url': 'http://0.0.0.0:9101/v1', '__actions': { 'st2.action': { 'st2_context': { 'api_url': 'http://0.0.0.0:9101/v1', 'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions', 'parent': { 'pack': 'mistral_tests', 'execution_id': str(execution.id), 'chain': { 'parameters': { 'var1': 'foobar', 'var2': '{% raw %}{{foobar}}{% endraw %}', 'var3': [ '{% raw %}{{foo}}{% endraw %}', '{% raw %}{{bar}}{% endraw %}' ], 'var4': { 'foobar': '{% raw %}{{foobar}}{% endraw %}' } } } }, 'notify': {}, 'skip_notify_tasks': [] } } } } executions.ExecutionManager.create.assert_called_with( WF1_NAME, workflow_input=workflow_input, env=env, notify=NOTIFY) @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_under_parent_chain_with_nonetype_in_chain_context( self): ac_ctx = {'chain': None} liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS, context=ac_ctx) liveaction, execution = action_service.request(liveaction) liveaction = self._wait_on_status( liveaction, 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), 'st2_action_api_url': 'http://0.0.0.0:9101/v1', '__actions': { 'st2.action': { 'st2_context': { 'api_url': 'http://0.0.0.0:9101/v1', 'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions', 'parent': { 'pack': 'mistral_tests', 'execution_id': str(execution.id), 'chain': None }, 'notify': {}, 'skip_notify_tasks': [] } } } } executions.ExecutionManager.create.assert_called_with( WF1_NAME, workflow_input=workflow_input, env=env, notify=NOTIFY) @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_under_parent_chain_with_nonetype_in_params_context( self): ac_ctx = {'chain': {'params': None}} liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS, context=ac_ctx) liveaction, execution = action_service.request(liveaction) liveaction = self._wait_on_status( liveaction, 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), 'st2_action_api_url': 'http://0.0.0.0:9101/v1', '__actions': { 'st2.action': { 'st2_context': { 'api_url': 'http://0.0.0.0:9101/v1', 'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions', 'parent': { 'pack': 'mistral_tests', 'execution_id': str(execution.id), 'chain': { 'params': None } }, 'notify': {}, 'skip_notify_tasks': [] } } } } executions.ExecutionManager.create.assert_called_with( WF1_NAME, workflow_input=workflow_input, env=env, notify=NOTIFY) @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') liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS) liveaction, execution = action_service.request(liveaction) liveaction = self._wait_on_status( liveaction, 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), 'st2_action_api_url': 'https://0.0.0.0:9101/v1', '__actions': { 'st2.action': { 'st2_context': { 'api_url': 'https://0.0.0.0:9101/v1', 'endpoint': 'https://0.0.0.0:9101/v1/actionexecutions', 'parent': { 'pack': 'mistral_tests', 'execution_id': str(execution.id) }, 'notify': {}, 'skip_notify_tasks': [] } } } } executions.ExecutionManager.create.assert_called_with( WF1_NAME, workflow_input=workflow_input, env=env, notify=NOTIFY) @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': {} } } liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS, notify=notify_data) liveaction, execution = action_service.request(liveaction) liveaction = self._wait_on_status( liveaction, 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), 'st2_action_api_url': 'http://0.0.0.0:9101/v1', '__actions': { 'st2.action': { 'st2_context': { 'api_url': 'http://0.0.0.0:9101/v1', 'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions', 'parent': { 'pack': 'mistral_tests', '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, notify=NOTIFY) @mock.patch.object( workflows.WorkflowManager, 'list', mock.MagicMock(side_effect=requests.exceptions.ConnectionError( 'Connection refused'))) def test_launch_workflow_mistral_offline(self): liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS) liveaction, execution = action_service.request(liveaction) liveaction = self._wait_on_status( liveaction, action_constants.LIVEACTION_STATUS_FAILED) self.assertIn('Connection refused', 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): liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS) liveaction, execution = action_service.request(liveaction) liveaction = self._wait_on_status( liveaction, 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): liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS) liveaction, execution = action_service.request(liveaction) liveaction = self._wait_on_status( liveaction, 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): liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS) liveaction, execution = action_service.request(liveaction) liveaction = self._wait_on_status( liveaction, 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 = self._wait_on_status( liveaction, 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): liveaction = LiveActionDB(action=WF2_NAME, parameters=ACTION_PARAMS) liveaction, execution = action_service.request(liveaction) liveaction = self._wait_on_status( liveaction, 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 = TEST_PACK + '.workflow_v2_name_mismatch' liveaction = LiveActionDB(action=action_ref, parameters=ACTION_PARAMS) liveaction, execution = action_service.request(liveaction) liveaction = self._wait_on_status( liveaction, 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(workflows.WorkflowManager, 'get', mock.MagicMock(return_value=WF3)) @mock.patch.object(workflows.WorkflowManager, 'create', mock.MagicMock(return_value=[WF3])) @mock.patch.object( executions.ExecutionManager, 'create', mock.MagicMock(return_value=executions.Execution(None, WF3_EXEC))) def test_launch_workflow_reverse(self): # no differences for liveaction (direct == reverse) liveaction = LiveActionDB(action=WF3_NAME, parameters=ACTION_PARAMS) liveaction, execution = action_service.request(liveaction) liveaction = self._wait_on_status( liveaction, action_constants.LIVEACTION_STATUS_RUNNING) # no differences for mistral_context (direct == reverse) mistral_context = liveaction.context.get('mistral', None) self.assertIsNotNone(mistral_context) self.assertEqual(mistral_context['execution_id'], WF3_EXEC.get('id')) self.assertEqual(mistral_context['workflow_name'], WF3_EXEC.get('workflow_name')) # no differences for workflow_input (direct == reverse) workflow_input = copy.deepcopy(ACTION_PARAMS) workflow_input.update({'count': '3'}) env = { 'st2_execution_id': str(execution.id), 'st2_liveaction_id': str(liveaction.id), 'st2_action_api_url': 'http://0.0.0.0:9101/v1', '__actions': { 'st2.action': { 'st2_context': { 'api_url': 'http://0.0.0.0:9101/v1', 'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions', 'parent': { 'pack': 'mistral_tests', 'execution_id': str(execution.id) }, 'notify': {}, 'skip_notify_tasks': [] } } } } # task_name must be passed to mistral.executions.create for reverse workflows task_name = WF3_REVERSE_TARGET_TASK_NAME executions.ExecutionManager.create.assert_called_with( WF3_NAME, workflow_input=workflow_input, env=env, notify=NOTIFY, task_name=task_name) @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): liveaction = LiveActionDB(action=WB1_NAME, parameters=ACTION_PARAMS) liveaction, execution = action_service.request(liveaction) liveaction = self._wait_on_status( liveaction, 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): liveaction = LiveActionDB(action=WB2_NAME, parameters=ACTION_PARAMS) liveaction, execution = action_service.request(liveaction) liveaction = self._wait_on_status( liveaction, 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): liveaction = LiveActionDB(action=WB3_NAME, parameters=ACTION_PARAMS) liveaction, execution = action_service.request(liveaction) liveaction = self._wait_on_status( liveaction, 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): liveaction = LiveActionDB(action=WB1_NAME, parameters=ACTION_PARAMS) liveaction, execution = action_service.request(liveaction) liveaction = self._wait_on_status( liveaction, 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 = self._wait_on_status( liveaction, 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 = TEST_PACK + '.workbook_v2_name_mismatch' liveaction = LiveActionDB(action=action_ref, parameters=ACTION_PARAMS) liveaction, execution = action_service.request(liveaction) liveaction = self._wait_on_status( liveaction, action_constants.LIVEACTION_STATUS_FAILED) self.assertIn('Name of the workbook must be the same', liveaction.result['error'])
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)
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') @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), 'st2_action_api_url': 'http://0.0.0.0:9101/v1', '__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), 'st2_action_api_url': 'https://0.0.0.0:9101/v1', '__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), 'st2_action_api_url': 'http://0.0.0.0:9101/v1', '__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('Connection refused'))) 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('Connection refused', 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']) def test_callback_handler_status_map(self): # Ensure all StackStorm status are mapped otherwise leads to zombie workflow. self.assertListEqual(sorted(mistral_status_map.keys()), sorted(action_constants.LIVEACTION_STATUSES)) @mock.patch.object( action_executions.ActionExecutionManager, 'update', mock.MagicMock(return_value=None)) def test_callback_handler_with_result_as_text(self): MistralCallbackHandler.callback('http://127.0.0.1:8989/v2/action_executions/12345', {}, action_constants.LIVEACTION_STATUS_SUCCEEDED, '<html></html>') @mock.patch.object( action_executions.ActionExecutionManager, 'update', mock.MagicMock(return_value=None)) def test_callback_handler_with_result_as_dict(self): MistralCallbackHandler.callback('http://127.0.0.1:8989/v2/action_executions/12345', {}, action_constants.LIVEACTION_STATUS_SUCCEEDED, {'a': 1}) @mock.patch.object( action_executions.ActionExecutionManager, 'update', mock.MagicMock(return_value=None)) def test_callback_handler_with_result_as_json_str(self): MistralCallbackHandler.callback('http://127.0.0.1:8989/v2/action_executions/12345', {}, action_constants.LIVEACTION_STATUS_SUCCEEDED, '{"a": 1}') MistralCallbackHandler.callback('http://127.0.0.1:8989/v2/action_executions/12345', {}, action_constants.LIVEACTION_STATUS_SUCCEEDED, "{'a': 1}") @mock.patch.object( action_executions.ActionExecutionManager, 'update', mock.MagicMock(return_value=None)) def test_callback_handler_with_result_as_list(self): MistralCallbackHandler.callback('http://127.0.0.1:8989/v2/action_executions/12345', {}, action_constants.LIVEACTION_STATUS_SUCCEEDED, ["a", "b", "c"]) @mock.patch.object( action_executions.ActionExecutionManager, 'update', mock.MagicMock(return_value=None)) def test_callback_handler_with_result_as_list_str(self): MistralCallbackHandler.callback('http://127.0.0.1:8989/v2/action_executions/12345', {}, action_constants.LIVEACTION_STATUS_SUCCEEDED, '["a", "b", "c"]') @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://127.0.0.1:8989/v2/action_executions/12345' } ) for status in action_constants.LIVEACTION_COMPLETED_STATES: expected_mistral_status = mistral_status_map[status] LocalShellRunner.run = mock.Mock(return_value=(status, NON_EMPTY_RESULT, None)) liveaction, execution = action_service.request(liveaction) liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, status) action_executions.ActionExecutionManager.update.assert_called_with( '12345', state=expected_mistral_status, output=NON_EMPTY_RESULT) @mock.patch.object( LocalShellRunner, 'run', mock.MagicMock(return_value=(action_constants.LIVEACTION_STATUS_RUNNING, NON_EMPTY_RESULT, None))) @mock.patch.object( action_executions.ActionExecutionManager, 'update', mock.MagicMock(return_value=None)) def test_callback_incomplete_state(self): liveaction = LiveActionDB( action='core.local', parameters={'cmd': 'uname -a'}, callback={ 'source': 'mistral', 'url': 'http://127.0.0.1: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_RUNNING) self.assertFalse(action_executions.ActionExecutionManager.update.called) @mock.patch.object( LocalShellRunner, 'run', mock.MagicMock(return_value=(action_constants.LIVEACTION_STATUS_SUCCEEDED, NON_EMPTY_RESULT, None))) @mock.patch.object( action_executions.ActionExecutionManager, 'update', mock.MagicMock(side_effect=[ requests.exceptions.ConnectionError(), None])) def test_callback_retry(self): liveaction = LiveActionDB( action='core.local', parameters={'cmd': 'uname -a'}, callback={ 'source': 'mistral', 'url': 'http://127.0.0.1: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) calls = [call('12345', state='SUCCESS', output=NON_EMPTY_RESULT) for i in range(0, 2)] action_executions.ActionExecutionManager.update.assert_has_calls(calls) @mock.patch.object( LocalShellRunner, 'run', mock.MagicMock(return_value=(action_constants.LIVEACTION_STATUS_SUCCEEDED, NON_EMPTY_RESULT, None))) @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): liveaction = LiveActionDB( action='core.local', parameters={'cmd': 'uname -a'}, callback={ 'source': 'mistral', 'url': 'http://127.0.0.1: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) # This test initially setup mock for action_executions.ActionExecutionManager.update # to fail the first 4 times and return success on the 5th times. The max attempts # is set to 3. We expect only 3 calls to pass thru the update method. calls = [call('12345', state='SUCCESS', output=NON_EMPTY_RESULT) for i in range(0, 2)] action_executions.ActionExecutionManager.update.assert_has_calls(calls) @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) @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(side_effect=[requests.exceptions.ConnectionError(), executions.Execution(None, WF1_EXEC_PAUSED)])) def test_cancel_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')) 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) @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(side_effect=requests.exceptions.ConnectionError('Connection refused'))) def test_cancel_retry_exhausted(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) calls = [call(WF1_EXEC.get('id'), 'PAUSED') for i in range(0, 2)] executions.ExecutionManager.update.assert_has_calls(calls) liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_CANCELING) 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)
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)