def test_action_stdout_and_stderr_is_stored_in_the_db( self, mock_spawn, mock_popen): # Feature is enabled cfg.CONF.set_override(name="stream_output", group="actionrunner", override=True) values = {"delimiter": ACTION_OUTPUT_RESULT_DELIMITER} # Note: We need to mock spawn function so we can test everything in single event loop # iteration mock_spawn.side_effect = blocking_eventlet_spawn # No output to stdout and no result (implicit None) mock_stdout = [ "pre result line 1\n", "pre result line 2\n", "%(delimiter)sTrue%(delimiter)s" % values, "post result line 1", ] mock_stderr = ["stderr line 1\n", "stderr line 2\n", "stderr line 3\n"] mock_process = mock.Mock() mock_process.returncode = 0 mock_popen.return_value = mock_process mock_process.stdout.closed = False mock_process.stderr.closed = False mock_process.stdout.readline = make_mock_stream_readline( mock_process.stdout, mock_stdout, stop_counter=4) mock_process.stderr.readline = make_mock_stream_readline( mock_process.stderr, mock_stderr, stop_counter=3) runner = self._get_mock_runner_obj() runner.entry_point = PASCAL_ROW_ACTION_PATH runner.pre_run() (_, output, _) = runner.run({"row_index": 4}) self.assertMultiLineEqual( output["stdout"], "pre result line 1\npre result line 2\npost result line 1") self.assertMultiLineEqual( output["stderr"], "stderr line 1\nstderr line 2\nstderr line 3\n") self.assertEqual(output["result"], "True") self.assertEqual(output["exit_code"], 0) # Verify stdout and stderr lines have been correctly stored in the db # Note - result delimiter should not be stored in the db output_dbs = ActionExecutionOutput.query(output_type="stdout") self.assertEqual(len(output_dbs), 3) self.assertEqual(output_dbs[0].runner_ref, "python-script") self.assertEqual(output_dbs[0].data, mock_stdout[0]) self.assertEqual(output_dbs[1].data, mock_stdout[1]) self.assertEqual(output_dbs[2].data, mock_stdout[3]) output_dbs = ActionExecutionOutput.query(output_type="stderr") self.assertEqual(len(output_dbs), 3) self.assertEqual(output_dbs[0].runner_ref, "python-script") self.assertEqual(output_dbs[0].data, mock_stderr[0]) self.assertEqual(output_dbs[1].data, mock_stderr[1]) self.assertEqual(output_dbs[2].data, mock_stderr[2])
def test_action_stdout_and_stderr_is_stored_in_the_db( self, mock_spawn, mock_popen): # Feature is enabled cfg.CONF.set_override(name='stream_output', group='actionrunner', override=True) values = {'delimiter': ACTION_OUTPUT_RESULT_DELIMITER} # Note: We need to mock spawn function so we can test everything in single event loop # iteration mock_spawn.side_effect = blocking_eventlet_spawn # No output to stdout and no result (implicit None) mock_stdout = [ 'pre result line 1\n', 'pre result line 2\n', '%(delimiter)sTrue%(delimiter)s' % values, 'post result line 1' ] mock_stderr = ['stderr line 1\n', 'stderr line 2\n', 'stderr line 3\n'] mock_process = mock.Mock() mock_process.returncode = 0 mock_popen.return_value = mock_process mock_process.stdout.closed = False mock_process.stderr.closed = False mock_process.stdout.readline = make_mock_stream_readline( mock_process.stdout, mock_stdout, stop_counter=4) mock_process.stderr.readline = make_mock_stream_readline( mock_process.stderr, mock_stderr, stop_counter=3) runner = self._get_mock_runner_obj() 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'], 'pre result line 1\npre result line 2\npost result line 1') self.assertEqual(output['stderr'], 'stderr line 1\nstderr line 2\nstderr line 3\n') self.assertEqual(output['result'], 'True') self.assertEqual(output['exit_code'], 0) # Verify stdout and stderr lines have been correctly stored in the db # Note - result delimiter should not be stored in the db output_dbs = ActionExecutionOutput.query(output_type='stdout') self.assertEqual(len(output_dbs), 3) self.assertEqual(output_dbs[0].runner_ref, 'python-script') self.assertEqual(output_dbs[0].data, mock_stdout[0]) self.assertEqual(output_dbs[1].data, mock_stdout[1]) self.assertEqual(output_dbs[2].data, mock_stdout[3]) output_dbs = ActionExecutionOutput.query(output_type='stderr') self.assertEqual(len(output_dbs), 3) self.assertEqual(output_dbs[0].runner_ref, 'python-script') self.assertEqual(output_dbs[0].data, mock_stderr[0]) self.assertEqual(output_dbs[1].data, mock_stderr[1]) self.assertEqual(output_dbs[2].data, mock_stderr[2])
def test_action_stdout_and_stderr_is_stored_in_the_db(self, mock_spawn, mock_popen): # Feature is enabled cfg.CONF.set_override(name='stream_output', group='actionrunner', override=True) values = {'delimiter': ACTION_OUTPUT_RESULT_DELIMITER} # Note: We need to mock spawn function so we can test everything in single event loop # iteration mock_spawn.side_effect = blocking_eventlet_spawn # No output to stdout and no result (implicit None) mock_stdout = [ 'pre result line 1\n', 'pre result line 2\n', '%(delimiter)sTrue%(delimiter)s' % values, 'post result line 1' ] mock_stderr = [ 'stderr line 1\n', 'stderr line 2\n', 'stderr line 3\n' ] mock_process = mock.Mock() mock_process.returncode = 0 mock_popen.return_value = mock_process mock_process.stdout.closed = False mock_process.stderr.closed = False mock_process.stdout.readline = make_mock_stream_readline(mock_process.stdout, mock_stdout, stop_counter=4) mock_process.stderr.readline = make_mock_stream_readline(mock_process.stderr, mock_stderr, stop_counter=3) runner = self._get_mock_runner_obj() runner.entry_point = PASCAL_ROW_ACTION_PATH runner.pre_run() (_, output, _) = runner.run({'row_index': 4}) self.assertEqual(output['stdout'], 'pre result line 1\npre result line 2\npost result line 1') self.assertEqual(output['stderr'], 'stderr line 1\nstderr line 2\nstderr line 3\n') self.assertEqual(output['result'], 'True') self.assertEqual(output['exit_code'], 0) # Verify stdout and stderr lines have been correctly stored in the db # Note - result delimiter should not be stored in the db output_dbs = ActionExecutionOutput.query(output_type='stdout') self.assertEqual(len(output_dbs), 3) self.assertEqual(output_dbs[0].runner_ref, 'python-script') self.assertEqual(output_dbs[0].data, mock_stdout[0]) self.assertEqual(output_dbs[1].data, mock_stdout[1]) self.assertEqual(output_dbs[2].data, mock_stdout[3]) output_dbs = ActionExecutionOutput.query(output_type='stderr') self.assertEqual(len(output_dbs), 3) self.assertEqual(output_dbs[0].runner_ref, 'python-script') self.assertEqual(output_dbs[0].data, mock_stderr[0]) self.assertEqual(output_dbs[1].data, mock_stderr[1]) self.assertEqual(output_dbs[2].data, mock_stderr[2])
def test_action_stdout_and_stderr_is_stored_in_the_db( self, mock_spawn, mock_popen): # Feature is enabled cfg.CONF.set_override(name='stream_output', group='actionrunner', override=True) # Note: We need to mock spawn function so we can test everything in single event loop # iteration mock_spawn.side_effect = blocking_eventlet_spawn # No output to stdout and no result (implicit None) mock_stdout = [ 'stdout line 1\n', 'stdout line 2\n', ] mock_stderr = ['stderr line 1\n', 'stderr line 2\n', 'stderr line 3\n'] mock_process = mock.Mock() mock_process.returncode = 0 mock_popen.return_value = mock_process mock_process.stdout.closed = False mock_process.stderr.closed = False mock_process.stdout.readline = make_mock_stream_readline( mock_process.stdout, mock_stdout, stop_counter=2) mock_process.stderr.readline = make_mock_stream_readline( mock_process.stderr, mock_stderr, stop_counter=3) models = self.fixtures_loader.load_models( fixtures_pack='generic', fixtures_dict={'actions': ['local.yaml']}) action_db = models['actions']['local.yaml'] runner = self._get_runner(action_db, cmd='echo $ST2_ACTION_API_URL') runner.pre_run() status, result, _ = runner.run({}) runner.post_run(status, result) self.assertEquals(status, action_constants.LIVEACTION_STATUS_SUCCEEDED) self.assertEqual(result['stdout'], 'stdout line 1\nstdout line 2') self.assertEqual(result['stderr'], 'stderr line 1\nstderr line 2\nstderr line 3') self.assertEqual(result['return_code'], 0) # Verify stdout and stderr lines have been correctly stored in the db output_dbs = ActionExecutionOutput.query(output_type='stdout') self.assertEqual(len(output_dbs), 2) self.assertEqual(output_dbs[0].data, mock_stdout[0]) self.assertEqual(output_dbs[1].data, mock_stdout[1]) output_dbs = ActionExecutionOutput.query(output_type='stderr') self.assertEqual(len(output_dbs), 3) self.assertEqual(output_dbs[0].data, mock_stderr[0]) self.assertEqual(output_dbs[1].data, mock_stderr[1]) self.assertEqual(output_dbs[2].data, mock_stderr[2])
def test_action_stdout_and_stderr_is_stored_in_the_db(self, mock_spawn, mock_popen): # Feature is enabled cfg.CONF.set_override(name='stream_output', group='actionrunner', override=True) # Note: We need to mock spawn function so we can test everything in single event loop # iteration mock_spawn.side_effect = blocking_eventlet_spawn # No output to stdout and no result (implicit None) mock_stdout = [ 'stdout line 1\n', 'stdout line 2\n', ] mock_stderr = [ 'stderr line 1\n', 'stderr line 2\n', 'stderr line 3\n' ] mock_process = mock.Mock() mock_process.returncode = 0 mock_popen.return_value = mock_process mock_process.stdout.closed = False mock_process.stderr.closed = False mock_process.stdout.readline = make_mock_stream_readline(mock_process.stdout, mock_stdout, stop_counter=2) mock_process.stderr.readline = make_mock_stream_readline(mock_process.stderr, mock_stderr, stop_counter=3) models = self.fixtures_loader.load_models( fixtures_pack='generic', fixtures_dict={'actions': ['local.yaml']}) action_db = models['actions']['local.yaml'] runner = self._get_runner(action_db, cmd='echo $ST2_ACTION_API_URL') runner.pre_run() status, result, _ = runner.run({}) runner.post_run(status, result) self.assertEquals(status, action_constants.LIVEACTION_STATUS_SUCCEEDED) self.assertEqual(result['stdout'], 'stdout line 1\nstdout line 2') self.assertEqual(result['stderr'], 'stderr line 1\nstderr line 2\nstderr line 3') self.assertEqual(result['return_code'], 0) # Verify stdout and stderr lines have been correctly stored in the db output_dbs = ActionExecutionOutput.query(output_type='stdout') self.assertEqual(len(output_dbs), 2) self.assertEqual(output_dbs[0].data, mock_stdout[0]) self.assertEqual(output_dbs[1].data, mock_stdout[1]) output_dbs = ActionExecutionOutput.query(output_type='stderr') self.assertEqual(len(output_dbs), 3) self.assertEqual(output_dbs[0].data, mock_stderr[0]) self.assertEqual(output_dbs[1].data, mock_stderr[1]) self.assertEqual(output_dbs[2].data, mock_stderr[2])
def test_action_stdout_and_stderr_is_stored_in_the_db( self, mock_spawn, mock_popen): # Feature is enabled cfg.CONF.set_override(name='stream_output', group='actionrunner', override=True) # Note: We need to mock spawn function so we can test everything in single event loop # iteration mock_spawn.side_effect = blocking_eventlet_spawn # No output to stdout and no result (implicit None) mock_stdout = [ 'stdout line 1\n', 'stdout line 2\n', 'stdout line 3\n', 'stdout line 4\n' ] mock_stderr = ['stderr line 1\n', 'stderr line 2\n', 'stderr line 3\n'] mock_process = mock.Mock() mock_process.returncode = 0 mock_popen.return_value = mock_process mock_process.stdout.closed = False mock_process.stderr.closed = False mock_process.stdout.readline = make_mock_stream_readline( mock_process.stdout, mock_stdout, stop_counter=4) mock_process.stderr.readline = make_mock_stream_readline( mock_process.stderr, mock_stderr, stop_counter=3) models = self.fixtures_loader.load_models( fixtures_pack='generic', fixtures_dict={'actions': ['local_script_with_params.yaml']}) action_db = models['actions']['local_script_with_params.yaml'] entry_point = os.path.join( get_fixtures_base_path(), 'generic/actions/local_script_with_params.sh') action_parameters = { 'param_string': 'test string', 'param_integer': 1, 'param_float': 2.55, 'param_boolean': True, 'param_list': ['a', 'b', 'c'], 'param_object': { 'foo': 'bar' } } runner = self._get_runner(action_db=action_db, entry_point=entry_point) runner.pre_run() status, result, _ = runner.run(action_parameters=action_parameters) runner.post_run(status, result) self.assertEqual( result['stdout'], 'stdout line 1\nstdout line 2\nstdout line 3\nstdout line 4') self.assertEqual(result['stderr'], 'stderr line 1\nstderr line 2\nstderr line 3') self.assertEqual(result['return_code'], 0) # Verify stdout and stderr lines have been correctly stored in the db output_dbs = ActionExecutionOutput.query(output_type='stdout') self.assertEqual(len(output_dbs), 4) self.assertEqual(output_dbs[0].data, mock_stdout[0]) self.assertEqual(output_dbs[1].data, mock_stdout[1]) self.assertEqual(output_dbs[2].data, mock_stdout[2]) self.assertEqual(output_dbs[3].data, mock_stdout[3]) output_dbs = ActionExecutionOutput.query(output_type='stderr') self.assertEqual(len(output_dbs), 3) self.assertEqual(output_dbs[0].data, mock_stderr[0]) self.assertEqual(output_dbs[1].data, mock_stderr[1]) self.assertEqual(output_dbs[2].data, mock_stderr[2])
def test_action_stdout_and_stderr_is_stored_in_the_db_short_running_action( self, mock_spawn, mock_popen): # Verify that we correctly retrieve all the output and wait for stdout and stderr reading # threads for short running actions. models = self.fixtures_loader.load_models( fixtures_pack='generic', fixtures_dict={'actions': ['local.yaml']}) action_db = models['actions']['local.yaml'] # Feature is enabled cfg.CONF.set_override(name='stream_output', group='actionrunner', override=True) # Note: We need to mock spawn function so we can test everything in single event loop # iteration mock_spawn.side_effect = blocking_eventlet_spawn # No output to stdout and no result (implicit None) mock_stdout = ['stdout line 1\n', 'stdout line 2\n'] mock_stderr = ['stderr line 1\n', 'stderr line 2\n'] # We add a sleep to simulate action process exiting before we finish reading data from mock_process = mock.Mock() mock_process.returncode = 0 mock_popen.return_value = mock_process mock_process.stdout.closed = False mock_process.stderr.closed = False mock_process.stdout.readline = make_mock_stream_readline( mock_process.stdout, mock_stdout, stop_counter=2, sleep_delay=1) mock_process.stderr.readline = make_mock_stream_readline( mock_process.stderr, mock_stderr, stop_counter=2) for index in range(1, 4): mock_process.stdout.closed = False mock_process.stderr.closed = False mock_process.stdout.counter = 0 mock_process.stderr.counter = 0 runner = self._get_runner(action_db, cmd='echo "foobar"') runner.pre_run() status, result, _ = runner.run({}) self.assertEquals(status, action_constants.LIVEACTION_STATUS_SUCCEEDED) self.assertEqual(result['stdout'], 'stdout line 1\nstdout line 2') self.assertEqual(result['stderr'], 'stderr line 1\nstderr line 2') self.assertEqual(result['return_code'], 0) # Verify stdout and stderr lines have been correctly stored in the db output_dbs = ActionExecutionOutput.query(output_type='stdout') if index == 1: db_index_1 = 0 db_index_2 = 1 elif index == 2: db_index_1 = 2 db_index_2 = 3 elif index == 3: db_index_1 = 4 db_index_2 = 5 elif index == 4: db_index_1 = 6 db_index_2 = 7 self.assertEqual(len(output_dbs), (index * 2)) self.assertEqual(output_dbs[db_index_1].data, mock_stdout[0]) self.assertEqual(output_dbs[db_index_2].data, mock_stdout[1]) output_dbs = ActionExecutionOutput.query(output_type='stderr') self.assertEqual(len(output_dbs), (index * 2)) self.assertEqual(output_dbs[db_index_1].data, mock_stderr[0]) self.assertEqual(output_dbs[db_index_2].data, mock_stderr[1])
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.returncode = 0 mock_popen.return_value = mock_process mock_process.stdout.closed = False mock_process.stderr.closed = False mock_process.stdout.readline = make_mock_stream_readline( mock_process.stdout, mock_stdout) mock_process.stderr.readline = make_mock_stream_readline( mock_process.stderr, mock_stderr) runner = self._get_mock_runner_obj() runner.entry_point = PASCAL_ROW_ACTION_PATH runner.pre_run() (_, output, _) = runner.run({'row_index': 4}) self.assertEqual(output['stdout'], '') self.assertEqual(output['stderr'], mock_stderr[0]) 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.returncode = 1 mock_popen.return_value = mock_process mock_process.stdout.closed = False mock_process.stderr.closed = False mock_process.stdout.readline = make_mock_stream_readline( mock_process.stdout, mock_stdout) mock_process.stderr.readline = make_mock_stream_readline( mock_process.stderr, mock_stderr) runner = self._get_mock_runner_obj() runner.entry_point = PASCAL_ROW_ACTION_PATH runner.pre_run() (status, output, _) = runner.run({'row_index': 4}) self.assertEqual(output['stdout'], 'pre resultpost result') self.assertEqual(output['stderr'], mock_stderr[0]) 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 succeeded mock_stdout = [ 'pre result%(delimiter)sNone%(delimiter)spost result' % values ] mock_stderr = ['foo stderr'] mock_process = mock.Mock() mock_process.returncode = 0 mock_popen.return_value = mock_process mock_process.stdout.closed = False mock_process.stderr.closed = False mock_process.stdout.readline = make_mock_stream_readline( mock_process.stdout, mock_stdout) mock_process.stderr.readline = make_mock_stream_readline( mock_process.stderr, mock_stderr) runner = self._get_mock_runner_obj() runner.entry_point = PASCAL_ROW_ACTION_PATH runner.pre_run() (status, output, _) = runner.run({'row_index': 4}) self.assertEqual(output['stdout'], 'pre resultpost result') self.assertEqual(output['stderr'], mock_stderr[0]) self.assertEqual(output['result'], 'None') self.assertEqual(output['exit_code'], 0) self.assertEqual(status, 'succeeded')
def test_action_stdout_and_stderr_is_not_stored_in_db_by_default( self, mock_spawn, mock_popen): # Feature should be disabled by default values = {'delimiter': ACTION_OUTPUT_RESULT_DELIMITER} # Note: We need to mock spawn function so we can test everything in single event loop # iteration mock_spawn.side_effect = blocking_eventlet_spawn # No output to stdout and no result (implicit None) mock_stdout = [ 'pre result line 1\n', '%(delimiter)sTrue%(delimiter)s' % values, 'post result line 1' ] mock_stderr = ['stderr line 1\n', 'stderr line 2\n', 'stderr line 3\n'] mock_process = mock.Mock() mock_process.returncode = 0 mock_popen.return_value = mock_process mock_process.stdout.closed = False mock_process.stderr.closed = False mock_process.stdout.readline = make_mock_stream_readline( mock_process.stdout, mock_stdout, stop_counter=3) mock_process.stderr.readline = make_mock_stream_readline( mock_process.stderr, mock_stderr, stop_counter=3) runner = self._get_mock_runner_obj() runner.entry_point = PASCAL_ROW_ACTION_PATH runner.pre_run() (_, output, _) = runner.run({'row_index': 4}) self.assertEqual(output['stdout'], 'pre result line 1\npost result line 1') self.assertEqual(output['stderr'], 'stderr line 1\nstderr line 2\nstderr line 3\n') self.assertEqual(output['result'], 'True') self.assertEqual(output['exit_code'], 0) output_dbs = ActionExecutionOutput.get_all() self.assertEqual(len(output_dbs), 0) # False is a default behavior so end result should be the same cfg.CONF.set_override(name='stream_output', group='actionrunner', override=False) mock_process = mock.Mock() mock_process.returncode = 0 mock_popen.return_value = mock_process mock_process.stdout.closed = False mock_process.stderr.closed = False mock_process.stdout.readline = make_mock_stream_readline( mock_process.stdout, mock_stdout, stop_counter=3) mock_process.stderr.readline = make_mock_stream_readline( mock_process.stderr, mock_stderr, stop_counter=3) runner.pre_run() (_, output, _) = runner.run({'row_index': 4}) self.assertEqual(output['stdout'], 'pre result line 1\npost result line 1') self.assertEqual(output['stderr'], 'stderr line 1\nstderr line 2\nstderr line 3\n') self.assertEqual(output['result'], 'True') self.assertEqual(output['exit_code'], 0) output_dbs = ActionExecutionOutput.get_all() self.assertEqual(len(output_dbs), 0)
def test_action_stdout_and_stderr_is_stored_in_the_db( self, mock_spawn, mock_popen): # Feature is enabled cfg.CONF.set_override(name="stream_output", group="actionrunner", override=True) # Note: We need to mock spawn function so we can test everything in single event loop # iteration mock_spawn.side_effect = blocking_eventlet_spawn # No output to stdout and no result (implicit None) mock_stdout = [ "stdout line 1\n", "stdout line 2\n", "stdout line 3\n", "stdout line 4\n", ] mock_stderr = ["stderr line 1\n", "stderr line 2\n", "stderr line 3\n"] mock_process = mock.Mock() mock_process.returncode = 0 mock_popen.return_value = mock_process mock_process.stdout.closed = False mock_process.stderr.closed = False mock_process.stdout.readline = make_mock_stream_readline( mock_process.stdout, mock_stdout, stop_counter=4) mock_process.stderr.readline = make_mock_stream_readline( mock_process.stderr, mock_stderr, stop_counter=3) models = self.fixtures_loader.load_models( fixtures_pack="generic", fixtures_dict={"actions": ["local_script_with_params.yaml"]}, ) action_db = models["actions"]["local_script_with_params.yaml"] entry_point = os.path.join( get_fixtures_base_path(), "generic/actions/local_script_with_params.sh") action_parameters = { "param_string": "test string", "param_integer": 1, "param_float": 2.55, "param_boolean": True, "param_list": ["a", "b", "c"], "param_object": { "foo": "bar" }, } runner = self._get_runner(action_db=action_db, entry_point=entry_point) runner.pre_run() status, result, _ = runner.run(action_parameters=action_parameters) runner.post_run(status, result) self.assertEqual( result["stdout"], "stdout line 1\nstdout line 2\nstdout line 3\nstdout line 4", ) self.assertEqual(result["stderr"], "stderr line 1\nstderr line 2\nstderr line 3") self.assertEqual(result["return_code"], 0) # Verify stdout and stderr lines have been correctly stored in the db output_dbs = ActionExecutionOutput.query(output_type="stdout") self.assertEqual(len(output_dbs), 4) self.assertEqual(output_dbs[0].data, mock_stdout[0]) self.assertEqual(output_dbs[1].data, mock_stdout[1]) self.assertEqual(output_dbs[2].data, mock_stdout[2]) self.assertEqual(output_dbs[3].data, mock_stdout[3]) output_dbs = ActionExecutionOutput.query(output_type="stderr") self.assertEqual(len(output_dbs), 3) self.assertEqual(output_dbs[0].data, mock_stderr[0]) self.assertEqual(output_dbs[1].data, mock_stderr[1]) self.assertEqual(output_dbs[2].data, mock_stderr[2])
def test_action_stdout_and_stderr_is_stored_in_the_db(self, mock_spawn, mock_popen): # Feature is enabled cfg.CONF.set_override(name='stream_output', group='actionrunner', override=True) # Note: We need to mock spawn function so we can test everything in single event loop # iteration mock_spawn.side_effect = blocking_eventlet_spawn # No output to stdout and no result (implicit None) mock_stdout = [ 'stdout line 1\n', 'stdout line 2\n', 'stdout line 3\n', 'stdout line 4\n' ] mock_stderr = [ 'stderr line 1\n', 'stderr line 2\n', 'stderr line 3\n' ] mock_process = mock.Mock() mock_process.returncode = 0 mock_popen.return_value = mock_process mock_process.stdout.closed = False mock_process.stderr.closed = False mock_process.stdout.readline = make_mock_stream_readline(mock_process.stdout, mock_stdout, stop_counter=4) mock_process.stderr.readline = make_mock_stream_readline(mock_process.stderr, mock_stderr, stop_counter=3) models = self.fixtures_loader.load_models( fixtures_pack='generic', fixtures_dict={'actions': ['local_script_with_params.yaml']}) action_db = models['actions']['local_script_with_params.yaml'] entry_point = os.path.join(get_fixtures_base_path(), 'generic/actions/local_script_with_params.sh') action_parameters = { 'param_string': 'test string', 'param_integer': 1, 'param_float': 2.55, 'param_boolean': True, 'param_list': ['a', 'b', 'c'], 'param_object': {'foo': 'bar'} } runner = self._get_runner(action_db=action_db, entry_point=entry_point) runner.pre_run() status, result, _ = runner.run(action_parameters=action_parameters) runner.post_run(status, result) self.assertEqual(result['stdout'], 'stdout line 1\nstdout line 2\nstdout line 3\nstdout line 4') self.assertEqual(result['stderr'], 'stderr line 1\nstderr line 2\nstderr line 3') self.assertEqual(result['return_code'], 0) # Verify stdout and stderr lines have been correctly stored in the db output_dbs = ActionExecutionOutput.query(output_type='stdout') self.assertEqual(len(output_dbs), 4) self.assertEqual(output_dbs[0].data, mock_stdout[0]) self.assertEqual(output_dbs[1].data, mock_stdout[1]) self.assertEqual(output_dbs[2].data, mock_stdout[2]) self.assertEqual(output_dbs[3].data, mock_stdout[3]) output_dbs = ActionExecutionOutput.query(output_type='stderr') self.assertEqual(len(output_dbs), 3) self.assertEqual(output_dbs[0].data, mock_stderr[0]) self.assertEqual(output_dbs[1].data, mock_stderr[1]) self.assertEqual(output_dbs[2].data, mock_stderr[2])
def test_action_stdout_and_stderr_is_stored_in_the_db_short_running_action(self, mock_spawn, mock_popen): # Verify that we correctly retrieve all the output and wait for stdout and stderr reading # threads for short running actions. models = self.fixtures_loader.load_models( fixtures_pack='generic', fixtures_dict={'actions': ['local.yaml']}) action_db = models['actions']['local.yaml'] # Feature is enabled cfg.CONF.set_override(name='stream_output', group='actionrunner', override=True) # Note: We need to mock spawn function so we can test everything in single event loop # iteration mock_spawn.side_effect = blocking_eventlet_spawn # No output to stdout and no result (implicit None) mock_stdout = [ 'stdout line 1\n', 'stdout line 2\n' ] mock_stderr = [ 'stderr line 1\n', 'stderr line 2\n' ] # We add a sleep to simulate action process exiting before we finish reading data from mock_process = mock.Mock() mock_process.returncode = 0 mock_popen.return_value = mock_process mock_process.stdout.closed = False mock_process.stderr.closed = False mock_process.stdout.readline = make_mock_stream_readline(mock_process.stdout, mock_stdout, stop_counter=2, sleep_delay=1) mock_process.stderr.readline = make_mock_stream_readline(mock_process.stderr, mock_stderr, stop_counter=2) for index in range(1, 4): mock_process.stdout.closed = False mock_process.stderr.closed = False mock_process.stdout.counter = 0 mock_process.stderr.counter = 0 runner = self._get_runner(action_db, cmd='echo "foobar"') runner.pre_run() status, result, _ = runner.run({}) self.assertEquals(status, action_constants.LIVEACTION_STATUS_SUCCEEDED) self.assertEqual(result['stdout'], 'stdout line 1\nstdout line 2') self.assertEqual(result['stderr'], 'stderr line 1\nstderr line 2') self.assertEqual(result['return_code'], 0) # Verify stdout and stderr lines have been correctly stored in the db output_dbs = ActionExecutionOutput.query(output_type='stdout') if index == 1: db_index_1 = 0 db_index_2 = 1 elif index == 2: db_index_1 = 2 db_index_2 = 3 elif index == 3: db_index_1 = 4 db_index_2 = 5 elif index == 4: db_index_1 = 6 db_index_2 = 7 self.assertEqual(len(output_dbs), (index * 2)) self.assertEqual(output_dbs[db_index_1].data, mock_stdout[0]) self.assertEqual(output_dbs[db_index_2].data, mock_stdout[1]) output_dbs = ActionExecutionOutput.query(output_type='stderr') self.assertEqual(len(output_dbs), (index * 2)) self.assertEqual(output_dbs[db_index_1].data, mock_stderr[0]) self.assertEqual(output_dbs[db_index_2].data, mock_stderr[1])
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.returncode = 0 mock_popen.return_value = mock_process mock_process.stdout.closed = False mock_process.stderr.closed = False mock_process.stdout.readline = make_mock_stream_readline( mock_process.stdout, mock_stdout) mock_process.stderr.readline = make_mock_stream_readline( mock_process.stderr, mock_stderr) runner = self._get_mock_runner_obj() runner.entry_point = PASCAL_ROW_ACTION_PATH runner.pre_run() (_, output, _) = runner.run({"row_index": 4}) self.assertEqual(output["stdout"], "") self.assertEqual(output["stderr"], mock_stderr[0]) 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.returncode = 1 mock_popen.return_value = mock_process mock_process.stdout.closed = False mock_process.stderr.closed = False mock_process.stdout.readline = make_mock_stream_readline( mock_process.stdout, mock_stdout) mock_process.stderr.readline = make_mock_stream_readline( mock_process.stderr, mock_stderr) runner = self._get_mock_runner_obj() runner.entry_point = PASCAL_ROW_ACTION_PATH runner.pre_run() (status, output, _) = runner.run({"row_index": 4}) self.assertEqual(output["stdout"], "pre resultpost result") self.assertEqual(output["stderr"], mock_stderr[0]) 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 succeeded mock_stdout = [ "pre result%(delimiter)sNone%(delimiter)spost result" % values ] mock_stderr = ["foo stderr"] mock_process = mock.Mock() mock_process.returncode = 0 mock_popen.return_value = mock_process mock_process.stdout.closed = False mock_process.stderr.closed = False mock_process.stdout.readline = make_mock_stream_readline( mock_process.stdout, mock_stdout) mock_process.stderr.readline = make_mock_stream_readline( mock_process.stderr, mock_stderr) runner = self._get_mock_runner_obj() runner.entry_point = PASCAL_ROW_ACTION_PATH runner.pre_run() (status, output, _) = runner.run({"row_index": 4}) self.assertEqual(output["stdout"], "pre resultpost result") self.assertEqual(output["stderr"], mock_stderr[0]) self.assertEqual(output["result"], "None") self.assertEqual(output["exit_code"], 0) self.assertEqual(status, "succeeded")
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.returncode = 0 mock_popen.return_value = mock_process mock_process.stdout.closed = False mock_process.stderr.closed = False mock_process.stdout.readline = make_mock_stream_readline(mock_process.stdout, mock_stdout) mock_process.stderr.readline = make_mock_stream_readline(mock_process.stderr, mock_stderr) runner = self._get_mock_runner_obj() runner.entry_point = PASCAL_ROW_ACTION_PATH runner.pre_run() (_, output, _) = runner.run({'row_index': 4}) self.assertEqual(output['stdout'], '') self.assertEqual(output['stderr'], mock_stderr[0]) 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.returncode = 1 mock_popen.return_value = mock_process mock_process.stdout.closed = False mock_process.stderr.closed = False mock_process.stdout.readline = make_mock_stream_readline(mock_process.stdout, mock_stdout) mock_process.stderr.readline = make_mock_stream_readline(mock_process.stderr, mock_stderr) runner = self._get_mock_runner_obj() runner.entry_point = PASCAL_ROW_ACTION_PATH runner.pre_run() (status, output, _) = runner.run({'row_index': 4}) self.assertEqual(output['stdout'], 'pre resultpost result') self.assertEqual(output['stderr'], mock_stderr[0]) 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 succeeded mock_stdout = ['pre result%(delimiter)sNone%(delimiter)spost result' % values] mock_stderr = ['foo stderr'] mock_process = mock.Mock() mock_process.returncode = 0 mock_popen.return_value = mock_process mock_process.stdout.closed = False mock_process.stderr.closed = False mock_process.stdout.readline = make_mock_stream_readline(mock_process.stdout, mock_stdout) mock_process.stderr.readline = make_mock_stream_readline(mock_process.stderr, mock_stderr) runner = self._get_mock_runner_obj() runner.entry_point = PASCAL_ROW_ACTION_PATH runner.pre_run() (status, output, _) = runner.run({'row_index': 4}) self.assertEqual(output['stdout'], 'pre resultpost result') self.assertEqual(output['stderr'], mock_stderr[0]) self.assertEqual(output['result'], 'None') self.assertEqual(output['exit_code'], 0) self.assertEqual(status, 'succeeded')
def test_action_stdout_and_stderr_is_not_stored_in_db_by_default(self, mock_spawn, mock_popen): # Feature should be disabled by default values = {'delimiter': ACTION_OUTPUT_RESULT_DELIMITER} # Note: We need to mock spawn function so we can test everything in single event loop # iteration mock_spawn.side_effect = blocking_eventlet_spawn # No output to stdout and no result (implicit None) mock_stdout = [ 'pre result line 1\n', '%(delimiter)sTrue%(delimiter)s' % values, 'post result line 1' ] mock_stderr = [ 'stderr line 1\n', 'stderr line 2\n', 'stderr line 3\n' ] mock_process = mock.Mock() mock_process.returncode = 0 mock_popen.return_value = mock_process mock_process.stdout.closed = False mock_process.stderr.closed = False mock_process.stdout.readline = make_mock_stream_readline(mock_process.stdout, mock_stdout, stop_counter=3) mock_process.stderr.readline = make_mock_stream_readline(mock_process.stderr, mock_stderr, stop_counter=3) runner = self._get_mock_runner_obj() runner.entry_point = PASCAL_ROW_ACTION_PATH runner.pre_run() (_, output, _) = runner.run({'row_index': 4}) self.assertEqual(output['stdout'], 'pre result line 1\npost result line 1') self.assertEqual(output['stderr'], 'stderr line 1\nstderr line 2\nstderr line 3\n') self.assertEqual(output['result'], 'True') self.assertEqual(output['exit_code'], 0) output_dbs = ActionExecutionOutput.get_all() self.assertEqual(len(output_dbs), 0) # False is a default behavior so end result should be the same cfg.CONF.set_override(name='stream_output', group='actionrunner', override=False) mock_process = mock.Mock() mock_process.returncode = 0 mock_popen.return_value = mock_process mock_process.stdout.closed = False mock_process.stderr.closed = False mock_process.stdout.readline = make_mock_stream_readline(mock_process.stdout, mock_stdout, stop_counter=3) mock_process.stderr.readline = make_mock_stream_readline(mock_process.stderr, mock_stderr, stop_counter=3) runner.pre_run() (_, output, _) = runner.run({'row_index': 4}) self.assertEqual(output['stdout'], 'pre result line 1\npost result line 1') self.assertEqual(output['stderr'], 'stderr line 1\nstderr line 2\nstderr line 3\n') self.assertEqual(output['result'], 'True') self.assertEqual(output['exit_code'], 0) output_dbs = ActionExecutionOutput.get_all() self.assertEqual(len(output_dbs), 0)