def test_list(self): self.requests_mock.get(self.TEST_URL + URL_TEMPLATE, json={'executions': [EXEC, SUB_WF_EXEC]}) execution_list = self.executions.list() self.assertEqual(2, len(execution_list)) self.assertDictEqual( executions.Execution(self.executions, EXEC).to_dict(), execution_list[0].to_dict()) self.assertDictEqual( executions.Execution(self.executions, SUB_WF_EXEC).to_dict(), execution_list[1].to_dict())
def test_update_state(self): states = ['RUNNING', 'SUCCESS', 'PAUSED', 'ERROR', 'CANCELLED'] for state in states: self.client.executions.update.return_value = executions.Execution( mock, { 'id': '123', 'workflow_id': '123e4567-e89b-12d3-a456-426655440000', 'workflow_name': 'some', 'workflow_namespace': '', 'root_execution_id': '', 'description': '', 'state': state, 'state_info': None, 'created_at': '2020-02-07 08:10:32', 'updated_at': '2020-02-07 08:10:41', 'task_execution_id': None }) ex_result = list(EX_RESULT) ex_result[7] = state # We'll ignore "duration" since for not terminal states # it is unpredictable. del ex_result[11] ex_result = tuple(ex_result) result = self.call(execution_cmd.Update, app_args=['id', '-s', state]) result_ex = list(result[1]) del result_ex[11] result_ex = tuple(result_ex) self.assertEqual(ex_result, result_ex)
def test_update_state(self): states = ['RUNNING', 'SUCCESS', 'PAUSED', 'ERROR', 'CANCELLED'] for state in states: self.client.executions.update.return_value = executions.Execution( mock, { 'id': '123', 'workflow_id': '123e4567-e89b-12d3-a456-426655440000', 'workflow_name': 'some', 'description': '', 'state': state, 'state_info': None, 'created_at': '1', 'updated_at': '1', 'task_execution_id': None }) ex_result = list(EX_RESULT) ex_result[5] = state ex_result = tuple(ex_result) result = self.call(execution_cmd.Update, app_args=['id', '-s', state]) self.assertEqual(ex_result, result[1])
def test_create(self): self.requests_mock.post(self.TEST_URL + URL_TEMPLATE, json=EXEC, status_code=201) body = { 'workflow_name': EXEC['workflow_name'], 'description': '', 'input': jsonutils.dumps(EXEC['input']) } ex = self.executions.create( EXEC['workflow_name'], EXEC['workflow_namespace'], EXEC['input'] ) self.assertIsNotNone(ex) self.assertDictEqual( executions.Execution(self.executions, EXEC).to_dict(), ex.to_dict() ) self.assertDictEqual(body, self.requests_mock.last_request.json())
def test_get(self): mock = self.mock_http_get(content=EXEC) ex = self.executions.get(EXEC['id']) self.assertEqual(executions.Execution(self.executions, EXEC).to_dict(), ex.to_dict()) mock.assert_called_once_with(URL_TEMPLATE_ID % EXEC['id'])
def test_get_sub_executions(self): url = self.TEST_URL + URL_TEMPLATE_SUB_EXECUTIONS \ % (EXEC['id'], '?max_depth=-1&errors_only=') self.requests_mock.get(url, json={'executions': [EXEC, SUB_WF_EXEC]}) sub_execution_list = self.executions.get_ex_sub_executions(EXEC['id']) self.assertEqual(2, len(sub_execution_list)) self.assertDictEqual( executions.Execution(self.executions, EXEC).to_dict(), sub_execution_list[0].to_dict() ) self.assertDictEqual( executions.Execution(self.executions, SUB_WF_EXEC).to_dict(), sub_execution_list[1].to_dict() )
def test_get(self): url = self.TEST_URL + URL_TEMPLATE_ID % EXEC['id'] self.requests_mock.get(url, json=EXEC) ex = self.executions.get(EXEC['id']) self.assertDictEqual( executions.Execution(self.executions, EXEC).to_dict(), ex.to_dict())
def test_get_sub_wf_ex(self): url = self.TEST_URL + URL_TEMPLATE_ID % SUB_WF_EXEC['id'] self.requests_mock.get(url, json=SUB_WF_EXEC) ex = self.executions.get(SUB_WF_EXEC['id']) self.assertDictEqual( executions.Execution(self.executions, SUB_WF_EXEC).to_dict(), ex.to_dict())
def test_list(self): mock = self.mock_http_get(content={'executions': [EXEC]}) execution_list = self.executions.list() self.assertEqual(1, len(execution_list)) ex = execution_list[0] self.assertEqual(executions.Execution(self.executions, EXEC).to_dict(), ex.to_dict()) mock.assert_called_once_with(URL_TEMPLATE)
def test_update(self): mock = self.mock_http_put(content=EXEC) body = { 'state': EXEC['state'] } ex = self.executions.update(EXEC['id'], EXEC['state']) self.assertIsNotNone(ex) self.assertEqual(executions.Execution(self.executions, EXEC).to_dict(), ex.to_dict()) mock.assert_called_once_with( URL_TEMPLATE_ID % EXEC['id'], json.dumps(body))
def test_update(self): url = self.TEST_URL + URL_TEMPLATE_ID % EXEC['id'] self.requests_mock.put(url, json=EXEC) body = {'state': EXEC['state']} ex = self.executions.update(EXEC['id'], EXEC['state']) self.assertIsNotNone(ex) self.assertDictEqual( executions.Execution(self.executions, EXEC).to_dict(), ex.to_dict()) self.assertDictEqual(body, self.requests_mock.last_request.json())
def test_create(self): mock = self.mock_http_post(content=EXEC) body = { 'workflow_name': EXEC['workflow_name'], 'description': '', 'input': json.dumps(EXEC['input']), } ex = self.executions.create(EXEC['workflow_name'], EXEC['input']) self.assertIsNotNone(ex) self.assertEqual(executions.Execution(self.executions, EXEC).to_dict(), ex.to_dict()) mock.assert_called_once_with(URL_TEMPLATE, json.dumps(body))
def test_create_with_source_execution_id(self): self.requests_mock.post(self.TEST_URL + URL_TEMPLATE, json=SOURCE_EXEC, status_code=201) body = { 'description': '', 'source_execution_id': SOURCE_EXEC['source_execution_id'] } ex = self.executions.create( source_execution_id=SOURCE_EXEC['source_execution_id']) self.assertIsNotNone(ex) self.assertDictEqual( executions.Execution(self.executions, SOURCE_EXEC).to_dict(), ex.to_dict()) self.assertDictEqual(body, self.requests_mock.last_request.json())
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))) @mock.patch.object( MistralRunner, 'resume', mock.MagicMock( return_value=(action_constants.LIVEACTION_STATUS_RUNNING, { 'tasks': [] }, { 'execution_id': str(uuid.uuid4()) }))) def test_resume_option(self): MistralRunner.entry_point = mock.PropertyMock( return_value=WF1_YAML_FILE_PATH) liveaction1 = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS) liveaction1, execution1 = action_service.request(liveaction1) self.assertFalse(MistralRunner.resume.called) # Rerun the execution. context = {'re-run': {'ref': execution1.id, 'tasks': ['x']}} liveaction2 = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS, context=context) liveaction2, execution2 = action_service.request(liveaction2) liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_RUNNING) task_specs = {'x': {'reset': False}} MistralRunner.resume.assert_called_with(ex_ref=execution1, task_specs=task_specs) @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( MistralRunner, 'resume', mock.MagicMock( return_value=(action_constants.LIVEACTION_STATUS_RUNNING, { 'tasks': [] }, { 'execution_id': str(uuid.uuid4()) }))) def test_resume_option_reset_tasks(self): MistralRunner.entry_point = mock.PropertyMock( return_value=WF1_YAML_FILE_PATH) liveaction1 = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS) liveaction1, execution1 = action_service.request(liveaction1) self.assertFalse(MistralRunner.resume.called) # Rerun the execution. context = { 're-run': { 'ref': execution1.id, 'tasks': ['x', 'y'], 'reset': ['y'] } } liveaction2 = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS, context=context) liveaction2, execution2 = action_service.request(liveaction2) liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_RUNNING) task_specs = {'x': {'reset': False}, 'y': {'reset': True}} MistralRunner.resume.assert_called_with(ex_ref=execution1, task_specs=task_specs) @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_NOT_RERUNABLE))) @mock.patch.object( executions.ExecutionManager, 'get', mock.MagicMock( return_value=executions.Execution(None, WF1_EXEC_NOT_RERUNABLE))) @mock.patch.object(tasks.TaskManager, 'list', mock.MagicMock(return_value=WF1_TASKS)) def test_resume_workflow_not_in_rerunable_state(self): MistralRunner.entry_point = mock.PropertyMock( return_value=WF1_YAML_FILE_PATH) liveaction1 = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS) liveaction1, execution1 = action_service.request(liveaction1) # Rerun the execution. context = {'re-run': {'ref': execution1.id, 'tasks': ['say-friend']}} liveaction2 = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS, context=context) liveaction2, execution2 = action_service.request(liveaction2) liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_FAILED) self.assertIn('not in a rerunable state', liveaction2.result.get('error')) @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, 'list', mock.MagicMock(return_value=[executions.Execution(None, WF1_EXEC)])) @mock.patch.object( executions.ExecutionManager, 'create', mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC))) @mock.patch.object( executions.ExecutionManager, 'get', mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC))) @mock.patch.object(tasks.TaskManager, 'list', mock.MagicMock(return_value=WF1_TASKS)) def test_resume_tasks_not_in_rerunable_state(self): MistralRunner.entry_point = mock.PropertyMock( return_value=WF1_YAML_FILE_PATH) liveaction1 = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS) liveaction1, execution1 = action_service.request(liveaction1) # Rerun the execution. context = {'re-run': {'ref': execution1.id, 'tasks': ['say-friend']}} liveaction2 = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS, context=context) liveaction2, execution2 = action_service.request(liveaction2) liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_FAILED) self.assertIn('Unable to identify rerunable', liveaction2.result.get('error')) @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, 'list', mock.MagicMock(return_value=[executions.Execution(None, WF1_EXEC)])) @mock.patch.object( executions.ExecutionManager, 'create', mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC))) @mock.patch.object( executions.ExecutionManager, 'get', mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC))) @mock.patch.object(tasks.TaskManager, 'list', mock.MagicMock(return_value=WF1_TASKS)) def test_resume_unidentified_tasks(self): MistralRunner.entry_point = mock.PropertyMock( return_value=WF1_YAML_FILE_PATH) liveaction1 = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS) liveaction1, execution1 = action_service.request(liveaction1) # Rerun the execution. context = {'re-run': {'ref': execution1.id, 'tasks': ['x']}} liveaction2 = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS, context=context) liveaction2, execution2 = action_service.request(liveaction2) liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_FAILED) self.assertIn('Unable to identify', liveaction2.result.get('error')) @mock.patch.object(workflows.WorkflowManager, 'list', mock.MagicMock(return_value=[])) @mock.patch.object(workflows.WorkflowManager, 'get', mock.MagicMock(return_value=WF1)) @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_MAIN_EXEC))) @mock.patch.object( executions.ExecutionManager, 'get', mock.MagicMock( return_value=executions.Execution(None, WB1_MAIN_EXEC_ERRORED))) @mock.patch.object(executions.ExecutionManager, 'list', mock.MagicMock(return_value=[ executions.Execution(None, WB1_MAIN_EXEC_ERRORED), executions.Execution(None, WB1_SUB1_EXEC_ERRORED) ])) @mock.patch.object( tasks.TaskManager, 'list', mock.MagicMock(side_effect=[WB1_MAIN_TASKS, WB1_SUB1_TASKS])) @mock.patch.object(tasks.TaskManager, 'rerun', mock.MagicMock(return_value=None)) def test_resume_subworkflow_task(self): MistralRunner.entry_point = mock.PropertyMock( return_value=WB1_YAML_FILE_PATH) liveaction1 = LiveActionDB(action=WB1_NAME, parameters=ACTION_PARAMS) liveaction1, execution1 = action_service.request(liveaction1) # Rerun the execution. context = { 're-run': { 'ref': execution1.id, 'tasks': ['greet.say-friend'] } } liveaction2 = LiveActionDB(action=WB1_NAME, parameters=ACTION_PARAMS, context=context) liveaction2, execution2 = action_service.request(liveaction2) liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_RUNNING) expected_env = { 'st2_liveaction_id': str(liveaction2.id), 'st2_execution_id': str(execution2.id), '__actions': { 'st2.action': { 'st2_context': { 'api_url': 'http://0.0.0.0:9101/v1', 'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions', 'notify': {}, 'parent': { 're-run': context['re-run'], 'execution_id': str(execution2.id) }, 'skip_notify_tasks': [] } } }, 'st2_action_api_url': 'http://0.0.0.0:9101/v1' } tasks.TaskManager.rerun.assert_called_with(WB1_SUB1_TASK2['id'], reset=False, env=expected_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(workbooks.WorkbookManager, 'create', mock.MagicMock(return_value=WB1)) @mock.patch.object( executions.ExecutionManager, 'create', mock.MagicMock(return_value=executions.Execution(None, WB1_MAIN_EXEC))) @mock.patch.object( executions.ExecutionManager, 'get', mock.MagicMock( return_value=executions.Execution(None, WB1_MAIN_EXEC_ERRORED))) @mock.patch.object(executions.ExecutionManager, 'list', mock.MagicMock(return_value=[ executions.Execution(None, WB1_MAIN_EXEC_ERRORED), executions.Execution(None, WB1_SUB1_EXEC_ERRORED) ])) @mock.patch.object( tasks.TaskManager, 'list', mock.MagicMock(side_effect=[WB1_MAIN_TASKS, WB1_SUB1_TASKS])) def test_resume_unidentified_subworkflow_task(self): MistralRunner.entry_point = mock.PropertyMock( return_value=WB1_YAML_FILE_PATH) liveaction1 = LiveActionDB(action=WB1_NAME, parameters=ACTION_PARAMS) liveaction1, execution1 = action_service.request(liveaction1) # Rerun the execution. context = {'re-run': {'ref': execution1.id, 'tasks': ['greet.x']}} liveaction2 = LiveActionDB(action=WB1_NAME, parameters=ACTION_PARAMS, context=context) liveaction2, execution2 = action_service.request(liveaction2) liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_FAILED) self.assertIn('Unable to identify', liveaction2.result.get('error')) @mock.patch.object(workflows.WorkflowManager, 'list', mock.MagicMock(return_value=[])) @mock.patch.object(workflows.WorkflowManager, 'get', mock.MagicMock(return_value=WF1)) @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_MAIN_EXEC))) @mock.patch.object( executions.ExecutionManager, 'get', mock.MagicMock( return_value=executions.Execution(None, WB1_MAIN_EXEC_ERRORED))) @mock.patch.object(executions.ExecutionManager, 'list', mock.MagicMock(return_value=[ executions.Execution(None, WB1_MAIN_EXEC_ERRORED), executions.Execution(None, WB1_SUB1_EXEC_ERRORED) ])) @mock.patch.object( tasks.TaskManager, 'list', mock.MagicMock(side_effect=[WB1_MAIN_TASKS, WB1_SUB1_TASKS])) @mock.patch.object(tasks.TaskManager, 'rerun', mock.MagicMock(return_value=None)) def test_resume_and_reset_subworkflow_task(self): MistralRunner.entry_point = mock.PropertyMock( return_value=WB1_YAML_FILE_PATH) liveaction1 = LiveActionDB(action=WB1_NAME, parameters=ACTION_PARAMS) liveaction1, execution1 = action_service.request(liveaction1) # Rerun the execution. context = { 're-run': { 'ref': execution1.id, 'tasks': ['greet.say-friend'], 'reset': ['greet.say-friend'] } } liveaction2 = LiveActionDB(action=WB1_NAME, parameters=ACTION_PARAMS, context=context) liveaction2, execution2 = action_service.request(liveaction2) liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_RUNNING) expected_env = { 'st2_liveaction_id': str(liveaction2.id), 'st2_execution_id': str(execution2.id), '__actions': { 'st2.action': { 'st2_context': { 'api_url': 'http://0.0.0.0:9101/v1', 'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions', 'notify': {}, 'parent': { 're-run': context['re-run'], 'execution_id': str(execution2.id) }, 'skip_notify_tasks': [] } } }, 'st2_action_api_url': 'http://0.0.0.0:9101/v1' } tasks.TaskManager.rerun.assert_called_with(WB1_SUB1_TASK2['id'], reset=True, env=expected_env)
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'])
EXEC_DICT = { 'id': '123', 'workflow_id': '123e4567-e89b-12d3-a456-426655440000', 'workflow_name': 'some', 'workflow_namespace': '', 'root_execution_id': '', 'description': '', 'state': 'RUNNING', 'state_info': None, 'created_at': '1', 'updated_at': '1', 'task_execution_id': None } EXEC = executions.Execution(mock, EXEC_DICT) SUB_WF_EXEC = executions.Execution( mock, { 'id': '456', 'workflow_id': '123e4567-e89b-12d3-a456-426655440000', 'workflow_name': 'some_sub_wf', 'workflow_namespace': '', 'root_execution_id': 'ROOT_EXECUTION_ID', 'description': '', 'state': 'RUNNING', 'state_info': None, 'created_at': '1', 'updated_at': '1', 'task_execution_id': 'abc' })
class MistralRunnerCancelTest(DbTestCase): @classmethod def setUpClass(cls): super(MistralRunnerCancelTest, cls).setUpClass() # Override the retry configuration here otherwise st2tests.config.parse_args # in DbTestCase.setUpClass will reset these overrides. cfg.CONF.set_override('retry_exp_msec', 100, group='mistral') cfg.CONF.set_override('retry_exp_max_msec', 200, group='mistral') cfg.CONF.set_override('retry_stop_max_msec', 200, group='mistral') 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).__class__ @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_CANCELLED))) def test_cancel(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')) requester = cfg.CONF.system_user.user liveaction, execution = action_service.request_cancellation( liveaction, requester) executions.ExecutionManager.update.assert_called_with( WF1_EXEC.get('id'), 'CANCELLED') liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_CANCELING) @mock.patch.object(workflows.WorkflowManager, 'list', mock.MagicMock(return_value=[])) @mock.patch.object(workflows.WorkflowManager, 'get', mock.MagicMock(side_effect=[WF2, WF1])) @mock.patch.object(workflows.WorkflowManager, 'create', mock.MagicMock(side_effect=[[WF2], [WF1]])) @mock.patch.object(executions.ExecutionManager, 'create', mock.MagicMock(side_effect=[ executions.Execution(None, WF2_EXEC), executions.Execution(None, WF1_EXEC) ])) @mock.patch.object(executions.ExecutionManager, 'update', mock.MagicMock(side_effect=[ executions.Execution(None, WF2_EXEC_CANCELLED), executions.Execution(None, WF1_EXEC_CANCELLED) ])) def test_cancel_subworkflow_action(self): liveaction1 = LiveActionDB(action=WF2_NAME, parameters=ACTION_PARAMS) liveaction1, execution1 = action_service.request(liveaction1) liveaction1 = LiveAction.get_by_id(str(liveaction1.id)) self.assertEqual(liveaction1.status, action_constants.LIVEACTION_STATUS_RUNNING) liveaction2 = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS) liveaction2, execution2 = action_service.request(liveaction2) liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_RUNNING) # Mock the children of the parent execution to make this # test case has subworkflow execution. with mock.patch.object( ActionExecutionDB, 'children', new_callable=mock.PropertyMock) as action_ex_children_mock: action_ex_children_mock.return_value = [execution2.id] mistral_context = liveaction1.context.get('mistral', None) self.assertIsNotNone(mistral_context) self.assertEqual(mistral_context['execution_id'], WF2_EXEC.get('id')) self.assertEqual(mistral_context['workflow_name'], WF2_EXEC.get('workflow_name')) requester = cfg.CONF.system_user.user liveaction1, execution1 = action_service.request_cancellation( liveaction1, requester) self.assertTrue(executions.ExecutionManager.update.called) self.assertEqual(executions.ExecutionManager.update.call_count, 2) calls = [ mock.call(WF2_EXEC.get('id'), 'CANCELLED'), mock.call(WF1_EXEC.get('id'), 'CANCELLED') ] executions.ExecutionManager.update.assert_has_calls( calls, any_order=False) @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_CANCELLED) ])) def test_cancel_retry(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')) requester = cfg.CONF.system_user.user liveaction, execution = action_service.request_cancellation( liveaction, requester) executions.ExecutionManager.update.assert_called_with( WF1_EXEC.get('id'), 'CANCELLED') liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_CANCELING) @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): 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'), 'CANCELLED') 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)
class MistralRunnerPolicyTest(DbTestCase): @classmethod def setUpClass(cls): super(MistralRunnerPolicyTest, cls).setUpClass() # Override the retry configuration here otherwise st2tests.config.parse_args # in DbTestCase.setUpClass will reset these overrides. cfg.CONF.set_override('retry_exp_msec', 100, group='mistral') cfg.CONF.set_override('retry_exp_max_msec', 200, group='mistral') cfg.CONF.set_override('retry_stop_max_msec', 200, group='mistral') cfg.CONF.set_override('api_url', 'http://0.0.0.0:9101', group='auth') def setUp(self): super(MistralRunnerPolicyTest, self).setUp() # Start with a clean database for each test. self._establish_connection_and_re_create_db() # Register runners. runnersregistrar.register_runners() actions_registrar = actionsregistrar.ActionsRegistrar( use_pack_cache=False, fail_on_failure=True) for pack in PACKS: actions_registrar.register_from_pack(pack) # Register policies required for the tests. policiesregistrar.register_policy_types(st2common) policies_registrar = policiesregistrar.PolicyRegistrar( use_pack_cache=False, fail_on_failure=True) for pack in PACKS: policies_registrar.register_from_pack(pack) @classmethod def get_runner_class(cls, runner_name): return runners.get_runner(runner_name).__class__ def _drop_all_other_policies(self, test_policy): policy_dbs = [ policy_db for policy_db in Policy.get_all() if policy_db.ref != test_policy ] for policy_db in policy_dbs: Policy.delete(policy_db, publish=False) @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(action_executions.ActionExecutionManager, 'update', mock.MagicMock(return_value=None)) def test_cancel_on_task_action_concurrency(self): # Delete other policies in the test pack to avoid conflicts. required_policy = 'mistral_tests.cancel_on_concurrency' self._drop_all_other_policies(required_policy) # Get threshold from the policy. policy = Policy.get_by_ref(required_policy) threshold = policy.parameters.get('threshold', 0) self.assertGreater(threshold, 0) # Launch instances of the workflow up to threshold. for i in range(0, threshold): liveaction = LiveActionDB(action=WF1_NAME, parameters={'friend': 'friend' + str(i)}) liveaction, execution1 = action_service.request(liveaction) liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING) # Check number of running instances running = LiveAction.count( action=WF1_NAME, status=action_constants.LIVEACTION_STATUS_RUNNING) self.assertEqual(running, threshold) # Mock the mistral runner cancel method to assert cancel is called. mistral_runner_cls = self.get_runner_class('mistral_v2') with mock.patch.object(mistral_runner_cls, 'cancel', mock.MagicMock(return_value=None)): # Launch another instance of the workflow with mistral callback defined # to indicate that this is executed under a workflow. callback = { 'source': MISTRAL_RUNNER_NAME, 'url': 'http://127.0.0.1:8989/v2/action_executions/12345' } params = {'friend': 'grande animalerie'} liveaction2 = LiveActionDB(action=WF1_NAME, parameters=params, callback=callback) liveaction2, execution2 = action_service.request(liveaction2) action_executions.ActionExecutionManager.update.assert_called_once_with( '12345', output='{"error": "Execution canceled by user."}', state='CANCELLED') liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_CANCELED) # Assert cancel has been called. mistral_runner_cls.cancel.assert_called_once_with() @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(action_executions.ActionExecutionManager, 'update', mock.MagicMock(return_value=None)) def test_cancel_on_task_action_concurrency_by_attr(self): # Delete other policies in the test pack to avoid conflicts. required_policy = 'mistral_tests.cancel_on_concurrency_by_attr' self._drop_all_other_policies(required_policy) # Get threshold from the policy. policy = Policy.get_by_ref(required_policy) threshold = policy.parameters.get('threshold', 0) self.assertGreater(threshold, 0) params = {'friend': 'grande animalerie'} # Launch instances of the workflow up to threshold. for i in range(0, threshold): liveaction = LiveActionDB(action=WF1_NAME, parameters=params) liveaction, execution1 = action_service.request(liveaction) liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING) # Check number of running instances running = LiveAction.count( action=WF1_NAME, status=action_constants.LIVEACTION_STATUS_RUNNING, parameters__friend=params['friend']) self.assertEqual(running, threshold) # Mock the mistral runner cancel method to assert cancel is called. mistral_runner_cls = self.get_runner_class('mistral_v2') with mock.patch.object(mistral_runner_cls, 'cancel', mock.MagicMock(return_value=None)): # Launch another instance of the workflow with mistral callback defined # to indicate that this is executed under a workflow. callback = { 'source': MISTRAL_RUNNER_NAME, 'url': 'http://127.0.0.1:8989/v2/action_executions/12345' } liveaction2 = LiveActionDB(action=WF1_NAME, parameters=params, callback=callback) liveaction2, execution2 = action_service.request(liveaction2) action_executions.ActionExecutionManager.update.assert_called_once_with( '12345', output='{"error": "Execution canceled by user."}', state='CANCELLED') liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_CANCELED) # Assert cancel has been called. mistral_runner_cls.cancel.assert_called_once_with()
import mock import pkg_resources as pkg import six import sys from mistralclient.api.v2 import executions from mistralclient.commands.v2 import executions as execution_cmd from mistralclient.tests.unit import base EXEC = executions.Execution( mock, { 'id': '123', 'workflow_id': '123e4567-e89b-12d3-a456-426655440000', 'workflow_name': 'some', 'description': '', 'state': 'RUNNING', 'state_info': None, 'created_at': '1', 'updated_at': '1', 'task_execution_id': None }) SUB_WF_EXEC = executions.Execution( mock, { 'id': '456', 'workflow_id': '123e4567-e89b-12d3-a456-426655440000', 'workflow_name': 'some_sub_wf', 'description': '', 'state': 'RUNNING', 'state_info': None, 'created_at': '1',
class MistralAuthTest(DbTestCase): @classmethod def setUpClass(cls): super(MistralAuthTest, cls).setUpClass() # Override the retry configuration here otherwise st2tests.config.parse_args # in DbTestCase.setUpClass will reset these overrides. cfg.CONF.set_override('retry_exp_msec', 100, group='mistral') cfg.CONF.set_override('retry_exp_max_msec', 200, group='mistral') cfg.CONF.set_override('retry_stop_max_msec', 200, group='mistral') # Register runners. runners_registrar.register_runners() # Register test pack(s). registrar = actionsregistrar.ActionsRegistrar( use_pack_cache=False, fail_on_failure=True ) for pack in PACKS: registrar.register_from_pack(pack) def setUp(self): super(MistralAuthTest, self).setUp() cfg.CONF.set_override('api_url', 'http://0.0.0.0:9101', group='auth') # Mock the local runner run method. local_runner_cls = self.get_runner_class('local_runner') local_run_result = (action_constants.LIVEACTION_STATUS_SUCCEEDED, NON_EMPTY_RESULT, None) local_runner_cls.run = mock.Mock(return_value=local_run_result) @classmethod def get_runner_class(cls, runner_name): return runners.get_runner(runner_name).__class__ def tearDown(self): super(MistralAuthTest, self).tearDown() cfg.CONF.set_default('keystone_username', None, group='mistral') cfg.CONF.set_default('keystone_password', None, group='mistral') cfg.CONF.set_default('keystone_project_name', None, group='mistral') cfg.CONF.set_default('keystone_auth_url', None, 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))) @mock.patch.object( access_service, 'create_token', mock.MagicMock(return_value=TOKEN_DB)) def test_launch_workflow_with_st2_auth(self): liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS, context=ACTION_CONTEXT) 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': { 'auth_token': TOKEN_DB.token, 'api_url': 'http://0.0.0.0:9101/v1', 'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions', 'parent': { 'user': liveaction.context['user'], '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( client.Client, 'authenticate', mock.MagicMock(return_value=(cfg.CONF.mistral.v2_base_url, '123', 'abc', 'xyz'))) @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_mistral_auth(self): cfg.CONF.set_default('keystone_username', 'foo', group='mistral') cfg.CONF.set_default('keystone_password', 'bar', group='mistral') cfg.CONF.set_default('keystone_project_name', 'admin', group='mistral') cfg.CONF.set_default('keystone_auth_url', 'http://127.0.0.1:5000/v3', group='mistral') 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': { 'api_url': 'http://0.0.0.0:9101/v1', 'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions', 'parent': { 'execution_id': str(execution.id) }, 'notify': {}, 'skip_notify_tasks': [] } } } } client.Client.authenticate.assert_called_with( cfg.CONF.mistral.v2_base_url, cfg.CONF.mistral.keystone_username, cfg.CONF.mistral.keystone_password, cfg.CONF.mistral.keystone_project_name, cfg.CONF.mistral.keystone_auth_url, None, 'publicURL', 'workflow', None, None, None, False) executions.ExecutionManager.create.assert_called_with( WF1_NAME, workflow_input=workflow_input, env=env)
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() # Override the retry configuration here otherwise st2tests.config.parse_args # in DbTestCase.setUpClass will reset these overrides. cfg.CONF.set_override('retry_exp_msec', 100, group='mistral') cfg.CONF.set_override('retry_exp_max_msec', 200, group='mistral') cfg.CONF.set_override('retry_stop_max_msec', 200, group='mistral') 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) def setUp(self): super(MistralRunnerTest, self).setUp() # Mock the local runner run method. local_runner_cls = self.get_runner_class('local_runner') local_run_result = (action_constants.LIVEACTION_STATUS_SUCCEEDED, NON_EMPTY_RESULT, None) local_runner_cls.run = mock.Mock(return_value=local_run_result) @classmethod def get_runner_class(cls, runner_name): return runners.get_runner(runner_name).__class__ @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_resume_option(self): patched_mistral_runner = self.get_runner_class('mistral_v2') mock_resume_result = (action_constants.LIVEACTION_STATUS_RUNNING, { 'tasks': [] }, { 'execution_id': str(uuid.uuid4()) }) with mock.patch.object( patched_mistral_runner, 'resume', mock.MagicMock(return_value=mock_resume_result)): liveaction1 = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS) liveaction1, execution1 = action_service.request(liveaction1) self.assertFalse(patched_mistral_runner.resume.called) # Rerun the execution. context = {'re-run': {'ref': execution1.id, 'tasks': ['x']}} liveaction2 = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS, context=context) liveaction2, execution2 = action_service.request(liveaction2) liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_RUNNING) task_specs = {'x': {'reset': False}} patched_mistral_runner.resume.assert_called_with( ex_ref=execution1, task_specs=task_specs) @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_resume_option_reset_tasks(self): patched_mistral_runner = self.get_runner_class('mistral_v2') mock_resume_result = (action_constants.LIVEACTION_STATUS_RUNNING, { 'tasks': [] }, { 'execution_id': str(uuid.uuid4()) }) with mock.patch.object( patched_mistral_runner, 'resume', mock.MagicMock(return_value=mock_resume_result)): liveaction1 = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS) liveaction1, execution1 = action_service.request(liveaction1) self.assertFalse(patched_mistral_runner.resume.called) # Rerun the execution. context = { 're-run': { 'ref': execution1.id, 'tasks': ['x', 'y'], 'reset': ['y'] } } liveaction2 = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS, context=context) liveaction2, execution2 = action_service.request(liveaction2) liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_RUNNING) task_specs = {'x': {'reset': False}, 'y': {'reset': True}} patched_mistral_runner.resume.assert_called_with( ex_ref=execution1, task_specs=task_specs) @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_NOT_RERUNABLE))) @mock.patch.object( executions.ExecutionManager, 'get', mock.MagicMock( return_value=executions.Execution(None, WF1_EXEC_NOT_RERUNABLE))) @mock.patch.object(tasks.TaskManager, 'list', mock.MagicMock(return_value=WF1_TASKS)) def test_resume_workflow_not_in_rerunable_state(self): liveaction1 = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS) liveaction1, execution1 = action_service.request(liveaction1) # Rerun the execution. context = {'re-run': {'ref': execution1.id, 'tasks': ['say-friend']}} liveaction2 = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS, context=context) liveaction2, execution2 = action_service.request(liveaction2) liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_FAILED) self.assertIn('not in a rerunable state', liveaction2.result.get('error')) @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, 'list', mock.MagicMock(return_value=[executions.Execution(None, WF1_EXEC)])) @mock.patch.object( executions.ExecutionManager, 'create', mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC))) @mock.patch.object( executions.ExecutionManager, 'get', mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC))) @mock.patch.object(tasks.TaskManager, 'list', mock.MagicMock(return_value=WF1_TASKS)) def test_resume_tasks_not_in_rerunable_state(self): liveaction1 = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS) liveaction1, execution1 = action_service.request(liveaction1) # Rerun the execution. context = {'re-run': {'ref': execution1.id, 'tasks': ['say-friend']}} liveaction2 = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS, context=context) liveaction2, execution2 = action_service.request(liveaction2) liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_FAILED) self.assertIn('Unable to identify rerunable', liveaction2.result.get('error')) @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, 'list', mock.MagicMock(return_value=[executions.Execution(None, WF1_EXEC)])) @mock.patch.object( executions.ExecutionManager, 'create', mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC))) @mock.patch.object( executions.ExecutionManager, 'get', mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC))) @mock.patch.object(tasks.TaskManager, 'list', mock.MagicMock(return_value=WF1_TASKS)) def test_resume_unidentified_tasks(self): liveaction1 = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS) liveaction1, execution1 = action_service.request(liveaction1) # Rerun the execution. context = {'re-run': {'ref': execution1.id, 'tasks': ['x']}} liveaction2 = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS, context=context) liveaction2, execution2 = action_service.request(liveaction2) liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_FAILED) self.assertIn('Unable to identify', liveaction2.result.get('error')) @mock.patch.object(workflows.WorkflowManager, 'list', mock.MagicMock(return_value=[])) @mock.patch.object(workflows.WorkflowManager, 'get', mock.MagicMock(return_value=WF1)) @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_MAIN_EXEC))) @mock.patch.object( executions.ExecutionManager, 'get', mock.MagicMock( return_value=executions.Execution(None, WB1_MAIN_EXEC_ERRORED))) @mock.patch.object(executions.ExecutionManager, 'list', mock.MagicMock(return_value=[ executions.Execution(None, WB1_MAIN_EXEC_ERRORED), executions.Execution(None, WB1_SUB1_EXEC_ERRORED) ])) @mock.patch.object( tasks.TaskManager, 'list', mock.MagicMock(side_effect=[WB1_MAIN_TASKS, WB1_SUB1_TASKS])) @mock.patch.object(tasks.TaskManager, 'rerun', mock.MagicMock(return_value=None)) def test_resume_subworkflow_task(self): liveaction1 = LiveActionDB(action=WB1_NAME, parameters=ACTION_PARAMS) liveaction1, execution1 = action_service.request(liveaction1) # Rerun the execution. context = { 're-run': { 'ref': execution1.id, 'tasks': ['greet.say-friend'] } } liveaction2 = LiveActionDB(action=WB1_NAME, parameters=ACTION_PARAMS, context=context) liveaction2, execution2 = action_service.request(liveaction2) liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_RUNNING) expected_env = { 'st2_liveaction_id': str(liveaction2.id), 'st2_execution_id': str(execution2.id), '__actions': { 'st2.action': { 'st2_context': { 'api_url': 'http://0.0.0.0:9101/v1', 'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions', 'notify': {}, 'parent': { 'pack': 'mistral_tests', 're-run': context['re-run'], 'execution_id': str(execution2.id) }, 'skip_notify_tasks': [] } } }, 'st2_action_api_url': 'http://0.0.0.0:9101/v1' } tasks.TaskManager.rerun.assert_called_with(WB1_SUB1_TASK2['id'], reset=False, env=expected_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(workbooks.WorkbookManager, 'create', mock.MagicMock(return_value=WB1)) @mock.patch.object( executions.ExecutionManager, 'create', mock.MagicMock(return_value=executions.Execution(None, WB1_MAIN_EXEC))) @mock.patch.object( executions.ExecutionManager, 'get', mock.MagicMock( return_value=executions.Execution(None, WB1_MAIN_EXEC_ERRORED))) @mock.patch.object(executions.ExecutionManager, 'list', mock.MagicMock(return_value=[ executions.Execution(None, WB1_MAIN_EXEC_ERRORED), executions.Execution(None, WB1_SUB1_EXEC_ERRORED) ])) @mock.patch.object( tasks.TaskManager, 'list', mock.MagicMock(side_effect=[WB1_MAIN_TASKS, WB1_SUB1_TASKS])) def test_resume_unidentified_subworkflow_task(self): liveaction1 = LiveActionDB(action=WB1_NAME, parameters=ACTION_PARAMS) liveaction1, execution1 = action_service.request(liveaction1) # Rerun the execution. context = {'re-run': {'ref': execution1.id, 'tasks': ['greet.x']}} liveaction2 = LiveActionDB(action=WB1_NAME, parameters=ACTION_PARAMS, context=context) liveaction2, execution2 = action_service.request(liveaction2) liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_FAILED) self.assertIn('Unable to identify', liveaction2.result.get('error')) @mock.patch.object(workflows.WorkflowManager, 'list', mock.MagicMock(return_value=[])) @mock.patch.object(workflows.WorkflowManager, 'get', mock.MagicMock(return_value=WF1)) @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_MAIN_EXEC))) @mock.patch.object( executions.ExecutionManager, 'get', mock.MagicMock( return_value=executions.Execution(None, WB1_MAIN_EXEC_ERRORED))) @mock.patch.object(executions.ExecutionManager, 'list', mock.MagicMock(return_value=[ executions.Execution(None, WB1_MAIN_EXEC_ERRORED), executions.Execution(None, WB1_SUB1_EXEC_ERRORED) ])) @mock.patch.object( tasks.TaskManager, 'list', mock.MagicMock(side_effect=[WB1_MAIN_TASKS, WB1_SUB1_TASKS])) @mock.patch.object(tasks.TaskManager, 'rerun', mock.MagicMock(return_value=None)) def test_resume_and_reset_subworkflow_task(self): liveaction1 = LiveActionDB(action=WB1_NAME, parameters=ACTION_PARAMS) liveaction1, execution1 = action_service.request(liveaction1) # Rerun the execution. context = { 're-run': { 'ref': execution1.id, 'tasks': ['greet.say-friend'], 'reset': ['greet.say-friend'] } } liveaction2 = LiveActionDB(action=WB1_NAME, parameters=ACTION_PARAMS, context=context) liveaction2, execution2 = action_service.request(liveaction2) liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_RUNNING) expected_env = { 'st2_liveaction_id': str(liveaction2.id), 'st2_execution_id': str(execution2.id), '__actions': { 'st2.action': { 'st2_context': { 'api_url': 'http://0.0.0.0:9101/v1', 'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions', 'notify': {}, 'parent': { 'pack': 'mistral_tests', 're-run': context['re-run'], 'execution_id': str(execution2.id) }, 'skip_notify_tasks': [] } } }, 'st2_action_api_url': 'http://0.0.0.0:9101/v1' } tasks.TaskManager.rerun.assert_called_with(WB1_SUB1_TASK2['id'], reset=True, env=expected_env)
] MOCK_WF_TASKS_RUNNING = [ {'name': 'task1', 'state': 'SUCCESS'}, {'name': 'task2', 'state': 'RUNNING'} ] MOCK_WF_EX_DATA = { 'id': uuid.uuid4().hex, 'name': 'main', 'output': '{"k1": "v1"}', 'state': 'SUCCESS', 'state_info': None } MOCK_WF_EX = executions.Execution(None, MOCK_WF_EX_DATA) MOCK_WF_EX_TASKS_DATA = [ { 'id': uuid.uuid4().hex, 'name': 'task1', 'workflow_execution_id': MOCK_WF_EX_DATA['id'], 'workflow_name': MOCK_WF_EX_DATA['name'], 'created_at': str(datetime.datetime.utcnow()), 'updated_at': str(datetime.datetime.utcnow()), 'state': 'SUCCESS', 'state_info': None, 'input': '{"a": "b"}', 'result': '{"c": "d"}', 'published': '{"c": "d"}' },
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)
from st2common.persistence.action import Action, ActionExecution CHAMPION = worker.Worker(None) WORKFLOW_YAML = [f for f in fixture.WORKFLOW_YAMLS if 'workflow-v2.yaml' in f][0] WORKBOOK_SPEC = fixture.ARTIFACTS['workflows']['workflow-v2'] WORKBOOK = workbooks.Workbook(None, { 'name': 'workflow-v2', 'definition': WORKBOOK_SPEC }) WORKBOOK_OLD = workbooks.Workbook(None, { 'name': 'workflow-v2', 'definition': '' }) EXECUTION = executions.Execution(None, { 'id': str(uuid.uuid4()), 'state': 'RUNNING' }) def process_create(payload): if isinstance(payload, ActionExecutionDB): CHAMPION.execute_action(payload) @mock.patch.object(FabricRunner, '_run', mock.MagicMock(return_value={})) @mock.patch.object(CUDPublisher, 'publish_create', mock.MagicMock(side_effect=process_create)) @mock.patch.object(CUDPublisher, 'publish_update', mock.MagicMock(return_value=None)) class TestMistralRunner(DbTestCase): @classmethod
class MistralAuthTest(DbTestCase): @classmethod def setUpClass(cls): super(MistralAuthTest, 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(MistralAuthTest, self).setUp() cfg.CONF.set_override('api_url', 'http://0.0.0.0:9101', group='auth') def tearDown(self): super(MistralAuthTest, self).tearDown() cfg.CONF.set_default('keystone_username', None, group='mistral') cfg.CONF.set_default('keystone_password', None, group='mistral') cfg.CONF.set_default('keystone_project_name', None, group='mistral') cfg.CONF.set_default('keystone_auth_url', None, 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))) @mock.patch.object(access_service, 'create_token', mock.MagicMock(return_value=TOKEN_DB)) def test_launch_workflow_with_st2_auth(self): MistralRunner.entry_point = mock.PropertyMock( return_value=WF1_YAML_FILE_PATH) liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS, context=ACTION_CONTEXT) 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': { 'auth_token': TOKEN_DB.token, 'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions', 'parent': { 'user': liveaction.context['user'], '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( client.Client, 'authenticate', mock.MagicMock(return_value=(cfg.CONF.mistral.v2_base_url, '123', 'abc', 'xyz'))) @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_mistral_auth(self): cfg.CONF.set_default('keystone_username', 'foo', group='mistral') cfg.CONF.set_default('keystone_password', 'bar', group='mistral') cfg.CONF.set_default('keystone_project_name', 'admin', group='mistral') cfg.CONF.set_default('keystone_auth_url', 'http://127.0.0.1:5000/v3', group='mistral') 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': [] } } } } client.Client.authenticate.assert_called_with( cfg.CONF.mistral.v2_base_url, cfg.CONF.mistral.keystone_username, cfg.CONF.mistral.keystone_password, cfg.CONF.mistral.keystone_project_name, cfg.CONF.mistral.keystone_auth_url, None, 'publicURL', 'workflow', None, None, None, False) executions.ExecutionManager.create.assert_called_with( WF1_NAME, workflow_input=workflow_input, env=env)
# License for the specific language governing permissions and limitations # under the License. # import mock import pkg_resources as pkg from mistralclient.api.v2 import executions from mistralclient.commands.v2 import executions as execution_cmd from mistralclient.tests.unit import base EXECUTION = executions.Execution(mock, { 'id': '123', 'workflow_name': 'some', 'description': '', 'state': 'RUNNING', 'state_info': None, 'created_at': '1', 'updated_at': '1' }) class TestCLIExecutionsV2(base.BaseCommandTest): def test_create_wf_input_string(self): self.client.executions.create.return_value = EXECUTION result = self.call(execution_cmd.Create, app_args=['id', '{ "context": true }']) self.assertEqual(('123', 'some', '', 'RUNNING', None, '1', '1'), result[1])
def data(TEST): # MistralActions TEST.mistralclient_actions = test_data_utils.TestDataContainer() action_1 = actions.Action( actions.ActionManager(None), {'name': 'a', 'is_system': True, 'input': 'param1', 'description': 'my cool action', 'tags': ['test'], 'created_at': '1', 'updated_at': '1' } ) TEST.mistralclient_actions.add(action_1) # MistralExecutions TEST.mistralclient_executions = test_data_utils.TestDataContainer() execution_1 = executions.Execution( executions.ExecutionManager(None), {'id': '123', 'workflow_name': 'my_wf', 'description': '', 'state': 'RUNNING', 'input': { 'person': { 'first_name': 'John', 'last_name': 'Doe' } }} ) TEST.mistralclient_executions.add(execution_1) # Tasks TEST.mistralclient_tasks = test_data_utils.TestDataContainer() task_1 = tasks.Task( tasks.TaskManager(None), {'id': '1', 'workflow_execution_id': '123', 'name': 'my_task', 'workflow_name': 'my_wf', 'state': 'RUNNING', 'type': 'ACTION', 'tags': ['deployment', 'demo'], 'result': {'some': 'result'}}) TEST.mistralclient_tasks.add(task_1) # Workbooks TEST.mistralclient_workbooks = test_data_utils.TestDataContainer() workbook_1 = workbooks.Workbook( workbooks.WorkbookManager(None), {'name': 'a', 'tags': ['a', 'b'], 'created_at': '1', 'updated_at': '1', 'definition': WB_DEF} ) TEST.mistralclient_workbooks.add(workbook_1) # Workflows TEST.mistralclient_workflows = test_data_utils.TestDataContainer() workflow_1 = workflows.Workflow( workflows.WorkflowManager(None), {'name': 'a', 'tags': ['a', 'b'], 'input': 'param', 'created_at': '1', 'updated_at': '1', 'definition': WF_DEF} ) TEST.mistralclient_workflows.add(workflow_1) # MistralActionsExecutions TEST.mistralclient_action_executions = test_data_utils.TestDataContainer() action_executions_1 = action_executions.ActionExecution( action_executions.ActionExecutionManager(None), {'id': '1', 'name': 'a', 'tags': ['a', 'b'], 'workflow_name': 'my work flow', 'task_execution_id': '1', 'task_name': 'b', 'description': '', 'created_at': '1', 'updated_at': '1', 'accepted': True, 'state': 'RUNNING' } ) TEST.mistralclient_action_executions.add(action_executions_1) # MistralCronTriggers TEST.mistralclient_cron_triggers = test_data_utils.TestDataContainer() cron_triggers_1 = cron_triggers.CronTrigger( cron_triggers.CronTriggerManager(None), {'id': '1', 'name': 'a', 'workflow_name': 'my work flow', 'pattern': '', 'next_execution_time': '', 'remaining_executions': '', 'first_execution_time': '', 'created_at': '1', 'updated_at': '1' }) TEST.mistralclient_cron_triggers.add(cron_triggers_1)
class MistralRunnerPauseResumeTest(DbTestCase): @classmethod def setUpClass(cls): super(MistralRunnerPauseResumeTest, cls).setUpClass() # Override the retry configuration here otherwise st2tests.config.parse_args # in DbTestCase.setUpClass will reset these overrides. cfg.CONF.set_override('retry_exp_msec', 100, group='mistral') cfg.CONF.set_override('retry_exp_max_msec', 200, group='mistral') cfg.CONF.set_override('retry_stop_max_msec', 200, group='mistral') 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).__class__ @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_pause(self): # Launch the workflow execution. 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')) # Pause the workflow execution. requester = cfg.CONF.system_user.user liveaction, execution = action_service.request_pause(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_PAUSING) @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=[ executions.Execution(None, WF1_EXEC_PAUSED), executions.Execution(None, WF1_EXEC)])) def test_resume(self): # Launch the workflow execution. 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')) # Pause the workflow execution. requester = cfg.CONF.system_user.user liveaction, execution = action_service.request_pause(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_PAUSING) # Manually update the liveaction from pausing to paused. The paused state # is usually updated by the mistral querier. action_service.update_status(liveaction, action_constants.LIVEACTION_STATUS_PAUSED) liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_PAUSED) # Resume the workflow execution. liveaction, execution = action_service.request_resume(liveaction, requester) executions.ExecutionManager.update.assert_called_with(WF1_EXEC.get('id'), 'RUNNING') liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING) @mock.patch.object( workflows.WorkflowManager, 'list', mock.MagicMock(return_value=[])) @mock.patch.object( workflows.WorkflowManager, 'get', mock.MagicMock(side_effect=[WF2, WF1])) @mock.patch.object( workflows.WorkflowManager, 'create', mock.MagicMock(side_effect=[[WF2], [WF1]])) @mock.patch.object( executions.ExecutionManager, 'create', mock.MagicMock(side_effect=[ executions.Execution(None, WF2_EXEC), executions.Execution(None, WF1_EXEC)])) @mock.patch.object( executions.ExecutionManager, 'update', mock.MagicMock(side_effect=[ executions.Execution(None, WF2_EXEC_PAUSED), executions.Execution(None, WF1_EXEC_PAUSED), executions.Execution(None, WF2_EXEC), executions.Execution(None, WF1_EXEC)])) def test_resume_subworkflow_action(self): requester = cfg.CONF.system_user.user liveaction1 = LiveActionDB(action=WF2_NAME, parameters=ACTION_PARAMS) liveaction1, execution1 = action_service.request(liveaction1) liveaction1 = LiveAction.get_by_id(str(liveaction1.id)) self.assertEqual(liveaction1.status, action_constants.LIVEACTION_STATUS_RUNNING) liveaction2 = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS) liveaction2, execution2 = action_service.request(liveaction2) liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_RUNNING) # Mock the children of the parent execution to make this # test case has subworkflow execution. with mock.patch.object( ActionExecutionDB, 'children', new_callable=mock.PropertyMock) as action_ex_children_mock: action_ex_children_mock.return_value = [execution2.id] mistral_context = liveaction1.context.get('mistral', None) self.assertIsNotNone(mistral_context) self.assertEqual(mistral_context['execution_id'], WF2_EXEC.get('id')) self.assertEqual(mistral_context['workflow_name'], WF2_EXEC.get('workflow_name')) # Pause the parent liveaction and check that the request is cascaded down. liveaction1, execution1 = action_service.request_pause(liveaction1, requester) self.assertTrue(executions.ExecutionManager.update.called) self.assertEqual(executions.ExecutionManager.update.call_count, 2) calls = [ mock.call(WF2_EXEC.get('id'), 'PAUSED'), mock.call(WF1_EXEC.get('id'), 'PAUSED') ] executions.ExecutionManager.update.assert_has_calls(calls, any_order=False) liveaction1 = LiveAction.get_by_id(str(liveaction1.id)) self.assertEqual(liveaction1.status, action_constants.LIVEACTION_STATUS_PAUSING) liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_PAUSING) # Manually set the liveaction status to PAUSED. action_service.update_status(liveaction2, action_constants.LIVEACTION_STATUS_PAUSED) action_service.update_status(liveaction1, action_constants.LIVEACTION_STATUS_PAUSED) liveaction1 = LiveAction.get_by_id(str(liveaction1.id)) self.assertEqual(liveaction1.status, action_constants.LIVEACTION_STATUS_PAUSED) liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_PAUSED) # Resume the parent liveaction and check that the request is cascaded down. liveaction1, execution1 = action_service.request_resume(liveaction1, requester) # Includes the previous calls. self.assertTrue(executions.ExecutionManager.update.called) self.assertEqual(executions.ExecutionManager.update.call_count, 4) calls = [ mock.call(WF2_EXEC.get('id'), 'PAUSED'), mock.call(WF1_EXEC.get('id'), 'PAUSED'), mock.call(WF2_EXEC.get('id'), 'RUNNING'), mock.call(WF1_EXEC.get('id'), 'RUNNING') ] executions.ExecutionManager.update.assert_has_calls(calls, any_order=False) liveaction1 = LiveAction.get_by_id(str(liveaction1.id)) self.assertEqual(liveaction1.status, action_constants.LIVEACTION_STATUS_RUNNING) liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_RUNNING) @mock.patch.object( workflows.WorkflowManager, 'list', mock.MagicMock(return_value=[])) @mock.patch.object( workflows.WorkflowManager, 'get', mock.MagicMock(side_effect=[WF2, WF1])) @mock.patch.object( workflows.WorkflowManager, 'create', mock.MagicMock(side_effect=[[WF2], [WF1]])) @mock.patch.object( executions.ExecutionManager, 'create', mock.MagicMock(side_effect=[ executions.Execution(None, WF2_EXEC), executions.Execution(None, WF1_EXEC)])) @mock.patch.object( executions.ExecutionManager, 'update', mock.MagicMock(side_effect=[ executions.Execution(None, WF2_EXEC_PAUSED), executions.Execution(None, WF1_EXEC_PAUSED), executions.Execution(None, WF2_EXEC), executions.Execution(None, WF1_EXEC)])) def test_pause_missing_subworkflow_action(self): requester = cfg.CONF.system_user.user liveaction1 = LiveActionDB(action=WF2_NAME, parameters=ACTION_PARAMS) liveaction1, execution1 = action_service.request(liveaction1) liveaction1 = LiveAction.get_by_id(str(liveaction1.id)) self.assertEqual(liveaction1.status, action_constants.LIVEACTION_STATUS_RUNNING) # Mock the children of the parent execution to make this # test case has subworkflow execution. with mock.patch.object( ActionExecutionDB, 'children', new_callable=mock.PropertyMock) as action_ex_children_mock: action_ex_children_mock.return_value = [uuid.uuid4().hex] mistral_context = liveaction1.context.get('mistral', None) self.assertIsNotNone(mistral_context) self.assertEqual(mistral_context['execution_id'], WF2_EXEC.get('id')) self.assertEqual(mistral_context['workflow_name'], WF2_EXEC.get('workflow_name')) # Pause the parent liveaction and check that the request is cascaded down. liveaction1, execution1 = action_service.request_pause(liveaction1, requester) self.assertTrue(executions.ExecutionManager.update.called) self.assertEqual(executions.ExecutionManager.update.call_count, 1) calls = [ mock.call(WF2_EXEC.get('id'), 'PAUSED'), ] executions.ExecutionManager.update.assert_has_calls(calls, any_order=False) # The workflow execution will fail because the liveaction for the subworkflow # should not be missing and we do not know what state it is in. liveaction1 = LiveAction.get_by_id(str(liveaction1.id)) self.assertEqual(liveaction1.status, action_constants.LIVEACTION_STATUS_FAILED) self.assertIn('not a valid ObjectId', liveaction1.result.get('error', '')) @mock.patch.object( workflows.WorkflowManager, 'list', mock.MagicMock(return_value=[])) @mock.patch.object( workflows.WorkflowManager, 'get', mock.MagicMock(side_effect=[WF2, WF1])) @mock.patch.object( workflows.WorkflowManager, 'create', mock.MagicMock(side_effect=[[WF2], [WF1]])) @mock.patch.object( executions.ExecutionManager, 'create', mock.MagicMock(side_effect=[ executions.Execution(None, WF2_EXEC), executions.Execution(None, WF1_EXEC)])) @mock.patch.object( executions.ExecutionManager, 'update', mock.MagicMock(side_effect=[ executions.Execution(None, WF2_EXEC_PAUSED), executions.Execution(None, WF1_EXEC_PAUSED), executions.Execution(None, WF2_EXEC), executions.Execution(None, WF1_EXEC)])) def test_resume_missing_subworkflow_action(self): requester = cfg.CONF.system_user.user liveaction1 = LiveActionDB(action=WF2_NAME, parameters=ACTION_PARAMS) liveaction1, execution1 = action_service.request(liveaction1) liveaction1 = LiveAction.get_by_id(str(liveaction1.id)) self.assertEqual(liveaction1.status, action_constants.LIVEACTION_STATUS_RUNNING) liveaction2 = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS) liveaction2, execution2 = action_service.request(liveaction2) liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_RUNNING) # Mock the children of the parent execution to make this # test case has subworkflow execution. with mock.patch.object( ActionExecutionDB, 'children', new_callable=mock.PropertyMock) as action_ex_children_mock: action_ex_children_mock.return_value = [execution2.id] mistral_context = liveaction1.context.get('mistral', None) self.assertIsNotNone(mistral_context) self.assertEqual(mistral_context['execution_id'], WF2_EXEC.get('id')) self.assertEqual(mistral_context['workflow_name'], WF2_EXEC.get('workflow_name')) # Pause the parent liveaction and check that the request is cascaded down. liveaction1, execution1 = action_service.request_pause(liveaction1, requester) self.assertTrue(executions.ExecutionManager.update.called) self.assertEqual(executions.ExecutionManager.update.call_count, 2) calls = [ mock.call(WF2_EXEC.get('id'), 'PAUSED'), mock.call(WF1_EXEC.get('id'), 'PAUSED') ] executions.ExecutionManager.update.assert_has_calls(calls, any_order=False) liveaction1 = LiveAction.get_by_id(str(liveaction1.id)) self.assertEqual(liveaction1.status, action_constants.LIVEACTION_STATUS_PAUSING) liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_PAUSING) # Manually set the liveaction status to PAUSED. action_service.update_status(liveaction2, action_constants.LIVEACTION_STATUS_PAUSED) action_service.update_status(liveaction1, action_constants.LIVEACTION_STATUS_PAUSED) liveaction1 = LiveAction.get_by_id(str(liveaction1.id)) self.assertEqual(liveaction1.status, action_constants.LIVEACTION_STATUS_PAUSED) liveaction2 = LiveAction.get_by_id(str(liveaction2.id)) self.assertEqual(liveaction2.status, action_constants.LIVEACTION_STATUS_PAUSED) # Mock the children of the parent execution to make this # test case has subworkflow execution. with mock.patch.object( ActionExecutionDB, 'children', new_callable=mock.PropertyMock) as action_ex_children_mock: action_ex_children_mock.return_value = [uuid.uuid4().hex] # Resume the parent liveaction and check that the request is cascaded down. liveaction1, execution1 = action_service.request_resume(liveaction1, requester) # Includes the previous calls. self.assertTrue(executions.ExecutionManager.update.called) self.assertEqual(executions.ExecutionManager.update.call_count, 3) calls = [ mock.call(WF2_EXEC.get('id'), 'PAUSED'), mock.call(WF1_EXEC.get('id'), 'PAUSED'), mock.call(WF2_EXEC.get('id'), 'RUNNING'), ] executions.ExecutionManager.update.assert_has_calls(calls, any_order=False) # The workflow execution will fail because the liveaction for the subworkflow # should not be missing and we do not know what state it is in. liveaction1 = LiveAction.get_by_id(str(liveaction1.id)) self.assertEqual(liveaction1.status, action_constants.LIVEACTION_STATUS_FAILED) self.assertIn('not a valid ObjectId', liveaction1.result.get('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.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)