def test_callback_resuming_state(self): local_runner_cls = self.get_runner_class('local_runner', 'local_shell_command_runner') local_run_result = (action_constants.LIVEACTION_STATUS_RESUMING, NON_EMPTY_RESULT, None) local_runner_cls.run = mock.Mock(return_value=local_run_result) local_resume_result = (action_constants.LIVEACTION_STATUS_RUNNING, NON_EMPTY_RESULT, None) local_runner_cls.resume = mock.Mock(return_value=local_resume_result) liveaction = LiveActionDB( action='core.local', parameters={'cmd': 'uname -a'}, callback={ 'source': MISTRAL_RUNNER_NAME, 'url': 'http://127.0.0.1:8989/v2/action_executions/12345' }) liveaction, execution = action_service.request(liveaction) liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, local_resume_result[0]) self.assertFalse( action_executions.ActionExecutionManager.update.called)
def test_chain_runner_typed_system_params(self, request): action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack) kvps = [] try: kvps.append( KeyValuePair.add_or_update(KeyValuePairDB(name='a', value='1'))) kvps.append( KeyValuePair.add_or_update( KeyValuePairDB(name='a.b.c', value='two'))) chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_SYSTEM_PARAMS chain_runner.action = ACTION_2 chain_runner.liveaction = LiveActionDB(action=action_ref) chain_runner.pre_run() chain_runner.run({}) self.assertNotEqual(chain_runner.chain_holder.actionchain, None) expected_value = {'inttype': 1, 'strtype': 'two'} mock_args, _ = request.call_args self.assertEqual(mock_args[0].parameters, expected_value) finally: for kvp in kvps: KeyValuePair.delete(kvp)
def test_resume(self): # Launch the workflow execution. liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS) liveaction, execution = action_service.request(liveaction) liveaction = self._wait_on_status( liveaction, action_constants.LIVEACTION_STATUS_RUNNING) mistral_context = liveaction.context.get('mistral', None) self.assertIsNotNone(mistral_context) self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id')) self.assertEqual(mistral_context['workflow_name'], WF1_EXEC.get('workflow_name')) # Pause the workflow execution. requester = cfg.CONF.system_user.user liveaction, execution = action_service.request_pause( liveaction, requester) executions.ExecutionManager.update.assert_called_with( WF1_EXEC.get('id'), 'PAUSED') liveaction = self._wait_on_status( liveaction, action_constants.LIVEACTION_STATUS_PAUSING) # Manually update the liveaction from pausing to paused. The paused state # is usually updated by the mistral querier. action_service.update_status(liveaction, action_constants.LIVEACTION_STATUS_PAUSED) liveaction = self._wait_on_status( liveaction, action_constants.LIVEACTION_STATUS_PAUSED) # Resume the workflow execution. liveaction, execution = action_service.request_resume( liveaction, requester) executions.ExecutionManager.update.assert_called_with( WF1_EXEC.get('id'), 'RUNNING') liveaction = self._wait_on_status( liveaction, action_constants.LIVEACTION_STATUS_RUNNING)
def test_callback_success_state(self): local_runner_cls = self.get_runner_class('local_runner', 'local_shell_command_runner') local_run_result = (action_constants.LIVEACTION_STATUS_SUCCEEDED, NON_EMPTY_RESULT, None) local_runner_cls.run = mock.Mock(return_value=local_run_result) expected_mistral_status = self.status_map[local_run_result[0]] liveaction = LiveActionDB( action='core.local', parameters={'cmd': 'uname -a'}, callback={ 'source': MISTRAL_RUNNER_NAME, 'url': 'http://127.0.0.1:8989/v2/action_executions/12345' }) liveaction, execution = action_service.request(liveaction) liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_SUCCEEDED) action_executions.ActionExecutionManager.update.assert_called_with( '12345', state=expected_mistral_status, output=NON_EMPTY_RESULT)
def test_update_liveaction_with_incorrect_output_schema(self): liveaction_db = LiveActionDB() liveaction_db.status = 'initializing' liveaction_db.start_timestamp = get_datetime_utc_now() liveaction_db.action = ResourceReference( name=ActionDBUtilsTestCase.action_db.name, pack=ActionDBUtilsTestCase.action_db.pack).ref params = { 'actionstr': 'foo', 'some_key_that_aint_exist_in_action_or_runner': 'bar', 'runnerint': 555 } liveaction_db.parameters = params runner = mock.MagicMock() runner.output_schema = { "notaparam": { "type": "boolean" } } liveaction_db.runner = runner liveaction_db = LiveAction.add_or_update(liveaction_db) origliveaction_db = copy.copy(liveaction_db) now = get_datetime_utc_now() status = 'succeeded' result = 'Work is done.' context = {'third_party_id': uuid.uuid4().hex} newliveaction_db = action_db_utils.update_liveaction_status( status=status, result=result, context=context, end_timestamp=now, liveaction_id=liveaction_db.id) self.assertEqual(origliveaction_db.id, newliveaction_db.id) self.assertEqual(newliveaction_db.status, status) self.assertEqual(newliveaction_db.result, result) self.assertDictEqual(newliveaction_db.context, context) self.assertEqual(newliveaction_db.end_timestamp, now)
def test_liveaction_crud_no_notify(self): created = LiveActionDB() created.action = "core.local" created.description = "" created.status = "running" created.parameters = {} saved = LiveActionModelTest._save_liveaction(created) retrieved = LiveAction.get_by_id(saved.id) self.assertEqual(saved.action, retrieved.action, "Same triggertype was not returned.") self.assertEqual(retrieved.notify, None) # Test update self.assertIsNone(retrieved.end_timestamp) retrieved.end_timestamp = date_utils.get_datetime_utc_now() updated = LiveAction.add_or_update(retrieved) self.assertTrue(updated.end_timestamp == retrieved.end_timestamp) # Test delete LiveActionModelTest._delete([retrieved]) try: retrieved = LiveAction.get_by_id(saved.id) except StackStormDBObjectNotFoundError: retrieved = None self.assertIsNone(retrieved, "managed to retrieve after failure.")
def _invoke_action(action_exec_spec, params, context=None): """ Schedule an action execution. :type action_exec_spec: :class:`ActionExecutionSpecDB` :param params: Parameters to execute the action with. :type params: ``dict`` :rtype: :class:`LiveActionDB` on successful schedueling, None otherwise. """ action_ref = action_exec_spec['ref'] # prior to shipping off the params cast them to the right type. params = action_param_utils.cast_params(action_ref, params) liveaction = LiveActionDB(action=action_ref, context=context, parameters=params) liveaction, _ = action_service.request(liveaction) if liveaction.status == action_constants.LIVEACTION_STATUS_REQUESTED: return liveaction else: return None
def test_chained_executions(self): liveaction = LiveActionDB(action="executions.chain") liveaction, _ = action_service.request(liveaction) liveaction = self._wait_on_status( liveaction, action_constants.LIVEACTION_STATUS_FAILED) execution = self._get_action_execution(liveaction__id=str( liveaction.id), raise_exception=True) action = action_utils.get_action_by_ref("executions.chain") self.assertDictEqual(execution.action, vars(ActionAPI.from_model(action))) runner = RunnerType.get_by_name(action.runner_type["name"]) self.assertDictEqual(execution.runner, vars(RunnerTypeAPI.from_model(runner))) liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(execution.start_timestamp, liveaction.start_timestamp) # NOTE: Timestamp of liveaction and execution may be a bit different, depending on how long # it takes to persist each object in the database self.assertEqual( execution.end_timestamp.replace(microsecond=0), liveaction.end_timestamp.replace(microsecond=0), ) self.assertEqual(execution.result, liveaction.result) self.assertEqual(execution.status, liveaction.status) self.assertEqual(execution.context, liveaction.context) self.assertEqual(execution.liveaction["callback"], liveaction.callback) self.assertEqual(execution.liveaction["action"], liveaction.action) self.assertGreater(len(execution.children), 0) for child in execution.children: record = ActionExecution.get(id=child, raise_exception=True) self.assertEqual(record.parent, str(execution.id)) self.assertEqual(record.action["name"], "local") self.assertEqual(record.runner["name"], "local-shell-cmd")
def test_notify_triggers(self): liveaction_db = LiveActionDB(action='core.local') liveaction_db.id = bson.ObjectId() liveaction_db.description = '' liveaction_db.status = 'succeeded' liveaction_db.parameters = {} on_success = NotificationSubSchema(message='Action succeeded.') on_failure = NotificationSubSchema(message='Action failed.') liveaction_db.notify = NotificationSchema(on_success=on_success, on_failure=on_failure) liveaction_db.start_timestamp = date_utils.get_datetime_utc_now() liveaction_db.end_timestamp = \ (liveaction_db.start_timestamp + datetime.timedelta(seconds=50)) LiveAction.add_or_update(liveaction_db) execution = MOCK_EXECUTION execution.liveaction = vars(LiveActionAPI.from_model(liveaction_db)) execution.status = liveaction_db.status dispatcher = NotifierTestCase.MockDispatcher(self) notifier = Notifier(connection=None, queues=[], trigger_dispatcher=dispatcher) notifier.process(execution)
def test_chain_runner_dependent_results_param(self, request): chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_DEP_RESULTS_INPUT chain_runner.action = ACTION_1 action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack) chain_runner.liveaction = LiveActionDB(action=action_ref) chain_runner.pre_run() chain_runner.run({'s1': 1}) self.assertNotEqual(chain_runner.chain_holder.actionchain, None) expected_values = [{ u'p1': u'1' }, { u'p1': u'1' }, { u'out': u"{'c2': {'o1': '1'}, 'c1': {'o1': '1'}}" }] # Each of the call_args must be one of self.assertEqual(request.call_count, 3) for call_args in request.call_args_list: self.assertTrue(call_args[0][0].parameters in expected_values) expected_values.remove(call_args[0][0].parameters) self.assertEqual(len(expected_values), 0, 'Not all expected values received.')
def test_launch_workflow_with_st2_auth(self): MistralRunner.entry_point = mock.PropertyMock(return_value=WF1_YAML_FILE_PATH) liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS, context=ACTION_CONTEXT) liveaction, execution = action_service.request(liveaction) liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING) mistral_context = liveaction.context.get('mistral', None) self.assertIsNotNone(mistral_context) self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id')) self.assertEqual(mistral_context['workflow_name'], WF1_EXEC.get('workflow_name')) workflow_input = copy.deepcopy(ACTION_PARAMS) workflow_input.update({'count': '3'}) env = { 'st2_execution_id': str(execution.id), 'st2_liveaction_id': str(liveaction.id), '__actions': { 'st2.action': { 'st2_context': { 'auth_token': TOKEN_DB.token, 'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions', 'parent': { 'user': liveaction.context['user'], 'execution_id': str(execution.id) }, 'notify': {}, 'skip_notify_tasks': [] } } } } executions.ExecutionManager.create.assert_called_with( WF1_NAME, workflow_input=workflow_input, env=env)
def test_notify_triggers_jinja_patterns(self, dispatch): liveaction = LiveActionDB(action='core.local') liveaction.description = '' liveaction.status = 'succeeded' liveaction.parameters = {'cmd': 'mamma mia', 'runner_foo': 'foo'} on_success = NotificationSubSchema(message='Command {{action_parameters.cmd}} succeeded.', data={'stdout': '{{action_results.stdout}}'}) liveaction.notify = NotificationSchema(on_success=on_success) liveaction.start_timestamp = date_utils.get_datetime_utc_now() liveaction.end_timestamp = liveaction.start_timestamp + datetime.timedelta(seconds=50) notifier = Notifier(connection=None, queues=[]) notifier.process(liveaction) exp = {'status': 'succeeded', 'start_timestamp': isotime.format(liveaction.start_timestamp), 'route': 'notify.default', 'runner_ref': 'run-local-cmd', 'channel': 'notify.default', 'message': u'Command mamma mia succeeded.', 'data': {'result': '{}', 'stdout': 'stuff happens'}, 'action_ref': u'core.local', 'execution_id': str(MOCK_EXECUTION.id), 'end_timestamp': isotime.format(liveaction.end_timestamp)} dispatch.assert_called_once_with('core.st2.generic.notifytrigger', payload=exp, trace_context={}) notifier.process(liveaction)
def test_chain_runner_publish(self, request): chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_WITH_PUBLISH chain_runner.action = ACTION_2 action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack) chain_runner.liveaction = LiveActionDB(action=action_ref) chain_runner.runner_parameters = {'display_published': True} chain_runner.pre_run() action_parameters = {'action_param_1': 'test value 1'} _, result, _ = chain_runner.run(action_parameters=action_parameters) # We also assert that the action parameters are available in the # "publish" scope self.assertNotEqual(chain_runner.chain_holder.actionchain, None) expected_value = {'inttype': 1, 'strtype': 'published', 'booltype': True, 'published_action_param': action_parameters['action_param_1']} mock_args, _ = request.call_args self.assertEqual(mock_args[0].parameters, expected_value) # Assert that the variables are correctly published self.assertEqual(result['published'], {'published_action_param': u'test value 1', 'o1': u'published'})
def test_chain_runner_failure_during_param_rendering_multiple_tasks(self, request): # Parameter rendering should result in a top level error which aborts # the whole chain chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_SECOND_TASK_RENDER_FAIL_PATH chain_runner.action = ACTION_1 action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack) chain_runner.liveaction = LiveActionDB(action=action_ref) chain_runner.pre_run() status, result, _ = chain_runner.run({}) # Verify that only first task has ran self.assertEqual(status, LIVEACTION_STATUS_FAILED) self.assertEqual(len(result['tasks']), 1) self.assertEqual(result['tasks'][0]['name'], 'c1') expected_error = ('Failed rendering value for action parameter "p1" in ' 'task "c2" (template string={{s1}}):') self.assertTrue('error' in result) self.assertTrue('traceback' in result) self.assertTrue('Failed to run task "c2". Parameter rendering failed' in result['error']) self.assertTrue(expected_error in result['error']) self.assertTrue('Traceback' in result['traceback'])
def test_chain_runner_publish_param_rendering_failure(self, request): # Parameter rendering should result in a top level error which aborts # the whole chain chain_runner = acr.get_runner() chain_runner.entry_point = CHAIN_WITH_PUBLISH_PARAM_RENDERING_FAILURE chain_runner.action = ACTION_1 action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack) chain_runner.liveaction = LiveActionDB(action=action_ref) chain_runner.pre_run() try: chain_runner.run({}) except ParameterRenderingFailedException as e: # TODO: Should we treat this as task error? Right now it bubbles all # the way up and it's not really consistent with action param # rendering failure expected_error = ( 'Failed rendering value for publish parameter "p1" in ' 'task "c2" (template string={{ not_defined }}):') self.assertTrue(expected_error in str(e)) pass else: self.fail('Exception was not thrown')
def test_callback_retry(self): local_runner_cls = self.get_runner_class('local_runner') local_run_result = (action_constants.LIVEACTION_STATUS_SUCCEEDED, NON_EMPTY_RESULT, None) local_runner_cls.run = mock.Mock(return_value=local_run_result) liveaction = LiveActionDB( action='core.local', parameters={'cmd': 'uname -a'}, callback={ 'source': MISTRAL_RUNNER_NAME, 'url': 'http://127.0.0.1:8989/v2/action_executions/12345' }) liveaction, execution = action_service.request(liveaction) liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_SUCCEEDED) calls = [ call('12345', state='SUCCESS', output=NON_EMPTY_RESULT) for i in range(0, 2) ] action_executions.ActionExecutionManager.update.assert_has_calls(calls)
def test_req_nonexistent_action(self): parameters = {'hosts': '127.0.0.1', 'cmd': 'uname -a'} action_ref = ResourceReference(name='i.action', pack='default').ref ex = LiveActionDB(action=action_ref, parameters=parameters) self.assertRaises(ValueError, action_service.request, ex)
def test_chain_cancel_cascade_to_parent_workflow(self): # A temp file is created during test setup. Ensure the temp file exists. # The test action chain will stall until this file is deleted. This gives # the unit test a moment to run any test related logic. path = self.temp_file_path self.assertTrue(os.path.exists(path)) action = TEST_PACK + '.' + 'test_cancel_with_subworkflow' params = {'tempfile': path, 'message': 'foobar'} liveaction = LiveActionDB(action=action, parameters=params) liveaction, execution = action_service.request(liveaction) liveaction = LiveAction.get_by_id(str(liveaction.id)) # Wait until the liveaction is running. liveaction = self._wait_on_status( liveaction, action_constants.LIVEACTION_STATUS_RUNNING) # Wait for subworkflow to register. execution = self._wait_for_children(execution) self.assertEqual(len(execution.children), 1) # Wait until the subworkflow is running. task1_exec = ActionExecution.get_by_id(execution.children[0]) task1_live = LiveAction.get_by_id(task1_exec.liveaction['id']) task1_live = self._wait_on_status( task1_live, action_constants.LIVEACTION_STATUS_RUNNING) # Request subworkflow to cancel. task1_live, task1_exec = action_service.request_cancellation( task1_live, USERNAME) # Wait until the subworkflow is canceling. task1_exec = ActionExecution.get_by_id(execution.children[0]) task1_live = LiveAction.get_by_id(task1_exec.liveaction['id']) task1_live = self._wait_on_status( task1_live, action_constants.LIVEACTION_STATUS_CANCELING) # Delete the temporary file that the action chain is waiting on. os.remove(path) self.assertFalse(os.path.exists(path)) # Wait until the subworkflow is canceled. task1_exec = ActionExecution.get_by_id(execution.children[0]) task1_live = LiveAction.get_by_id(task1_exec.liveaction['id']) task1_live = self._wait_on_status( task1_live, action_constants.LIVEACTION_STATUS_CANCELED) # Wait until the parent liveaction is canceled. liveaction = self._wait_on_status( liveaction, action_constants.LIVEACTION_STATUS_CANCELED) self.assertEqual(len(execution.children), 1) # Wait for non-blocking threads to complete. Ensure runner is not running. MockLiveActionPublisherNonBlocking.wait_all() # Check liveaction result. self.assertIn('tasks', liveaction.result) self.assertEqual(len(liveaction.result['tasks']), 1) subworkflow = liveaction.result['tasks'][0] self.assertEqual(len(subworkflow['result']['tasks']), 1) self.assertEqual(subworkflow['state'], action_constants.LIVEACTION_STATUS_CANCELED)
def test_req_override_runner_parameter_type_attribute_no_value_changed( self): parameters = {'hosts': '127.0.0.1', 'cmd': 'uname -a'} req = LiveActionDB(action=ACTION_OVR_PARAM_BAD_ATTR_NOOP_REF, parameters=parameters) req, _ = action_service.request(req)
def test_req_optional_parameter_none_value_no_default(self): parameters = {"hosts": "127.0.0.1", "cmd": "uname -a", "arg_default_type": None} req = LiveActionDB(action=ACTION_REF, parameters=parameters) req, _ = action_service.request(req)
def test_req_nonexistent_action(self): parameters = {"hosts": "127.0.0.1", "cmd": "uname -a"} action_ref = ResourceReference(name="i.action", pack="default").ref ex = LiveActionDB(action=action_ref, parameters=parameters) self.assertRaises(ValueError, action_service.request, ex)
def test_launch_workflow_mistral_offline(self): liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS) liveaction, execution = action_service.request(liveaction) liveaction = self._wait_on_status( liveaction, action_constants.LIVEACTION_STATUS_FAILED) self.assertIn('Connection refused', liveaction.result['error'])
def test_req_invalid_parameters(self): parameters = {"hosts": "127.0.0.1", "cmd": "uname -a", "arg_default_value": 123} liveaction = LiveActionDB(action=ACTION_REF, parameters=parameters) self.assertRaises( jsonschema.ValidationError, action_service.request, liveaction )
"k1": "v1", "k2": "v2", "k3": 3, "k4": True, "k5": { "foo": "bar" }, "k6": [1, 3], } MOCK_TRIGGER_INSTANCE_4 = TriggerInstanceDB() MOCK_TRIGGER_INSTANCE_4.id = "triggerinstance-test4" MOCK_TRIGGER_INSTANCE_4.payload = MOCK_TRIGGER_INSTANCE_PAYLOAD MOCK_TRIGGER_INSTANCE_4.occurrence_time = date_utils.get_datetime_utc_now() MOCK_LIVEACTION = LiveActionDB() MOCK_LIVEACTION.id = "liveaction-test-1.id" MOCK_LIVEACTION.status = "requested" MOCK_EXECUTION = ActionExecutionDB() MOCK_EXECUTION.id = "exec-test-1.id" MOCK_EXECUTION.status = "requested" FAILURE_REASON = "fail!" class BaseRuleEnforcerTestCase(DbTestCase): models = None @classmethod
def test_launch_workflow_under_parent_chain_with_jinja_parameters(self): ac_ctx = { 'chain': { 'parameters': { 'var1': 'foobar', 'var2': '{{foobar}}', 'var3': ['{{foo}}', '{{bar}}'], 'var4': { 'foobar': '{{foobar}}' }, } } } liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS, context=ac_ctx) liveaction, execution = action_service.request(liveaction) liveaction = self._wait_on_status( liveaction, action_constants.LIVEACTION_STATUS_RUNNING) mistral_context = liveaction.context.get('mistral', None) self.assertIsNotNone(mistral_context) self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id')) self.assertEqual(mistral_context['workflow_name'], WF1_EXEC.get('workflow_name')) workflow_input = copy.deepcopy(ACTION_PARAMS) workflow_input.update({'count': '3'}) env = { 'st2_execution_id': str(execution.id), 'st2_liveaction_id': str(liveaction.id), 'st2_action_api_url': 'http://0.0.0.0:9101/v1', '__actions': { 'st2.action': { 'st2_context': { 'api_url': 'http://0.0.0.0:9101/v1', 'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions', 'parent': { 'pack': 'mistral_tests', 'execution_id': str(execution.id), 'chain': { 'parameters': { 'var1': 'foobar', 'var2': '{% raw %}{{foobar}}{% endraw %}', 'var3': [ '{% raw %}{{foo}}{% endraw %}', '{% raw %}{{bar}}{% endraw %}' ], 'var4': { 'foobar': '{% raw %}{{foobar}}{% endraw %}' } } } }, 'notify': {}, 'skip_notify_tasks': [] } } } } executions.ExecutionManager.create.assert_called_with( WF1_NAME, workflow_input=workflow_input, env=env, notify=NOTIFY)
def test_launch_workbook_with_many_workflows_no_default(self): liveaction = LiveActionDB(action=WB3_NAME, parameters=ACTION_PARAMS) liveaction, execution = action_service.request(liveaction) liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_FAILED) self.assertIn('Default workflow cannot be determined.', liveaction.result['error'])
def test_launch_workflow_with_many_workflows(self): liveaction = LiveActionDB(action=WF2_NAME, parameters=ACTION_PARAMS) liveaction, execution = action_service.request(liveaction) liveaction = LiveAction.get_by_id(str(liveaction.id)) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_FAILED) self.assertIn('Multiple workflows is not supported.', liveaction.result['error'])
MOCK_CHILD_ACTIONEXECUTION_SUCCEEDED = ActionExecutionDB( action={'ref': 'mock.task'}, runner={'name': 'local-shell-cmd'}, liveaction={'id': uuid.uuid4().hex}, status=action_constants.LIVEACTION_STATUS_SUCCEEDED, children=[]) MOCK_CHILD_ACTIONEXECUTION_PAUSED = ActionExecutionDB( action={'ref': 'mock.task'}, runner={'name': 'mistral_v2'}, liveaction={'id': uuid.uuid4().hex}, status=action_constants.LIVEACTION_STATUS_PAUSED, children=[]) MOCK_LIVEACTION_RUNNING = LiveActionDB( action='mock.workflow', status=action_constants.LIVEACTION_STATUS_RUNNING) MOCK_ACTIONEXECUTION_RUNNING_CHILD_REQUESTED = ActionExecutionDB( action={'ref': 'mock.workflow'}, runner={'name': 'mistral_v2'}, liveaction={'id': MOCK_LIVEACTION_RUNNING.id}, status=action_constants.LIVEACTION_STATUS_RUNNING, children=[MOCK_CHILD_ACTIONEXECUTION_REQUESTED.id]) MOCK_ACTIONEXECUTION_RUNNING_CHILD_RUNNING = ActionExecutionDB( action={'ref': 'mock.workflow'}, runner={'name': 'mistral_v2'}, liveaction={'id': MOCK_LIVEACTION_RUNNING.id}, status=action_constants.LIVEACTION_STATUS_RUNNING, children=[MOCK_CHILD_ACTIONEXECUTION_RUNNING.id])
def test_chain_pause_resume_last_task_failed_with_no_next_task(self): # A temp file is created during test setup. Ensure the temp file exists. # The test action chain will stall until this file is deleted. This gives # the unit test a moment to run any test related logic. path = self.temp_file_path self.assertTrue(os.path.exists(path)) action = TEST_PACK + '.' + 'test_pause_resume_last_task_failed_with_no_next_task' params = {'tempfile': path, 'message': 'foobar'} liveaction = LiveActionDB(action=action, parameters=params) liveaction, execution = action_service.request(liveaction) liveaction = LiveAction.get_by_id(str(liveaction.id)) # Wait until the liveaction is running. liveaction = self._wait_for_status( liveaction, action_constants.LIVEACTION_STATUS_RUNNING) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING) # Request action chain to pause. liveaction, execution = action_service.request_pause( liveaction, USERNAME) # Wait until the liveaction is pausing. liveaction = self._wait_for_status( liveaction, action_constants.LIVEACTION_STATUS_PAUSING) extra_info = str(liveaction) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_PAUSING, extra_info) # Delete the temporary file that the action chain is waiting on. os.remove(path) self.assertFalse(os.path.exists(path)) # Wait until the liveaction is paused. liveaction = self._wait_for_status( liveaction, action_constants.LIVEACTION_STATUS_PAUSED) extra_info = str(liveaction) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_PAUSED, extra_info) # Wait for non-blocking threads to complete. Ensure runner is not running. MockLiveActionPublisherNonBlocking.wait_all() # Request action chain to resume. liveaction, execution = action_service.request_resume( liveaction, USERNAME) # Wait until the liveaction is completed. liveaction = self._wait_for_status( liveaction, action_constants.LIVEACTION_STATUS_FAILED) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_FAILED) # Wait for non-blocking threads to complete. MockLiveActionPublisherNonBlocking.wait_all() # Check liveaction result. self.assertIn('tasks', liveaction.result) self.assertEqual(len(liveaction.result['tasks']), 1) self.assertEqual(liveaction.result['tasks'][0]['state'], action_constants.LIVEACTION_STATUS_FAILED)
def test_chain_pause_resume_status_change(self): """Tests context_result is updated when last task's status changes between pause and resume """ # A temp file is created during test setup. Ensure the temp file exists. # The test action chain will stall until this file is deleted. This gives # the unit test a moment to run any test related logic. path = self.temp_file_path self.assertTrue(os.path.exists(path)) action = TEST_PACK + '.' + 'test_pause_resume_context_result' params = {'tempfile': path} liveaction = LiveActionDB(action=action, parameters=params) liveaction, execution = action_service.request(liveaction) liveaction = LiveAction.get_by_id(str(liveaction.id)) # This workflow runs 'core.ask' so will pause on its own. We just need to # wait until the liveaction is pausing. liveaction = self._wait_for_status( liveaction, action_constants.LIVEACTION_STATUS_PAUSING) extra_info = str(liveaction) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_PAUSING, extra_info) # Delete the temporary file that the action chain is waiting on. os.remove(path) self.assertFalse(os.path.exists(path)) # Wait until the liveaction is paused. liveaction = self._wait_for_status( liveaction, action_constants.LIVEACTION_STATUS_PAUSED) extra_info = str(liveaction) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_PAUSED, extra_info) # Wait for non-blocking threads to complete. Ensure runner is not running. MockLiveActionPublisherNonBlocking.wait_all() last_task_liveaction_id = liveaction.result['tasks'][-1][ 'liveaction_id'] action_utils.update_liveaction_status( status=action_constants.LIVEACTION_STATUS_SUCCEEDED, result={'foo': 'bar'}, liveaction_id=last_task_liveaction_id) # Request action chain to resume. liveaction, execution = action_service.request_resume( liveaction, USERNAME) # Wait until the liveaction is completed. liveaction = self._wait_for_status( liveaction, action_constants.LIVEACTION_STATUS_SUCCEEDED) self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_SUCCEEDED) # Wait for non-blocking threads to complete. MockLiveActionPublisherNonBlocking.wait_all() # Check liveaction result. self.assertIn('tasks', liveaction.result) self.assertEqual(len(liveaction.result['tasks']), 2) self.assertEqual(liveaction.result['tasks'][0]['result']['foo'], 'bar')