def test_python_action_wrapper_script_doesnt_get_added_to_sys_path(self): # Validate that the directory where python_action_wrapper.py script is located # (st2common/runners) doesn't get added to sys.path runner = python_runner.get_runner() runner.action = self._get_mock_action_obj() runner.runner_parameters = {} runner.entry_point = PATHS_ACTION_PATH runner.container_service = service.RunnerContainerService() runner.pre_run() (status, output, _) = runner.run({}) self.assertEqual(status, LIVEACTION_STATUS_SUCCEEDED) self.assertTrue(output is not None) lines = output['stdout'].split('\n') process_sys_path = lines[0] process_pythonpath = lines[1] assert 'sys.path' in process_sys_path assert 'PYTHONPATH' in process_pythonpath wrapper_script_path = 'st2common/runners' assertion_msg = 'Found python wrapper script path in subprocess path' self.assertTrue(wrapper_script_path not in process_sys_path, assertion_msg) self.assertTrue(wrapper_script_path not in process_pythonpath, assertion_msg)
def _get_mock_runner_obj(self): runner = python_runner.get_runner() runner.execution = MOCK_EXECUTION runner.action = self._get_mock_action_obj() runner.runner_parameters = {} return runner
def test_simple_action_no_entry_point(self): runner = python_runner.get_runner() runner.action = self._get_mock_action_obj() runner.runner_parameters = {} runner.entry_point = '' runner.container_service = service.RunnerContainerService() expected_msg = 'Action .*? is missing entry_point attribute' self.assertRaisesRegexp(Exception, expected_msg, runner.run, {})
def test_exception_in_simple_action_with_invalid_status(self): runner = python_runner.get_runner() runner.action = self._get_mock_action_obj() runner.runner_parameters = {} runner.entry_point = PASCAL_ROW_ACTION_PATH runner.container_service = service.RunnerContainerService() runner.pre_run() self.assertRaises(ValueError, runner.run, action_parameters={'row_index': 'd'})
def test_simple_action_fail(self): runner = python_runner.get_runner() runner.action = self._get_mock_action_obj() runner.runner_parameters = {} runner.entry_point = PASCAL_ROW_ACTION_PATH runner.container_service = service.RunnerContainerService() runner.pre_run() (status, result, _) = runner.run({'row_index': '4'}) self.assertTrue(result is not None) self.assertEqual(status, LIVEACTION_STATUS_FAILED)
def test_simple_action_no_file(self): runner = python_runner.get_runner() runner.action = self._get_mock_action_obj() runner.runner_parameters = {} runner.entry_point = 'foo.py' runner.container_service = service.RunnerContainerService() runner.pre_run() (status, result, _) = runner.run({}) self.assertTrue(result is not None) self.assertEqual(status, LIVEACTION_STATUS_FAILED)
def test_action_with_same_module_name_as_module_in_stdlib(self): runner = python_runner.get_runner() runner.action = self._get_mock_action_obj() runner.runner_parameters = {} runner.entry_point = TEST_ACTION_PATH runner.container_service = service.RunnerContainerService() runner.pre_run() (status, output, _) = runner.run({}) self.assertEqual(status, LIVEACTION_STATUS_SUCCEEDED) self.assertTrue(output is not None) self.assertEqual(output['result'], 'test action')
def test_simple_action_with_status_failed(self): runner = python_runner.get_runner() runner.action = self._get_mock_action_obj() runner.runner_parameters = {} runner.entry_point = PASCAL_ROW_ACTION_PATH runner.container_service = service.RunnerContainerService() runner.pre_run() (status, output, _) = runner.run({'row_index': 'a'}) self.assertEqual(status, LIVEACTION_STATUS_FAILED) self.assertTrue(output is not None) self.assertEqual(output['result'], "This is suppose to fail don't worry!!")
def test_simple_action_with_result_no_status(self): runner = python_runner.get_runner() runner.action = self._get_mock_action_obj() runner.runner_parameters = {} runner.entry_point = PASCAL_ROW_ACTION_PATH runner.container_service = service.RunnerContainerService() runner.pre_run() (status, output, _) = runner.run({'row_index': 5}) self.assertEqual(status, LIVEACTION_STATUS_SUCCEEDED) self.assertTrue(output is not None) self.assertEqual(output['result'], [1, 5, 10, 10, 5, 1])
def test_simple_action_with_status_succeeded(self): runner = python_runner.get_runner() runner.action = self._get_mock_action_obj() runner.runner_parameters = {} runner.entry_point = PASCAL_ROW_ACTION_PATH runner.container_service = service.RunnerContainerService() runner.pre_run() (status, output, _) = runner.run({'row_index': 4}) self.assertEqual(status, LIVEACTION_STATUS_SUCCEEDED) self.assertTrue(output is not None) self.assertEqual(output['result'], [1, 4, 6, 4, 1])
def test_simple_action_with_status_complex_type_returned_for_result(self): # Result containing a complex type shouldn't break the returning a tuple with status # behavior runner = python_runner.get_runner() runner.action = self._get_mock_action_obj() runner.runner_parameters = {} runner.entry_point = PASCAL_ROW_ACTION_PATH runner.container_service = service.RunnerContainerService() runner.pre_run() (status, output, _) = runner.run({'row_index': 'complex_type'}) self.assertEqual(status, LIVEACTION_STATUS_FAILED) self.assertTrue(output is not None) self.assertTrue('<pascal_row.PascalRowAction object at' in output['result'])
def test_simple_action_timeout(self): timeout = 0 runner = python_runner.get_runner() runner.action = self._get_mock_action_obj() runner.runner_parameters = {python_runner.RUNNER_TIMEOUT: timeout} runner.entry_point = PASCAL_ROW_ACTION_PATH runner.container_service = service.RunnerContainerService() runner.pre_run() (status, output, _) = runner.run({'row_index': 4}) self.assertEqual(status, LIVEACTION_STATUS_TIMED_OUT) self.assertTrue(output is not None) self.assertEqual(output['result'], 'None') self.assertEqual(output['error'], 'Action failed to complete in 0 seconds') self.assertEqual(output['exit_code'], -9)
def test_simple_action_with_status_complex_type_returned_for_result(self): # Result containing a complex type shouldn't break the returning a tuple with status # behavior runner = python_runner.get_runner() runner.action = self._get_mock_action_obj() runner.runner_parameters = {} runner.entry_point = PASCAL_ROW_ACTION_PATH runner.container_service = service.RunnerContainerService() runner.pre_run() (status, output, _) = runner.run({'row_index': 'complex_type'}) self.assertEqual(status, LIVEACTION_STATUS_FAILED) self.assertTrue(output is not None) self.assertTrue( '<pascal_row.PascalRowAction object at' in output['result'])
def test_common_st2_env_vars_are_available_to_the_action(self, mock_popen): mock_process = mock.Mock() mock_process.communicate.return_value = ('', '') mock_popen.return_value = mock_process runner = python_runner.get_runner() runner.auth_token = mock.Mock() runner.auth_token.token = 'ponies' runner.action = self._get_mock_action_obj() runner.runner_parameters = {} runner.entry_point = PASCAL_ROW_ACTION_PATH runner.container_service = service.RunnerContainerService() runner.pre_run() (_, _, _) = runner.run({'row_index': 4}) _, call_kwargs = mock_popen.call_args actual_env = call_kwargs['env'] self.assertCommonSt2EnvVarsAvailableInEnv(env=actual_env)
def test_action_returns_non_serializable_result(self): # Actions returns non-simple type which can't be serialized, verify result is simple str() # representation of the result runner = python_runner.get_runner() runner.action = self._get_mock_action_obj() runner.runner_parameters = {} runner.entry_point = NON_SIMPLE_TYPE_ACTION runner.container_service = service.RunnerContainerService() runner.pre_run() (status, output, _) = runner.run({}) self.assertEqual(status, LIVEACTION_STATUS_SUCCEEDED) self.assertTrue(output is not None) expected_result_re = (r"\[{'a': '1'}, {'h': 3, 'c': 2}, {'e': " "<non_simple_type.Test object at .*?>}\]") match = re.match(expected_result_re, output['result']) self.assertTrue(match)
def test_action_with_user_supplied_env_vars(self, mock_popen): env_vars = {'key1': 'val1', 'key2': 'val2', 'PYTHONPATH': 'foobar'} mock_process = mock.Mock() mock_process.communicate.return_value = ('', '') mock_popen.return_value = mock_process runner = python_runner.get_runner() runner.action = self._get_mock_action_obj() runner.runner_parameters = {'env': env_vars} runner.entry_point = PASCAL_ROW_ACTION_PATH runner.container_service = service.RunnerContainerService() runner.pre_run() (_, _, _) = runner.run({'row_index': 4}) _, call_kwargs = mock_popen.call_args actual_env = call_kwargs['env'] for key, value in env_vars.items(): # Verify that a blacklsited PYTHONPATH has been filtered out if key == 'PYTHONPATH': self.assertTrue(actual_env[key] != value) else: self.assertEqual(actual_env[key], value)
def test_runner_creation(self): runner = python_runner.get_runner() self.assertTrue(runner is not None, 'Creation failed. No instance.') self.assertEqual(type(runner), python_runner.PythonRunner, 'Creation failed. No instance.')
def test_stdout_interception_and_parsing(self, mock_popen): values = {'delimiter': ACTION_OUTPUT_RESULT_DELIMITER} # No output to stdout and no result (implicit None) mock_stdout = '%(delimiter)sNone%(delimiter)s' % values mock_stderr = 'foo stderr' mock_process = mock.Mock() mock_process.communicate.return_value = (mock_stdout, mock_stderr) mock_process.returncode = 0 mock_popen.return_value = mock_process runner = python_runner.get_runner() runner.action = self._get_mock_action_obj() runner.runner_parameters = {} runner.entry_point = PASCAL_ROW_ACTION_PATH runner.container_service = service.RunnerContainerService() runner.pre_run() (_, output, _) = runner.run({'row_index': 4}) self.assertEqual(output['stdout'], '') self.assertEqual(output['stderr'], mock_stderr) self.assertEqual(output['result'], 'None') self.assertEqual(output['exit_code'], 0) # Output to stdout, no result (implicit None),return_code 1 and status # failed mock_stdout = 'pre result%(delimiter)sNone%(delimiter)spost result' % values mock_stderr = 'foo stderr' mock_process = mock.Mock() mock_process.communicate.return_value = (mock_stdout, mock_stderr) mock_process.returncode = 1 mock_popen.return_value = mock_process runner = python_runner.get_runner() runner.action = self._get_mock_action_obj() runner.runner_parameters = {} runner.entry_point = PASCAL_ROW_ACTION_PATH runner.container_service = service.RunnerContainerService() runner.pre_run() (status, output, _) = runner.run({'row_index': 4}) self.assertEqual(output['stdout'], 'pre resultpost result') self.assertEqual(output['stderr'], mock_stderr) self.assertEqual(output['result'], 'None') self.assertEqual(output['exit_code'], 1) self.assertEqual(status, 'failed') # Output to stdout, no result (implicit None), return_code 1 and status # succedded mock_stdout = 'pre result%(delimiter)sNone%(delimiter)spost result' % values mock_stderr = 'foo stderr' mock_process = mock.Mock() mock_process.communicate.return_value = (mock_stdout, mock_stderr) mock_process.returncode = 0 mock_popen.return_value = mock_process runner = python_runner.get_runner() runner.action = self._get_mock_action_obj() runner.runner_parameters = {} runner.entry_point = PASCAL_ROW_ACTION_PATH runner.container_service = service.RunnerContainerService() runner.pre_run() (status, output, _) = runner.run({'row_index': 4}) self.assertEqual(output['stdout'], 'pre resultpost result') self.assertEqual(output['stderr'], mock_stderr) self.assertEqual(output['result'], 'None') self.assertEqual(output['exit_code'], 0) self.assertEqual(status, 'succeeded')