def test_retry_policy_applied_on_workflow_failure(self): wf_name = 'sequential' wf_ac_ref = TEST_PACK + '.' + wf_name wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, wf_name + '.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING, lv_ac_db.result) # Ensure there is only one execution recorded. self.assertEqual(len(lv_db_access.LiveAction.query(action=wf_ac_ref)), 1) # Identify the records for the workflow and task. wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0] t1_ex_db = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id))[0] t1_lv_ac_db = lv_db_access.LiveAction.query(task_execution=str(t1_ex_db.id))[0] t1_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(t1_ex_db.id))[0] # Manually set the status to fail. ac_svc.update_status(t1_lv_ac_db, ac_const.LIVEACTION_STATUS_FAILED) t1_lv_ac_db = lv_db_access.LiveAction.query(task_execution=str(t1_ex_db.id))[0] t1_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(t1_ex_db.id))[0] self.assertEqual(t1_ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED) notifier.get_notifier().process(t1_ac_ex_db) workflows.get_engine().process(t1_ac_ex_db) # Assert the main workflow is completed. ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED) notifier.get_notifier().process(ac_ex_db) # Ensure execution is retried. self.assertEqual(len(lv_db_access.LiveAction.query(action=wf_ac_ref)), 2)
def test_adherence_to_output_schema(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'sequential_with_schema.yaml') wf_input = {'who': 'Thanos'} lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'], parameters=wf_input) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) wf_ex_dbs = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id)) wf_ex_db = wf_ex_dbs[0] query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'task1'} tk1_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk1_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk1_ex_db.id))[0] wf_svc.handle_action_execution_completion(tk1_ac_ex_db) tk1_ex_db = wf_db_access.TaskExecution.get_by_id(tk1_ex_db.id) wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'task2'} tk2_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk2_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk2_ex_db.id))[0] wf_svc.handle_action_execution_completion(tk2_ac_ex_db) tk2_ex_db = wf_db_access.TaskExecution.get_by_id(tk2_ex_db.id) wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'task3'} tk3_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk3_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk3_ex_db.id))[0] wf_svc.handle_action_execution_completion(tk3_ac_ex_db) wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED)
def test_run_workflow_action_config_context(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'config-context.yaml') wf_input = {} lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'], parameters=wf_input) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) # Assert action execution is running. lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING, lv_ac_db.result) wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0] self.assertEqual(wf_ex_db.status, ac_const.LIVEACTION_STATUS_RUNNING) # Assert task1 is already completed. query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'task1'} tk1_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk1_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk1_ex_db.id))[0] tk1_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk1_ac_ex_db.liveaction['id']) self.assertEqual(tk1_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) self.assertTrue(wf_svc.is_action_execution_under_workflow_context(tk1_ac_ex_db)) # Manually handle action execution completion. wf_svc.handle_action_execution_completion(tk1_ac_ex_db) # Assert workflow is completed. wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) self.assertEqual(wf_ex_db.status, wf_statuses.SUCCEEDED) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) # Verify config_context works self.assertEqual(wf_ex_db.output, {'msg': 'value of config key a'})
def test_with_items_empty_list(self): items = [] num_items = len(items) wf_input = {'members': items} wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'with-items.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'], parameters=wf_input) lv_ac_db, ac_ex_db = action_service.request(lv_ac_db) # Wait for the liveaction to complete. lv_ac_db = self._wait_on_status(lv_ac_db, action_constants.LIVEACTION_STATUS_SUCCEEDED) # Retrieve records from database. wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0] query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'task1'} t1_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] t1_ac_ex_dbs = ex_db_access.ActionExecution.query(task_execution=str(t1_ex_db.id)) # Ensure there is no action executions for the task and the task is already completed. self.assertEqual(len(t1_ac_ex_dbs), num_items) self.assertEqual(t1_ex_db.status, wf_statuses.SUCCEEDED) self.assertDictEqual(t1_ex_db.result, {'items': []}) # Assert the main workflow is completed. wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) self.assertEqual(wf_ex_db.status, wf_statuses.SUCCEEDED) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, action_constants.LIVEACTION_STATUS_SUCCEEDED) self.assertDictEqual(lv_ac_db.result, {'output': {'items': []}})
def test_notify_task_list_bad_item_value(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'sequential.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db.notify = notify_api_models.NotificationsHelper.to_model( MOCK_NOTIFY) expected_schema_failure_test_cases = [ 'task1', # Notify must be type of list. [123], # Item has to be type of string. [''], # String value cannot be empty. [' '], # String value cannot be just spaces. [' '], # String value cannot be just tabs. ['init task'], # String value cannot have space. ['init-task'], # String value cannot have dash. ['task1', 'task1'] # String values have to be unique. ] for notify_tasks in expected_schema_failure_test_cases: lv_ac_db.parameters = {'notify': notify_tasks} try: self.assertRaises(jsonschema.ValidationError, action_service.request, lv_ac_db) except Exception as e: raise AssertionError('%s: %s' % (six.text_type(e), notify_tasks))
def test_fail_start_task_action(self): expected_errors = [ { 'type': 'error', 'message': ( 'YaqlEvaluationException: Unable to evaluate expression ' '\'<% ctx().func.value %>\'. NoFunctionRegisteredException: ' 'Unknown function "#property#value"' ), 'task_id': 'task1', 'route': 0 } ] expected_result = {'output': None, 'errors': expected_errors} wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'fail-start-task-action.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) # Assert action execution for task is not started and workflow failed. wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0] tk_ex_dbs = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id)) self.assertEqual(len(tk_ex_dbs), 0) self.assertEqual(wf_ex_db.status, wf_statuses.FAILED) self.assertListEqual(self.sort_wf_runtime_errors(wf_ex_db.errors), expected_errors) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(lv_ac_db.result, expected_result) ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(ac_ex_db.result, expected_result)
def test_cancel_unexpected_exception(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, "sequential.yaml") lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta["name"]) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual( lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING, lv_ac_db.result ) # Cancel the action execution. requester = cfg.CONF.system_user.user lv_ac_db, ac_ex_db = ac_svc.request_cancellation(lv_ac_db, requester) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) # Make sure request cancellation is called. self.assertTrue(wf_svc.request_cancellation.called) # Make sure the live action and action execution still has a canceled # status despite of cancelation failure. The other option would be # to raise an exception and the records will be stuck in a canceling # status and user is unable to easily clean up. self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_CANCELED) self.assertIn( "Error encountered when canceling", lv_ac_db.result.get("error", "") )
def test_pause_subworkflow_not_cascade_up_to_workflow(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'subworkflow.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING, lv_ac_db.result) # Identify the records for the subworkflow. wf_ex_dbs = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id)) self.assertEqual(len(wf_ex_dbs), 1) tk_ex_dbs = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_dbs[0].id)) self.assertEqual(len(tk_ex_dbs), 1) tk_ac_ex_dbs = ex_db_access.ActionExecution.query(task_execution=str(tk_ex_dbs[0].id)) self.assertEqual(len(tk_ac_ex_dbs), 1) tk_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk_ac_ex_dbs[0].liveaction['id']) self.assertEqual(tk_lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING) # Pause the subworkflow. tk_lv_ac_db, tk_ac_ex_db = ac_svc.request_pause(tk_lv_ac_db, cfg.CONF.system_user.user) self.assertEqual(tk_lv_ac_db.status, ac_const.LIVEACTION_STATUS_PAUSING) # Assert the main workflow is still running. lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING)
def test_output_on_error(self): expected_output = { 'progress': 25 } expected_errors = [ { 'type': 'error', 'task_id': 'task2', 'message': 'Execution failed. See result for details.', 'result': { 'failed': True, 'return_code': 1, 'stderr': '', 'stdout': '', 'succeeded': False } } ] expected_result = { 'errors': expected_errors, 'output': expected_output } wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'output-on-error.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0] # Assert task1 is already completed and workflow execution is still running. query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'task1'} tk1_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk1_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk1_ex_db.id))[0] tk1_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk1_ac_ex_db.liveaction['id']) self.assertEqual(tk1_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) wf_svc.handle_action_execution_completion(tk1_ac_ex_db) wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) self.assertEqual(wf_ex_db.status, wf_statuses.RUNNING) # Assert task2 is already completed and workflow execution has failed. query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'task2'} tk2_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk2_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk2_ex_db.id))[0] tk2_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk2_ac_ex_db.liveaction['id']) self.assertEqual(tk2_lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED) wf_svc.handle_action_execution_completion(tk2_ac_ex_db) # Check output and result for expected value(s). wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) self.assertEqual(wf_ex_db.status, wf_statuses.FAILED) self.assertDictEqual(wf_ex_db.output, expected_output) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(lv_ac_db.result, expected_result) ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(ac_ex_db.result, expected_result)
def test_fail_vars_rendering(self): expected_errors = [{ 'type': 'error', 'message': ('YaqlEvaluationException: Unable to evaluate expression ' '\'<% abs(4).value %>\'. NoFunctionRegisteredException: ' 'Unknown function "#property#value"') }] expected_result = {'output': None, 'errors': expected_errors} wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'fail-vars-rendering.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) # Assert action execution for task is not started and workflow failed. wf_ex_db = wf_db_access.WorkflowExecution.query( action_execution=str(ac_ex_db.id))[0] tk_ex_dbs = wf_db_access.TaskExecution.query( workflow_execution=str(wf_ex_db.id)) self.assertEqual(len(tk_ex_dbs), 0) self.assertEqual(wf_ex_db.status, wf_statuses.FAILED) self.assertListEqual(self.sort_wf_runtime_errors(wf_ex_db.errors), expected_errors) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(lv_ac_db.result, expected_result) ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(ac_ex_db.result, expected_result)
def test_adherence_to_output_schema(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'sequential_with_schema.yaml') wf_input = {'who': 'Thanos'} lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'], parameters=wf_input) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) wf_ex_dbs = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id)) wf_ex_db = wf_ex_dbs[0] query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'task1'} tk1_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk1_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk1_ex_db.id))[0] wf_svc.handle_action_execution_completion(tk1_ac_ex_db) tk1_ex_db = wf_db_access.TaskExecution.get_by_id(tk1_ex_db.id) wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'task2'} tk2_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk2_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk2_ex_db.id))[0] wf_svc.handle_action_execution_completion(tk2_ac_ex_db) tk2_ex_db = wf_db_access.TaskExecution.get_by_id(tk2_ex_db.id) wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'task3'} tk3_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk3_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk3_ex_db.id))[0] wf_svc.handle_action_execution_completion(tk3_ac_ex_db) wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED)
def test_output_on_error(self): expected_output = { 'progress': 25 } expected_errors = [ { 'type': 'error', 'task_id': 'task2', 'message': 'Execution failed. See result for details.', 'result': { 'failed': True, 'return_code': 1, 'stderr': '', 'stdout': '', 'succeeded': False } } ] expected_result = { 'errors': expected_errors, 'output': expected_output } wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'output-on-error.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0] # Assert task1 is already completed and workflow execution is still running. query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'task1'} tk1_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk1_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk1_ex_db.id))[0] tk1_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk1_ac_ex_db.liveaction['id']) self.assertEqual(tk1_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) wf_svc.handle_action_execution_completion(tk1_ac_ex_db) wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) self.assertEqual(wf_ex_db.status, wf_states.RUNNING) # Assert task2 is already completed and workflow execution has failed. query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'task2'} tk2_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk2_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk2_ex_db.id))[0] tk2_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk2_ac_ex_db.liveaction['id']) self.assertEqual(tk2_lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED) wf_svc.handle_action_execution_completion(tk2_ac_ex_db) # Check output and result for expected value(s). wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) self.assertEqual(wf_ex_db.status, wf_states.FAILED) self.assertDictEqual(wf_ex_db.output, expected_output) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(lv_ac_db.result, expected_result) ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(ac_ex_db.result, expected_result)
def test_notify_task_list_bad_item_value(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'sequential.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db.notify = notify_api_models.NotificationsHelper.to_model(MOCK_NOTIFY) expected_schema_failure_test_cases = [ 'task1', # Notify must be type of list. [123], # Item has to be type of string. [''], # String value cannot be empty. [' '], # String value cannot be just spaces. [' '], # String value cannot be just tabs. ['init task'], # String value cannot have space. ['init-task'], # String value cannot have dash. ['task1', 'task1'] # String values have to be unique. ] for notify_tasks in expected_schema_failure_test_cases: lv_ac_db.parameters = {'notify': notify_tasks} try: self.assertRaises( jsonschema.ValidationError, action_service.request, lv_ac_db ) except Exception as e: raise AssertionError('%s: %s' % (six.text_type(e), notify_tasks))
def test_retry_policy_applied_on_workflow_failure(self): wf_name = 'sequential' wf_ac_ref = TEST_PACK + '.' + wf_name wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, wf_name + '.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING, lv_ac_db.result) # Ensure there is only one execution recorded. self.assertEqual(len(lv_db_access.LiveAction.query(action=wf_ac_ref)), 1) # Identify the records for the workflow and task. wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0] t1_ex_db = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id))[0] t1_lv_ac_db = lv_db_access.LiveAction.query(task_execution=str(t1_ex_db.id))[0] t1_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(t1_ex_db.id))[0] # Manually set the status to fail. ac_svc.update_status(t1_lv_ac_db, ac_const.LIVEACTION_STATUS_FAILED) t1_lv_ac_db = lv_db_access.LiveAction.query(task_execution=str(t1_ex_db.id))[0] t1_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(t1_ex_db.id))[0] self.assertEqual(t1_ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED) notifier.get_notifier().process(t1_ac_ex_db) workflows.get_engine().process(t1_ac_ex_db) # Assert the main workflow is completed. ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED) notifier.get_notifier().process(ac_ex_db) # Ensure execution is retried. self.assertEqual(len(lv_db_access.LiveAction.query(action=wf_ac_ref)), 2)
def test_with_items_empty_list(self): items = [] num_items = len(items) wf_input = {'members': items} wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'with-items.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'], parameters=wf_input) lv_ac_db, ac_ex_db = action_service.request(lv_ac_db) # Wait for the liveaction to complete. lv_ac_db = self._wait_on_status(lv_ac_db, action_constants.LIVEACTION_STATUS_SUCCEEDED) # Retrieve records from database. wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0] query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'task1'} t1_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] t1_ac_ex_dbs = ex_db_access.ActionExecution.query(task_execution=str(t1_ex_db.id)) # Ensure there is no action executions for the task and the task is already completed. self.assertEqual(len(t1_ac_ex_dbs), num_items) self.assertEqual(t1_ex_db.status, wf_statuses.SUCCEEDED) self.assertDictEqual(t1_ex_db.result, {'items': []}) # Assert the main workflow is completed. wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) self.assertEqual(wf_ex_db.status, wf_statuses.SUCCEEDED) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, action_constants.LIVEACTION_STATUS_SUCCEEDED) self.assertDictEqual(lv_ac_db.result, {'output': {'items': []}})
def test_fail_input_rendering(self): expected_errors = [{ "type": "error", "message": ("YaqlEvaluationException: Unable to evaluate expression " "'<% abs(4).value %>'. NoFunctionRegisteredException: " 'Unknown function "#property#value"'), }] expected_result = {"output": None, "errors": expected_errors} wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, "fail-input-rendering.yaml") lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta["name"]) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) # Assert action execution for task is not started and workflow failed. wf_ex_db = wf_db_access.WorkflowExecution.query( action_execution=str(ac_ex_db.id))[0] tk_ex_dbs = wf_db_access.TaskExecution.query( workflow_execution=str(wf_ex_db.id)) self.assertEqual(len(tk_ex_dbs), 0) self.assertEqual(wf_ex_db.status, wf_statuses.FAILED) self.assertListEqual(self.sort_workflow_errors(wf_ex_db.errors), expected_errors) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(lv_ac_db.result, expected_result) ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(ac_ex_db.result, expected_result)
def test_fail_start_task_input_expr_eval(self): expected_errors = [{ 'message': 'Unknown function "#property#value"', 'task_id': 'task1' }] expected_result = {'output': None, 'errors': expected_errors} wf_file = 'fail-start-task-input-expr-eval.yaml' wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, wf_file) lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) # Assert action execution for task is not started and workflow failed. wf_ex_db = wf_db_access.WorkflowExecution.query( action_execution=str(ac_ex_db.id))[0] tk_ex_dbs = wf_db_access.TaskExecution.query( workflow_execution=str(wf_ex_db.id)) self.assertEqual(len(tk_ex_dbs), 0) self.assertEqual(wf_ex_db.status, wf_states.FAILED) self.assertListEqual(self.sort_wf_runtime_errors(wf_ex_db.errors), expected_errors) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(lv_ac_db.result, expected_result) ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(ac_ex_db.result, expected_result)
def test_delay(self): expected_delay_sec = 1 expected_delay_msec = expected_delay_sec * 1000 wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'delay.yaml') wf_input = {'delay': expected_delay_sec} lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'], parameters=wf_input) lv_ac_db, ac_ex_db = action_service.request(lv_ac_db) lv_ac_db = self._wait_on_status( lv_ac_db, action_constants.LIVEACTION_STATUS_RUNNING) # Identify records for the main workflow. wf_ex_db = wf_db_access.WorkflowExecution.query( action_execution=str(ac_ex_db.id))[0] query_filters = { 'workflow_execution': str(wf_ex_db.id), 'task_id': 'task1' } t1_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] t1_ac_ex_db = ex_db_access.ActionExecution.query( task_execution=str(t1_ex_db.id))[0] t1_lv_ac_db = lv_db_access.LiveAction.query( task_execution=str(t1_ex_db.id))[0] # Assert delay value is rendered and assigned. self.assertEqual(t1_ex_db.delay, expected_delay_sec) self.assertEqual(t1_lv_ac_db.delay, expected_delay_msec) self.assertEqual(t1_ac_ex_db.delay, expected_delay_msec)
def test_subworkflow_with_items_empty_list(self): wf_input = {'members': []} wf_meta = base.get_wf_fixture_meta_data( TEST_PACK_PATH, 'with-items-empty-parent.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'], parameters=wf_input) lv_ac_db, ac_ex_db = action_service.request(lv_ac_db) # Identify the records for the main workflow. wf_ex_db = wf_db_access.WorkflowExecution.query( action_execution=str(ac_ex_db.id))[0] tk_ex_dbs = wf_db_access.TaskExecution.query( workflow_execution=str(wf_ex_db.id)) self.assertEqual(len(tk_ex_dbs), 1) # Identify the records for the tasks. t1_ac_ex_db = ex_db_access.ActionExecution.query( task_execution=str(tk_ex_dbs[0].id))[0] t1_wf_ex_db = wf_db_access.WorkflowExecution.query( action_execution=str(t1_ac_ex_db.id))[0] self.assertEqual(t1_ac_ex_db.status, action_constants.LIVEACTION_STATUS_SUCCEEDED) self.assertEqual(t1_wf_ex_db.status, wf_statuses.SUCCEEDED) # Manually processing completion of the subworkflow in task1. workflows.get_engine().process(t1_ac_ex_db) t1_ex_db = wf_db_access.TaskExecution.get_by_id(tk_ex_dbs[0].id) self.assertEqual(t1_ex_db.status, wf_statuses.SUCCEEDED) # Check that the workflow execution is completed. wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) self.assertEqual(wf_ex_db.status, wf_statuses.SUCCEEDED) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, action_constants.LIVEACTION_STATUS_SUCCEEDED)
def test_run_workflow_action_config_context(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'config-context.yaml') wf_input = {} lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'], parameters=wf_input) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) # Assert action execution is running. lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING, lv_ac_db.result) wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0] self.assertEqual(wf_ex_db.status, ac_const.LIVEACTION_STATUS_RUNNING) # Assert task1 is already completed. query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'task1'} tk1_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk1_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk1_ex_db.id))[0] tk1_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk1_ac_ex_db.liveaction['id']) self.assertEqual(tk1_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) self.assertTrue(wf_svc.is_action_execution_under_workflow_context(tk1_ac_ex_db)) # Manually handle action execution completion. wf_svc.handle_action_execution_completion(tk1_ac_ex_db) # Assert workflow is completed. wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) self.assertEqual(wf_ex_db.status, wf_statuses.SUCCEEDED) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) # Verify config_context works self.assertEqual(wf_ex_db.output, {'msg': 'value of config key a'})
def test_cancel_workflow_cascade_down_to_subworkflow(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'subworkflow.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING, lv_ac_db.result) # Identify the records for the subworkflow. wf_ex_dbs = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id)) self.assertEqual(len(wf_ex_dbs), 1) tk_ex_dbs = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_dbs[0].id)) self.assertEqual(len(tk_ex_dbs), 1) tk_ac_ex_dbs = ex_db_access.ActionExecution.query(task_execution=str(tk_ex_dbs[0].id)) self.assertEqual(len(tk_ac_ex_dbs), 1) tk_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk_ac_ex_dbs[0].liveaction['id']) self.assertEqual(tk_lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING) # Cancel the main workflow. requester = cfg.CONF.system_user.user lv_ac_db, ac_ex_db = ac_svc.request_cancellation(lv_ac_db, requester) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_CANCELING) # Assert the subworkflow is canceled. tk_lv_ac_db = lv_db_access.LiveAction.get_by_id(str(tk_lv_ac_db.id)) self.assertEqual(tk_lv_ac_db.status, ac_const.LIVEACTION_STATUS_CANCELED) # Assert the main workflow is canceled. lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_CANCELED)
def test_fail_start_task_input_expr_eval(self): expected_errors = [ { 'message': 'Unknown function "#property#value"', 'task_id': 'task1' } ] expected_result = {'output': None, 'errors': expected_errors} wf_file = 'fail-start-task-input-expr-eval.yaml' wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, wf_file) lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) # Assert action execution for task is not started and workflow failed. wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0] tk_ex_dbs = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id)) self.assertEqual(len(tk_ex_dbs), 0) self.assertEqual(wf_ex_db.status, wf_states.FAILED) self.assertListEqual(self.sort_wf_runtime_errors(wf_ex_db.errors), expected_errors) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(lv_ac_db.result, expected_result) ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(ac_ex_db.result, expected_result)
def test_delay_for_with_items(self): expected_delay_sec = 1 expected_delay_msec = expected_delay_sec * 1000 wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'with-items-delay.yaml') wf_input = {'delay': expected_delay_sec} lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'], parameters=wf_input) lv_ac_db, ac_ex_db = action_service.request(lv_ac_db) # Assert action execution is running. lv_ac_db = self._wait_on_status( lv_ac_db, action_constants.LIVEACTION_STATUS_RUNNING) wf_ex_db = wf_db_access.WorkflowExecution.query( action_execution=str(ac_ex_db.id))[0] self.assertEqual(wf_ex_db.status, action_constants.LIVEACTION_STATUS_RUNNING) # Process the with items task. query_filters = { 'workflow_execution': str(wf_ex_db.id), 'task_id': 'task1' } t1_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] t1_ac_ex_dbs = ex_db_access.ActionExecution.query( task_execution=str(t1_ex_db.id)) t1_lv_ac_dbs = lv_db_access.LiveAction.query( task_execution=str(t1_ex_db.id)) # Assert delay value is rendered and assigned. self.assertEqual(t1_ex_db.delay, expected_delay_sec) for t1_lv_ac_db in t1_lv_ac_dbs: self.assertEqual(t1_lv_ac_db.delay, expected_delay_msec) for t1_ac_ex_db in t1_ac_ex_dbs: self.assertEqual(t1_ac_ex_db.delay, expected_delay_msec) status = [ ac_ex.status == action_constants.LIVEACTION_STATUS_SUCCEEDED for ac_ex in t1_ac_ex_dbs ] self.assertTrue(all(status)) for t1_ac_ex_db in t1_ac_ex_dbs: workflows.get_engine().process(t1_ac_ex_db) t1_ex_db = wf_db_access.TaskExecution.get_by_id(t1_ex_db.id) self.assertEqual(t1_ex_db.status, wf_states.SUCCEEDED) # Assert the main workflow is completed. wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) self.assertEqual(wf_ex_db.status, wf_states.SUCCEEDED) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, action_constants.LIVEACTION_STATUS_SUCCEEDED)
def test_pause_workflow_cascade_down_to_subworkflow(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'subworkflow.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING, lv_ac_db.result) # Identify the records for the main workflow. wf_ex_dbs = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id)) self.assertEqual(len(wf_ex_dbs), 1) wf_ex_db = wf_ex_dbs[0] tk_ex_dbs = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id)) self.assertEqual(len(tk_ex_dbs), 1) tk_ex_db = tk_ex_dbs[0] tk_ac_ex_dbs = ex_db_access.ActionExecution.query(task_execution=str(tk_ex_db.id)) self.assertEqual(len(tk_ac_ex_dbs), 1) tk_ac_ex_db = tk_ac_ex_dbs[0] tk_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk_ac_ex_db.liveaction['id']) self.assertEqual(tk_lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING) # Identify the records for the subworkflow. sub_wf_ex_dbs = wf_db_access.WorkflowExecution.query(action_execution=str(tk_ac_ex_db.id)) self.assertEqual(len(sub_wf_ex_dbs), 1) sub_wf_ex_db = sub_wf_ex_dbs[0] sub_tk_ex_dbs = wf_db_access.TaskExecution.query(workflow_execution=str(sub_wf_ex_db.id)) self.assertEqual(len(sub_tk_ex_dbs), 1) sub_tk_ex_db = sub_tk_ex_dbs[0] sub_tk_ac_ex_dbs = ex_db_access.ActionExecution.query(task_execution=str(sub_tk_ex_db.id)) self.assertEqual(len(sub_tk_ac_ex_dbs), 1) # Pause the main workflow and assert it is pausing because subworkflow is still running. lv_ac_db, ac_ex_db = ac_svc.request_pause(lv_ac_db, cfg.CONF.system_user.user) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_PAUSING) # Assert the subworkflow is pausing. tk_lv_ac_db = lv_db_access.LiveAction.get_by_id(str(tk_lv_ac_db.id)) self.assertEqual(tk_lv_ac_db.status, ac_const.LIVEACTION_STATUS_PAUSING) # Manually handle action execution completion for the task in the subworkflow. sub_tk_ac_ex_db = sub_tk_ac_ex_dbs[0] self.assertEqual(sub_tk_ac_ex_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) workflows.get_engine().process(sub_tk_ac_ex_db) # Assert the subworkflow is paused and manually process the execution update. tk_lv_ac_db = lv_db_access.LiveAction.get_by_id(str(tk_lv_ac_db.id)) self.assertEqual(tk_lv_ac_db.status, ac_const.LIVEACTION_STATUS_PAUSED) tk_ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(tk_ac_ex_db.id)) self.assertEqual(tk_ac_ex_db.status, ac_const.LIVEACTION_STATUS_PAUSED) workflows.get_engine().process(tk_ac_ex_db) # Assert the main workflow is paused. lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_PAUSED)
def test_pause_workflow_cascade_down_to_subworkflow(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'subworkflow.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING, lv_ac_db.result) # Identify the records for the main workflow. wf_ex_dbs = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id)) self.assertEqual(len(wf_ex_dbs), 1) wf_ex_db = wf_ex_dbs[0] tk_ex_dbs = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id)) self.assertEqual(len(tk_ex_dbs), 1) tk_ex_db = tk_ex_dbs[0] tk_ac_ex_dbs = ex_db_access.ActionExecution.query(task_execution=str(tk_ex_db.id)) self.assertEqual(len(tk_ac_ex_dbs), 1) tk_ac_ex_db = tk_ac_ex_dbs[0] tk_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk_ac_ex_db.liveaction['id']) self.assertEqual(tk_lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING) # Identify the records for the subworkflow. sub_wf_ex_dbs = wf_db_access.WorkflowExecution.query(action_execution=str(tk_ac_ex_db.id)) self.assertEqual(len(sub_wf_ex_dbs), 1) sub_wf_ex_db = sub_wf_ex_dbs[0] sub_tk_ex_dbs = wf_db_access.TaskExecution.query(workflow_execution=str(sub_wf_ex_db.id)) self.assertEqual(len(sub_tk_ex_dbs), 1) sub_tk_ex_db = sub_tk_ex_dbs[0] sub_tk_ac_ex_dbs = ex_db_access.ActionExecution.query(task_execution=str(sub_tk_ex_db.id)) self.assertEqual(len(sub_tk_ac_ex_dbs), 1) # Pause the main workflow and assert it is pausing because subworkflow is still running. lv_ac_db, ac_ex_db = ac_svc.request_pause(lv_ac_db, cfg.CONF.system_user.user) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_PAUSING) # Assert the subworkflow is pausing. tk_lv_ac_db = lv_db_access.LiveAction.get_by_id(str(tk_lv_ac_db.id)) self.assertEqual(tk_lv_ac_db.status, ac_const.LIVEACTION_STATUS_PAUSING) # Manually handle action execution completion for the task in the subworkflow. sub_tk_ac_ex_db = sub_tk_ac_ex_dbs[0] self.assertEqual(sub_tk_ac_ex_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) workflows.get_engine().process(sub_tk_ac_ex_db) # Assert the subworkflow is paused and manually process the execution update. tk_lv_ac_db = lv_db_access.LiveAction.get_by_id(str(tk_lv_ac_db.id)) self.assertEqual(tk_lv_ac_db.status, ac_const.LIVEACTION_STATUS_PAUSED) tk_ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(tk_ac_ex_db.id)) self.assertEqual(tk_ac_ex_db.status, ac_const.LIVEACTION_STATUS_PAUSED) workflows.get_engine().process(tk_ac_ex_db) # Assert the main workflow is paused. lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_PAUSED)
def test_include_result_to_error_log(self): username = "******" wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, "sequential.yaml") wf_input = {"who": "Thanos"} lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta["name"], parameters=wf_input) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) # Assert action execution is running. lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING, lv_ac_db.result) wf_ex_dbs = wf_db_access.WorkflowExecution.query( action_execution=str(ac_ex_db.id)) wf_ex_db = wf_ex_dbs[0] # Assert task1 is already completed. query_filters = { "workflow_execution": str(wf_ex_db.id), "task_id": "task1" } tk1_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk1_ac_ex_db = ex_db_access.ActionExecution.query( task_execution=str(tk1_ex_db.id))[0] tk1_lv_ac_db = lv_db_access.LiveAction.get_by_id( tk1_ac_ex_db.liveaction["id"]) self.assertEqual(tk1_lv_ac_db.context.get("user"), username) self.assertEqual(tk1_lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED) # Action execution result can contain dotted notation so ensure this is tested. result = {"127.0.0.1": {"hostname": "foobar"}} self.assertDictEqual(tk1_lv_ac_db.result, result) # Manually handle action execution completion. wf_svc.handle_action_execution_completion(tk1_ac_ex_db) # Assert task and workflow failed. tk1_ex_db = wf_db_access.TaskExecution.get_by_id(tk1_ex_db.id) self.assertEqual(tk1_ex_db.status, wf_statuses.FAILED) wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) self.assertEqual(wf_ex_db.status, wf_statuses.FAILED) # Assert result is included in the error log. expected_errors = [{ "message": "Execution failed. See result for details.", "type": "error", "task_id": "task1", "result": { "127.0.0.1": { "hostname": "foobar" } }, }] self.assertListEqual(wf_ex_db.errors, expected_errors)
def test_fail_next_task_input_value_type(self): if six.PY3: msg = "Value \"{'x': 'foobar'}\" must either be a string or None. Got \"dict\"." else: msg = "Value \"{u'x': u'foobar'}\" must either be a string or None. Got \"dict\"." msg = "ValueError: " + msg expected_errors = [{ "type": "error", "message": msg, "task_id": "task2", "route": 0 }] expected_result = {"output": None, "errors": expected_errors} wf_file = "fail-task-input-value-type.yaml" wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, wf_file) wf_input = {"var1": {"x": "foobar"}} lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta["name"], parameters=wf_input) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) # Assert task1 is already completed and workflow execution is still running. wf_ex_db = wf_db_access.WorkflowExecution.query( action_execution=str(ac_ex_db.id))[0] tk1_ex_db = wf_db_access.TaskExecution.query( workflow_execution=str(wf_ex_db.id))[0] tk1_ac_ex_db = ex_db_access.ActionExecution.query( task_execution=str(tk1_ex_db.id))[0] tk1_lv_ac_db = lv_db_access.LiveAction.get_by_id( tk1_ac_ex_db.liveaction["id"]) self.assertEqual(tk1_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) self.assertEqual(wf_ex_db.status, wf_statuses.RUNNING) # Manually handle action execution completion for task1 which has an error in publish. wf_svc.handle_action_execution_completion(tk1_ac_ex_db) # Assert workflow execution and task2 execution failed. wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(str(wf_ex_db.id)) self.assertEqual(wf_ex_db.status, wf_statuses.FAILED) self.assertListEqual(self.sort_workflow_errors(wf_ex_db.errors), expected_errors) tk2_ex_db = wf_db_access.TaskExecution.query(task_id="task2")[0] self.assertEqual(tk2_ex_db.status, wf_statuses.FAILED) self.assertDictEqual(tk2_ex_db.result, {"errors": expected_errors}) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(lv_ac_db.result, expected_result) ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(ac_ex_db.result, expected_result)
def test_fail_next_task_input_value_type(self): if six.PY3: msg = 'Value "{\'x\': \'foobar\'}" must either be a string or None. Got "dict".' else: msg = 'Value "{u\'x\': u\'foobar\'}" must either be a string or None. Got "dict".' msg = 'ValueError: ' + msg expected_errors = [{ 'type': 'error', 'message': msg, 'task_id': 'task2', 'route': 0 }] expected_result = {'output': None, 'errors': expected_errors} wf_file = 'fail-task-input-value-type.yaml' wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, wf_file) wf_input = {'var1': {'x': 'foobar'}} lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'], parameters=wf_input) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) # Assert task1 is already completed and workflow execution is still running. wf_ex_db = wf_db_access.WorkflowExecution.query( action_execution=str(ac_ex_db.id))[0] tk1_ex_db = wf_db_access.TaskExecution.query( workflow_execution=str(wf_ex_db.id))[0] tk1_ac_ex_db = ex_db_access.ActionExecution.query( task_execution=str(tk1_ex_db.id))[0] tk1_lv_ac_db = lv_db_access.LiveAction.get_by_id( tk1_ac_ex_db.liveaction['id']) self.assertEqual(tk1_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) self.assertEqual(wf_ex_db.status, wf_statuses.RUNNING) # Manually handle action execution completion for task1 which has an error in publish. wf_svc.handle_action_execution_completion(tk1_ac_ex_db) # Assert workflow execution and task2 execution failed. wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(str(wf_ex_db.id)) self.assertEqual(wf_ex_db.status, wf_statuses.FAILED) self.assertListEqual(self.sort_wf_runtime_errors(wf_ex_db.errors), expected_errors) tk2_ex_db = wf_db_access.TaskExecution.query(task_id='task2')[0] self.assertEqual(tk2_ex_db.status, wf_statuses.FAILED) self.assertDictEqual(tk2_ex_db.result, {'errors': expected_errors}) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(lv_ac_db.result, expected_result) ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(ac_ex_db.result, expected_result)
def _execute_workflow(self, wf_name, expected_task_sequence, expected_output, expected_status=wf_states.SUCCEEDED, expected_errors=None): wf_file = wf_name + '.yaml' wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, wf_file) lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) # Assert action execution is running. lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING, lv_ac_db.result) wf_ex_db = wf_db_access.WorkflowExecution.query( action_execution=str(ac_ex_db.id))[0] self.assertEqual(wf_ex_db.status, ac_const.LIVEACTION_STATUS_RUNNING) for task_id in expected_task_sequence: query_filters = { 'workflow_execution': str(wf_ex_db.id), 'task_id': task_id } tk_ex_dbs = wf_db_access.TaskExecution.query(**query_filters) tk_ex_db = sorted( tk_ex_dbs, key=lambda x: x.start_timestamp)[len(tk_ex_dbs) - 1] tk_ac_ex_db = ex_db_access.ActionExecution.query( task_execution=str(tk_ex_db.id))[0] tk_lv_ac_db = lv_db_access.LiveAction.get_by_id( tk_ac_ex_db.liveaction['id']) self.assertEqual(tk_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) self.assertTrue( wf_svc.is_action_execution_under_workflow_context(tk_ac_ex_db)) wf_svc.handle_action_execution_completion(tk_ac_ex_db) # Assert workflow is completed. wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) self.assertEqual(wf_ex_db.status, expected_status) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, expected_status) ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(ac_ex_db.status, expected_status) # Check workflow output, liveaction result, and action execution result. expected_result = {'output': expected_output} if expected_errors is not None: expected_result['errors'] = expected_errors if expected_output is not None: self.assertDictEqual(wf_ex_db.output, expected_output) self.assertDictEqual(lv_ac_db.result, expected_result) self.assertDictEqual(ac_ex_db.result, expected_result)
def test_action_context_source_channel(self): wf_name = 'subworkflow-source-channel-from-action-context' wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, wf_name + '.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'], context={'source_channel': 'general'}) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING, lv_ac_db.result) # Identify the records for the main workflow. wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0] t1_ex_db = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id))[0] t1_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(t1_ex_db.id))[0] t1_wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(t1_ac_ex_db.id))[0] self.assertEqual(t1_ex_db.status, wf_statuses.RUNNING) self.assertEqual(t1_ac_ex_db.status, ac_const.LIVEACTION_STATUS_RUNNING) self.assertEqual(t1_wf_ex_db.status, wf_statuses.RUNNING) # Complete subworkflow under task1. query_filters = {'workflow_execution': str(t1_wf_ex_db.id), 'task_id': 'task1'} t1_t1_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] t1_t1_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(t1_t1_ex_db.id))[0] wf_svc.handle_action_execution_completion(t1_t1_ac_ex_db) query_filters = {'workflow_execution': str(t1_wf_ex_db.id), 'task_id': 'task2'} t1_t2_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] t1_t2_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(t1_t2_ex_db.id))[0] wf_svc.handle_action_execution_completion(t1_t2_ac_ex_db) query_filters = {'workflow_execution': str(t1_wf_ex_db.id), 'task_id': 'task3'} t1_t3_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] t1_t3_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(t1_t3_ex_db.id))[0] wf_svc.handle_action_execution_completion(t1_t3_ac_ex_db) t1_wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(str(t1_wf_ex_db.id)) t1_ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(t1_ac_ex_db.id)) self.assertEqual(t1_wf_ex_db.status, wf_statuses.SUCCEEDED) self.assertEqual(t1_ac_ex_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) # Complete task1 and main workflow. wf_svc.handle_action_execution_completion(t1_ac_ex_db) t1_ex_db = wf_db_access.TaskExecution.get_by_id(str(t1_ex_db.id)) wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(str(wf_ex_db.id)) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(t1_ex_db.status, wf_statuses.SUCCEEDED) self.assertEqual(wf_ex_db.status, wf_statuses.SUCCEEDED) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) # Check result. expected_result = { 'output': { 'msg': 'general, All your base are belong to us!' } } self.assertDictEqual(lv_ac_db.result, expected_result)
def test_action_context_source_channel(self): wf_name = 'subworkflow-source-channel-from-action-context' wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, wf_name + '.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'], context={'source_channel': 'general'}) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING, lv_ac_db.result) # Identify the records for the main workflow. wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0] t1_ex_db = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id))[0] t1_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(t1_ex_db.id))[0] t1_wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(t1_ac_ex_db.id))[0] self.assertEqual(t1_ex_db.status, wf_statuses.RUNNING) self.assertEqual(t1_ac_ex_db.status, ac_const.LIVEACTION_STATUS_RUNNING) self.assertEqual(t1_wf_ex_db.status, wf_statuses.RUNNING) # Complete subworkflow under task1. query_filters = {'workflow_execution': str(t1_wf_ex_db.id), 'task_id': 'task1'} t1_t1_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] t1_t1_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(t1_t1_ex_db.id))[0] wf_svc.handle_action_execution_completion(t1_t1_ac_ex_db) query_filters = {'workflow_execution': str(t1_wf_ex_db.id), 'task_id': 'task2'} t1_t2_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] t1_t2_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(t1_t2_ex_db.id))[0] wf_svc.handle_action_execution_completion(t1_t2_ac_ex_db) query_filters = {'workflow_execution': str(t1_wf_ex_db.id), 'task_id': 'task3'} t1_t3_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] t1_t3_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(t1_t3_ex_db.id))[0] wf_svc.handle_action_execution_completion(t1_t3_ac_ex_db) t1_wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(str(t1_wf_ex_db.id)) t1_ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(t1_ac_ex_db.id)) self.assertEqual(t1_wf_ex_db.status, wf_statuses.SUCCEEDED) self.assertEqual(t1_ac_ex_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) # Complete task1 and main workflow. wf_svc.handle_action_execution_completion(t1_ac_ex_db) t1_ex_db = wf_db_access.TaskExecution.get_by_id(str(t1_ex_db.id)) wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(str(wf_ex_db.id)) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(t1_ex_db.status, wf_statuses.SUCCEEDED) self.assertEqual(wf_ex_db.status, wf_statuses.SUCCEEDED) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) # Check result. expected_result = { 'output': { 'msg': 'general, All your base are belong to us!' } } self.assertDictEqual(lv_ac_db.result, expected_result)
def test_no_retry_policy_applied_on_task_failure(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'subworkflow.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING, lv_ac_db.result) # Identify the records for the main workflow. wf_ex_db = wf_db_access.WorkflowExecution.query( action_execution=str(ac_ex_db.id))[0] tk_ex_dbs = wf_db_access.TaskExecution.query( workflow_execution=str(wf_ex_db.id)) self.assertEqual(len(tk_ex_dbs), 1) # Identify the records for the tasks. t1_ac_ex_db = ex_db_access.ActionExecution.query( task_execution=str(tk_ex_dbs[0].id))[0] t1_wf_ex_db = wf_db_access.WorkflowExecution.query( action_execution=str(t1_ac_ex_db.id))[0] self.assertEqual(t1_ac_ex_db.status, ac_const.LIVEACTION_STATUS_RUNNING) self.assertEqual(t1_wf_ex_db.status, wf_statuses.RUNNING) # Ensure there is only one execution for the task. tk_ac_ref = TEST_PACK + '.' + 'sequential' self.assertEqual(len(lv_db_access.LiveAction.query(action=tk_ac_ref)), 1) # Fail the subtask of the subworkflow. t1_t1_ex_db = wf_db_access.TaskExecution.query( workflow_execution=str(t1_wf_ex_db.id))[0] t1_t1_lv_ac_db = lv_db_access.LiveAction.query( task_execution=str(t1_t1_ex_db.id))[0] ac_svc.update_status(t1_t1_lv_ac_db, ac_const.LIVEACTION_STATUS_FAILED) t1_t1_ac_ex_db = ex_db_access.ActionExecution.query( task_execution=str(t1_t1_ex_db.id))[0] self.assertEqual(t1_t1_ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED) notifier.get_notifier().process(t1_t1_ac_ex_db) workflows.get_engine().process(t1_t1_ac_ex_db) # Ensure the task execution is not retried. self.assertEqual(len(lv_db_access.LiveAction.query(action=tk_ac_ref)), 1) # Process the failure of the subworkflow. t1_ac_ex_db = ex_db_access.ActionExecution.get_by_id( str(t1_ac_ex_db.id)) self.assertEqual(t1_ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED) workflows.get_engine().process(t1_ac_ex_db) # Assert the main workflow is completed. ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED)
def test_fail_incorrect_output_schema(self): wf_meta = base.get_wf_fixture_meta_data( TEST_PACK_PATH, 'sequential_with_broken_schema.yaml') wf_input = {'who': 'Thanos'} lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'], parameters=wf_input) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) wf_ex_dbs = wf_db_access.WorkflowExecution.query( action_execution=str(ac_ex_db.id)) wf_ex_db = wf_ex_dbs[0] query_filters = { 'workflow_execution': str(wf_ex_db.id), 'task_id': 'task1' } tk1_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk1_ac_ex_db = ex_db_access.ActionExecution.query( task_execution=str(tk1_ex_db.id))[0] wf_svc.handle_action_execution_completion(tk1_ac_ex_db) tk1_ex_db = wf_db_access.TaskExecution.get_by_id(tk1_ex_db.id) wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) query_filters = { 'workflow_execution': str(wf_ex_db.id), 'task_id': 'task2' } tk2_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk2_ac_ex_db = ex_db_access.ActionExecution.query( task_execution=str(tk2_ex_db.id))[0] wf_svc.handle_action_execution_completion(tk2_ac_ex_db) tk2_ex_db = wf_db_access.TaskExecution.get_by_id(tk2_ex_db.id) wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) query_filters = { 'workflow_execution': str(wf_ex_db.id), 'task_id': 'task3' } tk3_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk3_ac_ex_db = ex_db_access.ActionExecution.query( task_execution=str(tk3_ex_db.id))[0] wf_svc.handle_action_execution_completion(tk3_ac_ex_db) wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED) expected_result = { 'error': "Additional properties are not allowed", 'message': 'Error validating output. See error output for more details.' } self.assertIn(expected_result['error'], ac_ex_db.result['error']) self.assertEqual(expected_result['message'], ac_ex_db.result['message'])
def test_pause_with_active_children(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'sequential.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING, lv_ac_db.result) lv_ac_db, ac_ex_db = ac_svc.request_pause(lv_ac_db, cfg.CONF.system_user.user) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_PAUSING)
def test_pause_with_active_children(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'sequential.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING, lv_ac_db.result) lv_ac_db, ac_ex_db = ac_svc.request_pause(lv_ac_db, cfg.CONF.system_user.user) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_PAUSING)
def test_run_workflow_with_unicode_input(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'sequential.yaml') wf_input = {'who': '薩諾斯'} lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'], parameters=wf_input) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0] # Process task1. query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'task1'} tk1_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk1_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk1_ex_db.id))[0] tk1_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk1_ac_ex_db.liveaction['id']) self.assertEqual(tk1_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) wf_svc.handle_action_execution_completion(tk1_ac_ex_db) tk1_ex_db = wf_db_access.TaskExecution.get_by_id(tk1_ex_db.id) self.assertEqual(tk1_ex_db.status, wf_statuses.SUCCEEDED) # Process task2. query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'task2'} tk2_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk2_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk2_ex_db.id))[0] tk2_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk2_ac_ex_db.liveaction['id']) self.assertEqual(tk2_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) wf_svc.handle_action_execution_completion(tk2_ac_ex_db) tk2_ex_db = wf_db_access.TaskExecution.get_by_id(tk2_ex_db.id) self.assertEqual(tk2_ex_db.status, wf_statuses.SUCCEEDED) # Process task3. query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'task3'} tk3_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk3_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk3_ex_db.id))[0] tk3_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk3_ac_ex_db.liveaction['id']) self.assertEqual(tk3_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) wf_svc.handle_action_execution_completion(tk3_ac_ex_db) tk3_ex_db = wf_db_access.TaskExecution.get_by_id(tk3_ex_db.id) self.assertEqual(tk3_ex_db.status, wf_statuses.SUCCEEDED) # Assert workflow is completed. wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) self.assertEqual(wf_ex_db.status, wf_statuses.SUCCEEDED) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) # Check workflow output. wf_input_val = wf_input['who'].decode('utf-8') if six.PY2 else wf_input['who'] expected_output = {'msg': '%s, All your base are belong to us!' % wf_input_val} self.assertDictEqual(wf_ex_db.output, expected_output) # Check liveaction and action execution result. expected_result = {'output': expected_output} self.assertDictEqual(lv_ac_db.result, expected_result) self.assertDictEqual(ac_ex_db.result, expected_result)
def test_run_workflow_with_unicode_input(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'sequential.yaml') wf_input = {'who': '薩諾斯'} lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'], parameters=wf_input) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0] # Process task1. query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'task1'} tk1_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk1_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk1_ex_db.id))[0] tk1_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk1_ac_ex_db.liveaction['id']) self.assertEqual(tk1_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) wf_svc.handle_action_execution_completion(tk1_ac_ex_db) tk1_ex_db = wf_db_access.TaskExecution.get_by_id(tk1_ex_db.id) self.assertEqual(tk1_ex_db.status, wf_statuses.SUCCEEDED) # Process task2. query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'task2'} tk2_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk2_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk2_ex_db.id))[0] tk2_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk2_ac_ex_db.liveaction['id']) self.assertEqual(tk2_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) wf_svc.handle_action_execution_completion(tk2_ac_ex_db) tk2_ex_db = wf_db_access.TaskExecution.get_by_id(tk2_ex_db.id) self.assertEqual(tk2_ex_db.status, wf_statuses.SUCCEEDED) # Process task3. query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'task3'} tk3_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk3_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk3_ex_db.id))[0] tk3_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk3_ac_ex_db.liveaction['id']) self.assertEqual(tk3_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) wf_svc.handle_action_execution_completion(tk3_ac_ex_db) tk3_ex_db = wf_db_access.TaskExecution.get_by_id(tk3_ex_db.id) self.assertEqual(tk3_ex_db.status, wf_statuses.SUCCEEDED) # Assert workflow is completed. wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) self.assertEqual(wf_ex_db.status, wf_statuses.SUCCEEDED) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) # Check workflow output. wf_input_val = wf_input['who'].decode('utf-8') if six.PY2 else wf_input['who'] expected_output = {'msg': '%s, All your base are belong to us!' % wf_input_val} self.assertDictEqual(wf_ex_db.output, expected_output) # Check liveaction and action execution result. expected_result = {'output': expected_output} self.assertDictEqual(lv_ac_db.result, expected_result) self.assertDictEqual(ac_ex_db.result, expected_result)
def test_cancel_subworkflow_cascade_up_to_workflow_with_other_subworkflows(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'subworkflows.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING, lv_ac_db.result) # Identify the records for the subworkflow. wf_ex_dbs = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id)) self.assertEqual(len(wf_ex_dbs), 1) tk_ex_dbs = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_dbs[0].id)) self.assertEqual(len(tk_ex_dbs), 2) tk1_ac_ex_dbs = ex_db_access.ActionExecution.query(task_execution=str(tk_ex_dbs[0].id)) self.assertEqual(len(tk1_ac_ex_dbs), 1) tk1_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk1_ac_ex_dbs[0].liveaction['id']) self.assertEqual(tk1_lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING) tk2_ac_ex_dbs = ex_db_access.ActionExecution.query(task_execution=str(tk_ex_dbs[1].id)) self.assertEqual(len(tk2_ac_ex_dbs), 1) tk2_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk2_ac_ex_dbs[0].liveaction['id']) self.assertEqual(tk2_lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING) # Cancel the subworkflow which should cascade up to the root. requester = cfg.CONF.system_user.user tk1_lv_ac_db, tk1_ac_ex_db = ac_svc.request_cancellation(tk1_lv_ac_db, requester) self.assertEqual(tk1_lv_ac_db.status, ac_const.LIVEACTION_STATUS_CANCELING) # Assert the main workflow is canceling. lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_CANCELING) # Assert both subworkflows are canceled. tk1_lv_ac_db = lv_db_access.LiveAction.get_by_id(str(tk1_lv_ac_db.id)) self.assertEqual(tk1_lv_ac_db.status, ac_const.LIVEACTION_STATUS_CANCELED) tk2_lv_ac_db = lv_db_access.LiveAction.get_by_id(str(tk2_lv_ac_db.id)) self.assertEqual(tk2_lv_ac_db.status, ac_const.LIVEACTION_STATUS_CANCELED) # Manually handle action execution completion for one of the tasks. tk1_ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(tk1_ac_ex_db.id)) self.assertEqual(tk1_ac_ex_db.status, ac_const.LIVEACTION_STATUS_CANCELED) wf_svc.handle_action_execution_completion(tk1_ac_ex_db) # Manually handle action execution completion for the other task. tk2_ac_ex_db = tk2_ac_ex_dbs[0] tk2_ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(tk2_ac_ex_db.id)) self.assertEqual(tk2_ac_ex_db.status, ac_const.LIVEACTION_STATUS_CANCELED) wf_svc.handle_action_execution_completion(tk2_ac_ex_db) # Assert the main workflow is canceling. lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_CANCELED)
def test_cancel_subworkflow_cascade_up_to_workflow_with_other_subworkflows(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'subworkflows.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING, lv_ac_db.result) # Identify the records for the subworkflow. wf_ex_dbs = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id)) self.assertEqual(len(wf_ex_dbs), 1) tk_ex_dbs = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_dbs[0].id)) self.assertEqual(len(tk_ex_dbs), 2) tk1_ac_ex_dbs = ex_db_access.ActionExecution.query(task_execution=str(tk_ex_dbs[0].id)) self.assertEqual(len(tk1_ac_ex_dbs), 1) tk1_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk1_ac_ex_dbs[0].liveaction['id']) self.assertEqual(tk1_lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING) tk2_ac_ex_dbs = ex_db_access.ActionExecution.query(task_execution=str(tk_ex_dbs[1].id)) self.assertEqual(len(tk2_ac_ex_dbs), 1) tk2_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk2_ac_ex_dbs[0].liveaction['id']) self.assertEqual(tk2_lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING) # Cancel the subworkflow which should cascade up to the root. requester = cfg.CONF.system_user.user tk1_lv_ac_db, tk1_ac_ex_db = ac_svc.request_cancellation(tk1_lv_ac_db, requester) self.assertEqual(tk1_lv_ac_db.status, ac_const.LIVEACTION_STATUS_CANCELING) # Assert the main workflow is canceling. lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_CANCELING) # Assert both subworkflows are canceled. tk1_lv_ac_db = lv_db_access.LiveAction.get_by_id(str(tk1_lv_ac_db.id)) self.assertEqual(tk1_lv_ac_db.status, ac_const.LIVEACTION_STATUS_CANCELED) tk2_lv_ac_db = lv_db_access.LiveAction.get_by_id(str(tk2_lv_ac_db.id)) self.assertEqual(tk2_lv_ac_db.status, ac_const.LIVEACTION_STATUS_CANCELED) # Manually handle action execution completion for one of the tasks. tk1_ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(tk1_ac_ex_db.id)) self.assertEqual(tk1_ac_ex_db.status, ac_const.LIVEACTION_STATUS_CANCELED) wf_svc.handle_action_execution_completion(tk1_ac_ex_db) # Manually handle action execution completion for the other task. tk2_ac_ex_db = tk2_ac_ex_dbs[0] tk2_ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(tk2_ac_ex_db.id)) self.assertEqual(tk2_ac_ex_db.status, ac_const.LIVEACTION_STATUS_CANCELED) wf_svc.handle_action_execution_completion(tk2_ac_ex_db) # Assert the main workflow is canceling. lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_CANCELED)
def test_fail_inspection(self): expected_errors = [ { "type": "content", "message": 'The action "std.noop" is not registered in the database.', "schema_path": r"properties.tasks.patternProperties.^\w+$.properties.action", "spec_path": "tasks.task3.action", }, { "type": "context", "language": "yaql", "expression": "<% ctx().foobar %>", "message": 'Variable "foobar" is referenced before assignment.', "schema_path": r"properties.tasks.patternProperties.^\w+$.properties.input", "spec_path": "tasks.task1.input", }, { "type": "expression", "language": "yaql", "expression": "<% <% succeeded() %>", "message": ("Parse error: unexpected '<' at " "position 0 of expression '<% succeeded()'"), "schema_path": (r"properties.tasks.patternProperties.^\w+$." "properties.next.items.properties.when"), "spec_path": "tasks.task2.next[0].when", }, { "type": "syntax", "message": ("[{'cmd': 'echo <% ctx().macro %>'}] is " "not valid under any of the given schemas"), "schema_path": r"properties.tasks.patternProperties.^\w+$.properties.input.oneOf", "spec_path": "tasks.task2.input", }, ] wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, "fail-inspection.yaml") lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta["name"]) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertIn("errors", lv_ac_db.result) self.assertListEqual(lv_ac_db.result["errors"], expected_errors)
def test_cancel(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'sequential.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING, lv_ac_db.result) requester = cfg.CONF.system_user.user lv_ac_db, ac_ex_db = ac_svc.request_cancellation(lv_ac_db, requester) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_CANCELING)
def test_cancel(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'sequential.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING, lv_ac_db.result) requester = cfg.CONF.system_user.user lv_ac_db, ac_ex_db = ac_svc.request_cancellation(lv_ac_db, requester) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_CANCELING)
def test_fail_task_publish(self): expected_errors = [{ 'type': 'error', 'message': ('YaqlEvaluationException: Unable to evaluate expression ' '\'<% foobar() %>\'. NoFunctionRegisteredException: ' 'Unknown function "foobar"'), 'task_transition_id': 'task2__t0', 'task_id': 'task1', 'route': 0 }] expected_result = {'output': None, 'errors': expected_errors} wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'fail-task-publish.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) # Assert task1 is already completed. wf_ex_db = wf_db_access.WorkflowExecution.query( action_execution=str(ac_ex_db.id))[0] tk_ex_db = wf_db_access.TaskExecution.query( workflow_execution=str(wf_ex_db.id))[0] tk_ac_ex_db = ex_db_access.ActionExecution.query( task_execution=str(tk_ex_db.id))[0] tk_lv_ac_db = lv_db_access.LiveAction.get_by_id( tk_ac_ex_db.liveaction['id']) self.assertEqual(tk_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) # Manually handle action execution completion for task1 which has an error in publish. wf_svc.handle_action_execution_completion(tk_ac_ex_db) # Assert task1 succeeded but workflow failed. tk_ex_db = wf_db_access.TaskExecution.get_by_id(tk_ex_db.id) self.assertEqual(tk_ex_db.status, wf_statuses.SUCCEEDED) wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) self.assertEqual(wf_ex_db.status, wf_statuses.FAILED) self.assertListEqual(self.sort_wf_runtime_errors(wf_ex_db.errors), expected_errors) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(lv_ac_db.result, expected_result) ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(ac_ex_db.result, expected_result)
def test_fail_task_publish(self): expected_errors = [{ "type": "error", "message": ("YaqlEvaluationException: Unable to evaluate expression " "'<% foobar() %>'. NoFunctionRegisteredException: " 'Unknown function "foobar"'), "task_transition_id": "task2__t0", "task_id": "task1", "route": 0, }] expected_result = {"output": None, "errors": expected_errors} wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, "fail-task-publish.yaml") lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta["name"]) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) # Assert task1 is already completed. wf_ex_db = wf_db_access.WorkflowExecution.query( action_execution=str(ac_ex_db.id))[0] tk_ex_db = wf_db_access.TaskExecution.query( workflow_execution=str(wf_ex_db.id))[0] tk_ac_ex_db = ex_db_access.ActionExecution.query( task_execution=str(tk_ex_db.id))[0] tk_lv_ac_db = lv_db_access.LiveAction.get_by_id( tk_ac_ex_db.liveaction["id"]) self.assertEqual(tk_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) # Manually handle action execution completion for task1 which has an error in publish. wf_svc.handle_action_execution_completion(tk_ac_ex_db) # Assert task1 succeeded but workflow failed. tk_ex_db = wf_db_access.TaskExecution.get_by_id(tk_ex_db.id) self.assertEqual(tk_ex_db.status, wf_statuses.SUCCEEDED) wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) self.assertEqual(wf_ex_db.status, wf_statuses.FAILED) self.assertListEqual(self.sort_workflow_errors(wf_ex_db.errors), expected_errors) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(lv_ac_db.result, expected_result) ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(ac_ex_db.result, expected_result)
def test_runtime_context(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, "runtime-context.yaml") lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta["name"]) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual( lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING, lv_ac_db.result ) # Identify the records for the workflow. wf_ex_db = wf_db_access.WorkflowExecution.query( action_execution=str(ac_ex_db.id) )[0] t1_ex_db = wf_db_access.TaskExecution.query( workflow_execution=str(wf_ex_db.id) )[0] t1_ac_ex_db = ex_db_access.ActionExecution.query( task_execution=str(t1_ex_db.id) )[0] # Complete the worklfow. wf_svc.handle_action_execution_completion(t1_ac_ex_db) t1_ex_db = wf_db_access.TaskExecution.get_by_id(str(t1_ex_db.id)) wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(str(wf_ex_db.id)) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(t1_ex_db.status, wf_statuses.SUCCEEDED) self.assertEqual(wf_ex_db.status, wf_statuses.SUCCEEDED) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) # Check result. expected_st2_ctx = { "action_execution_id": str(ac_ex_db.id), "api_url": "http://127.0.0.1/v1", "user": "******", "pack": "orquesta_tests", "action": "orquesta_tests.runtime-context", "runner": "orquesta", } expected_st2_ctx_with_wf_ex_id = copy.deepcopy(expected_st2_ctx) expected_st2_ctx_with_wf_ex_id["workflow_execution_id"] = str(wf_ex_db.id) expected_output = { "st2_ctx_at_input": expected_st2_ctx, "st2_ctx_at_vars": expected_st2_ctx, "st2_ctx_at_publish": expected_st2_ctx_with_wf_ex_id, "st2_ctx_at_output": expected_st2_ctx_with_wf_ex_id, } expected_result = {"output": expected_output} self.assertDictEqual(lv_ac_db.result, expected_result)
def test_fail_next_task_input_value_type(self): if six.PY3: msg = 'Value "{\'x\': \'foobar\'}" must either be a string or None. Got "dict".' else: msg = 'Value "{u\'x\': u\'foobar\'}" must either be a string or None. Got "dict".' msg = 'ValueError: ' + msg expected_errors = [ { 'type': 'error', 'message': msg, 'task_id': 'task2', 'route': 0 } ] expected_result = {'output': None, 'errors': expected_errors} wf_file = 'fail-task-input-value-type.yaml' wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, wf_file) wf_input = {'var1': {'x': 'foobar'}} lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'], parameters=wf_input) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) # Assert task1 is already completed and workflow execution is still running. wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0] tk1_ex_db = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id))[0] tk1_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk1_ex_db.id))[0] tk1_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk1_ac_ex_db.liveaction['id']) self.assertEqual(tk1_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) self.assertEqual(wf_ex_db.status, wf_statuses.RUNNING) # Manually handle action execution completion for task1 which has an error in publish. wf_svc.handle_action_execution_completion(tk1_ac_ex_db) # Assert workflow execution and task2 execution failed. wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(str(wf_ex_db.id)) self.assertEqual(wf_ex_db.status, wf_statuses.FAILED) self.assertListEqual(self.sort_wf_runtime_errors(wf_ex_db.errors), expected_errors) tk2_ex_db = wf_db_access.TaskExecution.query(task_id='task2')[0] self.assertEqual(tk2_ex_db.status, wf_statuses.FAILED) self.assertDictEqual(tk2_ex_db.result, {'errors': expected_errors}) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(lv_ac_db.result, expected_result) ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(ac_ex_db.result, expected_result)
def test_no_notify(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'sequential.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = action_service.request(lv_ac_db) # Assert action execution is running. lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, action_constants.LIVEACTION_STATUS_RUNNING) wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0] self.assertEqual(wf_ex_db.status, action_constants.LIVEACTION_STATUS_RUNNING) # Check that notify is setup correctly in the db record. self.assertDictEqual(wf_ex_db.notify, {})
def _execute_workflow(self, wf_name, expected_task_sequence, expected_output, expected_status=wf_statuses.SUCCEEDED, expected_errors=None): wf_file = wf_name + '.yaml' wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, wf_file) lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) # Assert action execution is running. lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING, lv_ac_db.result) wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0] self.assertEqual(wf_ex_db.status, ac_const.LIVEACTION_STATUS_RUNNING) for task_id, route in expected_task_sequence: tk_ex_dbs = wf_db_access.TaskExecution.query( workflow_execution=str(wf_ex_db.id), task_id=task_id, task_route=route ) if len(tk_ex_dbs) <= 0: break tk_ex_db = sorted(tk_ex_dbs, key=lambda x: x.start_timestamp)[len(tk_ex_dbs) - 1] tk_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk_ex_db.id))[0] tk_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk_ac_ex_db.liveaction['id']) self.assertEqual(tk_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) self.assertTrue(wf_svc.is_action_execution_under_workflow_context(tk_ac_ex_db)) wf_svc.handle_action_execution_completion(tk_ac_ex_db) # Assert workflow is completed. wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) self.assertEqual(wf_ex_db.status, expected_status) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, expected_status) ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(ac_ex_db.status, expected_status) # Check workflow output, liveaction result, and action execution result. expected_result = {'output': expected_output} if expected_errors is not None: expected_result['errors'] = expected_errors if expected_output is not None: self.assertDictEqual(wf_ex_db.output, expected_output) self.assertDictEqual(lv_ac_db.result, expected_result) self.assertDictEqual(ac_ex_db.result, expected_result)
def test_fail_inspection(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'fail-inspection.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertIn('errors', lv_ac_db.result) self.assertIn('expressions', lv_ac_db.result['errors']) self.assertGreater(len(lv_ac_db.result['errors']['expressions']), 0) self.assertIn('context', lv_ac_db.result['errors']) self.assertGreater(len(lv_ac_db.result['errors']['context']), 0) self.assertIn('syntax', lv_ac_db.result['errors']) self.assertGreater(len(lv_ac_db.result['errors']['syntax']), 0)
def test_fail_inspection(self): expected_errors = [ { 'type': 'content', 'message': 'The action "std.noop" is not registered in the database.', 'schema_path': r'properties.tasks.patternProperties.^\w+$.properties.action', 'spec_path': 'tasks.task3.action' }, { 'type': 'context', 'language': 'yaql', 'expression': '<% ctx().foobar %>', 'message': 'Variable "foobar" is referenced before assignment.', 'schema_path': r'properties.tasks.patternProperties.^\w+$.properties.input', 'spec_path': 'tasks.task1.input', }, { 'type': 'expression', 'language': 'yaql', 'expression': '<% <% succeeded() %>', 'message': ( 'Parse error: unexpected \'<\' at ' 'position 0 of expression \'<% succeeded()\'' ), 'schema_path': ( r'properties.tasks.patternProperties.^\w+$.' 'properties.next.items.properties.when' ), 'spec_path': 'tasks.task2.next[0].when' }, { 'type': 'syntax', 'message': ( '[{\'cmd\': \'echo <% ctx().macro %>\'}] is ' 'not valid under any of the given schemas' ), 'schema_path': r'properties.tasks.patternProperties.^\w+$.properties.input.oneOf', 'spec_path': 'tasks.task2.input' } ] wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'fail-inspection.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertIn('errors', lv_ac_db.result) self.assertListEqual(lv_ac_db.result['errors'], expected_errors)
def test_fail_manually(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'fail-manually.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0] # Assert task1 and workflow execution failed due to fail in the task transition. query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'task1'} tk1_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk1_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk1_ex_db.id))[0] tk1_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk1_ac_ex_db.liveaction['id']) self.assertEqual(tk1_lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED) wf_svc.handle_action_execution_completion(tk1_ac_ex_db) wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) self.assertEqual(wf_ex_db.status, wf_statuses.FAILED) # Assert log task is scheduled even though the workflow execution failed manually. query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'log'} tk2_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk2_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk2_ex_db.id))[0] tk2_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk2_ac_ex_db.liveaction['id']) self.assertEqual(tk2_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) wf_svc.handle_action_execution_completion(tk2_ac_ex_db) wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) self.assertEqual(wf_ex_db.status, wf_statuses.FAILED) # Check errors and output. expected_errors = [ { 'task_id': 'fail', 'type': 'error', 'message': 'Execution failed. See result for details.' }, { 'task_id': 'task1', 'type': 'error', 'message': 'Execution failed. See result for details.', 'result': { 'failed': True, 'return_code': 1, 'stderr': '', 'stdout': '', 'succeeded': False } } ] self.assertListEqual(self.sort_wf_runtime_errors(wf_ex_db.errors), expected_errors)
def test_notify_task_list_item_value(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'sequential.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db.notify = notify_api_models.NotificationsHelper.to_model(MOCK_NOTIFY) expected_schema_success_test_cases = [ [], ['task1'], ['task1', 'task2'] ] for notify_tasks in expected_schema_success_test_cases: lv_ac_db.parameters = {'notify': notify_tasks} lv_ac_db, ac_ex_db = action_service.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, action_constants.LIVEACTION_STATUS_RUNNING)
def test_delay_for_with_items(self): expected_delay_sec = 1 expected_delay_msec = expected_delay_sec * 1000 wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'with-items-delay.yaml') wf_input = {'delay': expected_delay_sec} lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'], parameters=wf_input) lv_ac_db, ac_ex_db = action_service.request(lv_ac_db) # Assert action execution is running. lv_ac_db = self._wait_on_status(lv_ac_db, action_constants.LIVEACTION_STATUS_RUNNING) wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0] self.assertEqual(wf_ex_db.status, action_constants.LIVEACTION_STATUS_RUNNING) # Process the with items task. query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'task1'} t1_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] t1_ac_ex_dbs = ex_db_access.ActionExecution.query(task_execution=str(t1_ex_db.id)) t1_lv_ac_dbs = lv_db_access.LiveAction.query(task_execution=str(t1_ex_db.id)) # Assert delay value is rendered and assigned. self.assertEqual(t1_ex_db.delay, expected_delay_sec) for t1_lv_ac_db in t1_lv_ac_dbs: self.assertEqual(t1_lv_ac_db.delay, expected_delay_msec) for t1_ac_ex_db in t1_ac_ex_dbs: self.assertEqual(t1_ac_ex_db.delay, expected_delay_msec) status = [ ac_ex.status == action_constants.LIVEACTION_STATUS_SUCCEEDED for ac_ex in t1_ac_ex_dbs ] self.assertTrue(all(status)) for t1_ac_ex_db in t1_ac_ex_dbs: workflows.get_engine().process(t1_ac_ex_db) t1_ex_db = wf_db_access.TaskExecution.get_by_id(t1_ex_db.id) self.assertEqual(t1_ex_db.status, wf_statuses.SUCCEEDED) # Assert the main workflow is completed. wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) self.assertEqual(wf_ex_db.status, wf_statuses.SUCCEEDED) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, action_constants.LIVEACTION_STATUS_SUCCEEDED)
def test_fail_task_publish(self): expected_errors = [ { 'type': 'error', 'message': ( 'YaqlEvaluationException: Unable to evaluate expression ' '\'<% foobar() %>\'. NoFunctionRegisteredException: ' 'Unknown function "foobar"' ), 'task_transition_id': 'task2__t0', 'task_id': 'task1', 'route': 0 } ] expected_result = {'output': None, 'errors': expected_errors} wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'fail-task-publish.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) # Assert task1 is already completed. wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0] tk_ex_db = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id))[0] tk_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk_ex_db.id))[0] tk_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk_ac_ex_db.liveaction['id']) self.assertEqual(tk_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) # Manually handle action execution completion for task1 which has an error in publish. wf_svc.handle_action_execution_completion(tk_ac_ex_db) # Assert task1 succeeded but workflow failed. tk_ex_db = wf_db_access.TaskExecution.get_by_id(tk_ex_db.id) self.assertEqual(tk_ex_db.status, wf_statuses.SUCCEEDED) wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) self.assertEqual(wf_ex_db.status, wf_statuses.FAILED) self.assertListEqual(self.sort_wf_runtime_errors(wf_ex_db.errors), expected_errors) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(lv_ac_db.result, expected_result) ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(ac_ex_db.result, expected_result)
def test_default_notify_task_list(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'notify.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db.notify = notify_api_models.NotificationsHelper.to_model(MOCK_NOTIFY) lv_ac_db, ac_ex_db = action_service.request(lv_ac_db) # Assert action execution is running. lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, action_constants.LIVEACTION_STATUS_RUNNING) wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0] self.assertEqual(wf_ex_db.status, action_constants.LIVEACTION_STATUS_RUNNING) # Check that notify is setup correctly in the db record. expected_notify = { 'config': MOCK_NOTIFY, 'tasks': ['task1', 'task2', 'task3'] } self.assertDictEqual(wf_ex_db.notify, expected_notify)
def test_no_retry_policy_applied_on_task_failure(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'subworkflow.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING, lv_ac_db.result) # Identify the records for the main workflow. wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0] tk_ex_dbs = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id)) self.assertEqual(len(tk_ex_dbs), 1) # Identify the records for the tasks. t1_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk_ex_dbs[0].id))[0] t1_wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(t1_ac_ex_db.id))[0] self.assertEqual(t1_ac_ex_db.status, ac_const.LIVEACTION_STATUS_RUNNING) self.assertEqual(t1_wf_ex_db.status, wf_statuses.RUNNING) # Ensure there is only one execution for the task. tk_ac_ref = TEST_PACK + '.' + 'sequential' self.assertEqual(len(lv_db_access.LiveAction.query(action=tk_ac_ref)), 1) # Fail the subtask of the subworkflow. t1_t1_ex_db = wf_db_access.TaskExecution.query(workflow_execution=str(t1_wf_ex_db.id))[0] t1_t1_lv_ac_db = lv_db_access.LiveAction.query(task_execution=str(t1_t1_ex_db.id))[0] ac_svc.update_status(t1_t1_lv_ac_db, ac_const.LIVEACTION_STATUS_FAILED) t1_t1_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(t1_t1_ex_db.id))[0] self.assertEqual(t1_t1_ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED) notifier.get_notifier().process(t1_t1_ac_ex_db) workflows.get_engine().process(t1_t1_ac_ex_db) # Ensure the task execution is not retried. self.assertEqual(len(lv_db_access.LiveAction.query(action=tk_ac_ref)), 1) # Process the failure of the subworkflow. t1_ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(t1_ac_ex_db.id)) self.assertEqual(t1_ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED) workflows.get_engine().process(t1_ac_ex_db) # Assert the main workflow is completed. ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED)
def test_fail_task_execution(self): expected_errors = [ { 'type': 'error', 'message': 'Execution failed. See result for details.', 'task_id': 'task1', 'result': { 'stdout': '', 'stderr': 'boom!', 'return_code': 1, 'failed': True, 'succeeded': False } } ] expected_result = {'output': None, 'errors': expected_errors} wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'fail-task-execution.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) # Process task1. wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0] tk1_ex_db = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id))[0] tk1_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk1_ex_db.id))[0] tk1_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk1_ac_ex_db.liveaction['id']) self.assertEqual(tk1_lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED) wf_svc.handle_action_execution_completion(tk1_ac_ex_db) # Assert workflow state and result. wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(str(wf_ex_db.id)) self.assertEqual(wf_ex_db.status, wf_statuses.FAILED) self.assertListEqual(self.sort_wf_runtime_errors(wf_ex_db.errors), expected_errors) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(lv_ac_db.result, expected_result) ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(ac_ex_db.result, expected_result)
def test_fail_task_transition(self): expected_errors = [ { 'message': ( "Unable to resolve key 'foobar' in expression " "'<% succeeded() and result().foobar %>' from context." ), 'task_transition_id': 'task2__0', 'task_id': 'task1' } ] expected_result = {'output': None, 'errors': expected_errors} wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'fail-task-transition.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) # Assert task1 is already completed. wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0] tk_ex_db = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id))[0] tk_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk_ex_db.id))[0] tk_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk_ac_ex_db.liveaction['id']) self.assertEqual(tk_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) # Manually handle action execution completion for task1 which has an error in publish. wf_svc.handle_action_execution_completion(tk_ac_ex_db) # Assert task1 succeeded but workflow failed. tk_ex_db = wf_db_access.TaskExecution.get_by_id(tk_ex_db.id) self.assertEqual(tk_ex_db.status, wf_states.SUCCEEDED) wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) self.assertEqual(wf_ex_db.status, wf_states.FAILED) self.assertListEqual(self.sort_wf_runtime_errors(wf_ex_db.errors), expected_errors) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(lv_ac_db.result, expected_result) ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertDictEqual(ac_ex_db.result, expected_result)
def test_runtime_context(self): wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'runtime-context.yaml') lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name']) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_RUNNING, lv_ac_db.result) # Identify the records for the workflow. wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0] t1_ex_db = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id))[0] t1_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(t1_ex_db.id))[0] # Complete the worklfow. wf_svc.handle_action_execution_completion(t1_ac_ex_db) t1_ex_db = wf_db_access.TaskExecution.get_by_id(str(t1_ex_db.id)) wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(str(wf_ex_db.id)) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) self.assertEqual(t1_ex_db.status, wf_statuses.SUCCEEDED) self.assertEqual(wf_ex_db.status, wf_statuses.SUCCEEDED) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED) # Check result. expected_st2_ctx = { 'action_execution_id': str(ac_ex_db.id), 'api_url': 'http://127.0.0.1/v1', 'user': '******', 'pack': 'orquesta_tests' } expected_st2_ctx_with_wf_ex_id = copy.deepcopy(expected_st2_ctx) expected_st2_ctx_with_wf_ex_id['workflow_execution_id'] = str(wf_ex_db.id) expected_output = { 'st2_ctx_at_input': expected_st2_ctx, 'st2_ctx_at_vars': expected_st2_ctx, 'st2_ctx_at_publish': expected_st2_ctx_with_wf_ex_id, 'st2_ctx_at_output': expected_st2_ctx_with_wf_ex_id } expected_result = {'output': expected_output} self.assertDictEqual(lv_ac_db.result, expected_result)
def test_fail_incorrect_output_schema(self): wf_meta = base.get_wf_fixture_meta_data( TEST_PACK_PATH, 'sequential_with_broken_schema.yaml' ) wf_input = {'who': 'Thanos'} lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'], parameters=wf_input) lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) wf_ex_dbs = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id)) wf_ex_db = wf_ex_dbs[0] query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'task1'} tk1_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk1_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk1_ex_db.id))[0] wf_svc.handle_action_execution_completion(tk1_ac_ex_db) tk1_ex_db = wf_db_access.TaskExecution.get_by_id(tk1_ex_db.id) wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'task2'} tk2_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk2_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk2_ex_db.id))[0] wf_svc.handle_action_execution_completion(tk2_ac_ex_db) tk2_ex_db = wf_db_access.TaskExecution.get_by_id(tk2_ex_db.id) wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) query_filters = {'workflow_execution': str(wf_ex_db.id), 'task_id': 'task3'} tk3_ex_db = wf_db_access.TaskExecution.query(**query_filters)[0] tk3_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk3_ex_db.id))[0] wf_svc.handle_action_execution_completion(tk3_ac_ex_db) wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id) lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id)) ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id)) self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED) self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED) expected_result = { 'error': "Additional properties are not allowed", 'message': 'Error validating output. See error output for more details.' } self.assertIn(expected_result['error'], ac_ex_db.result['error']) self.assertEqual(expected_result['message'], ac_ex_db.result['message'])