def _insert_mock_stdout_and_stderr_objects_for_execution( self, execution_id, count=5 ): execution_id = str(execution_id) stdout_dbs, stderr_dbs = [], [] for i in range(0, count): stdout_db = ActionExecutionOutputDB( execution_id=execution_id, action_ref="dummy.pack", runner_ref="dummy", output_type="stdout", data="stdout %s" % (i), ) ActionExecutionOutput.add_or_update(stdout_db) stderr_db = ActionExecutionOutputDB( execution_id=execution_id, action_ref="dummy.pack", runner_ref="dummy", output_type="stderr", data="stderr%s" % (i), ) ActionExecutionOutput.add_or_update(stderr_db) return stdout_dbs, stderr_dbs
def test_get_output_finished_execution(self): # Test the execution output API endpoint for execution which has finished for status in action_constants.LIVEACTION_COMPLETED_STATES: # Insert mock execution and output objects status = action_constants.LIVEACTION_STATUS_SUCCEEDED timestamp = date_utils.get_datetime_utc_now() action_execution_db = ActionExecutionDB( start_timestamp=timestamp, end_timestamp=timestamp, status=status, action={"ref": "core.local"}, runner={"name": "local-shell-cmd"}, liveaction={"ref": "foo"}, ) action_execution_db = ActionExecution.add_or_update( action_execution_db) for i in range(1, 6): stdout_db = ActionExecutionOutputDB( execution_id=str(action_execution_db.id), action_ref="core.local", runner_ref="dummy", timestamp=timestamp, output_type="stdout", data="stdout %s\n" % (i), ) ActionExecutionOutput.add_or_update(stdout_db) for i in range(10, 15): stderr_db = ActionExecutionOutputDB( execution_id=str(action_execution_db.id), action_ref="core.local", runner_ref="dummy", timestamp=timestamp, output_type="stderr", data="stderr %s\n" % (i), ) ActionExecutionOutput.add_or_update(stderr_db) resp = self.app.get( "/v1/executions/%s/output" % (str(action_execution_db.id)), expect_errors=False, ) self.assertEqual(resp.status_int, 200) events = self._parse_response(resp.text) self.assertEqual(len(events), 11) self.assertEqual(events[0][1]["data"], "stdout 1\n") self.assertEqual(events[9][1]["data"], "stderr 14\n") self.assertEqual(events[10][0], "EOF") # Verify "last" short-hand id works resp = self.app.get("/v1/executions/last/output", expect_errors=False) self.assertEqual(resp.status_int, 200) events = self._parse_response(resp.text) self.assertEqual(len(events), 11) self.assertEqual(events[10][0], "EOF")
def publish_action_finished(action_execution_db): # Insert mock output object output_params['data'] = 'stdout pre finish 1\n' output_db = ActionExecutionOutputDB(**output_params) ActionExecutionOutput.add_or_update(output_db) # Transition execution to completed state so the connection closes action_execution_db.status = action_constants.LIVEACTION_STATUS_SUCCEEDED action_execution_db = ActionExecution.add_or_update(action_execution_db)
def test_get_output_finished_execution(self): # Test the execution output API endpoint for execution which has finished for status in action_constants.LIVEACTION_COMPLETED_STATES: # Insert mock execution and output objects status = action_constants.LIVEACTION_STATUS_SUCCEEDED timestamp = date_utils.get_datetime_utc_now() action_execution_db = ActionExecutionDB( start_timestamp=timestamp, end_timestamp=timestamp, status=status, action={'ref': 'core.local'}, runner={'name': 'local-shell-cmd'}, liveaction={'ref': 'foo'}) action_execution_db = ActionExecution.add_or_update( action_execution_db) for i in range(1, 6): stdout_db = ActionExecutionOutputDB(execution_id=str( action_execution_db.id), action_ref='core.local', runner_ref='dummy', timestamp=timestamp, output_type='stdout', data='stdout %s\n' % (i)) ActionExecutionOutput.add_or_update(stdout_db) for i in range(10, 15): stderr_db = ActionExecutionOutputDB(execution_id=str( action_execution_db.id), action_ref='core.local', runner_ref='dummy', timestamp=timestamp, output_type='stderr', data='stderr %s\n' % (i)) ActionExecutionOutput.add_or_update(stderr_db) resp = self.app.get('/v1/executions/%s/output' % (str(action_execution_db.id)), expect_errors=False) self.assertEqual(resp.status_int, 200) events = self._parse_response(resp.text) self.assertEqual(len(events), 11) self.assertEqual(events[0][1]['data'], 'stdout 1\n') self.assertEqual(events[9][1]['data'], 'stderr 14\n') self.assertEqual(events[10][0], 'EOF') # Verify "last" short-hand id works resp = self.app.get('/v1/executions/last/output', expect_errors=False) self.assertEqual(resp.status_int, 200) events = self._parse_response(resp.text) self.assertEqual(len(events), 11) self.assertEqual(events[10][0], 'EOF')
def publish_action_finished(action_execution_db): # Insert mock output object output_params['data'] = 'stdout pre finish 1\n' output_db = ActionExecutionOutputDB(**output_params) ActionExecutionOutput.add_or_update(output_db) eventlet.sleep(1.0) # Transition execution to completed state so the connection closes action_execution_db.status = action_constants.LIVEACTION_STATUS_SUCCEEDED action_execution_db = ActionExecution.add_or_update(action_execution_db)
def test_get_output_finished_execution(self): # Test the execution output API endpoint for execution which has finished for status in action_constants.LIVEACTION_COMPLETED_STATES: # Insert mock execution and output objects status = action_constants.LIVEACTION_STATUS_SUCCEEDED timestamp = date_utils.get_datetime_utc_now() action_execution_db = ActionExecutionDB(start_timestamp=timestamp, end_timestamp=timestamp, status=status, action={'ref': 'core.local'}, runner={'name': 'local-shell-cmd'}, liveaction={'ref': 'foo'}) action_execution_db = ActionExecution.add_or_update(action_execution_db) for i in range(1, 6): stdout_db = ActionExecutionOutputDB(execution_id=str(action_execution_db.id), action_ref='core.local', runner_ref='dummy', timestamp=timestamp, output_type='stdout', data='stdout %s\n' % (i)) ActionExecutionOutput.add_or_update(stdout_db) for i in range(10, 15): stderr_db = ActionExecutionOutputDB(execution_id=str(action_execution_db.id), action_ref='core.local', runner_ref='dummy', timestamp=timestamp, output_type='stderr', data='stderr %s\n' % (i)) ActionExecutionOutput.add_or_update(stderr_db) resp = self.app.get('/v1/executions/%s/output' % (str(action_execution_db.id)), expect_errors=False) self.assertEqual(resp.status_int, 200) events = self._parse_response(resp.text) self.assertEqual(len(events), 11) self.assertEqual(events[0][1]['data'], 'stdout 1\n') self.assertEqual(events[9][1]['data'], 'stderr 14\n') self.assertEqual(events[10][0], 'EOF') # Verify "last" short-hand id works resp = self.app.get('/v1/executions/last/output', expect_errors=False) self.assertEqual(resp.status_int, 200) events = self._parse_response(resp.text) self.assertEqual(len(events), 11) self.assertEqual(events[10][0], 'EOF')
def _insert_mock_stdout_and_stderr_objects_for_execution(self, execution_id, count=5): execution_id = str(execution_id) stdout_dbs, stderr_dbs = [], [] for i in range(0, count): stdout_db = ActionExecutionOutputDB(execution_id=execution_id, action_ref='dummy.pack', runner_ref='dummy', output_type='stdout', data='stdout %s' % (i)) ActionExecutionOutput.add_or_update(stdout_db) stderr_db = ActionExecutionOutputDB(execution_id=execution_id, action_ref='dummy.pack', runner_ref='dummy', output_type='stderr', data='stderr%s' % (i)) ActionExecutionOutput.add_or_update(stderr_db) return stdout_dbs, stderr_dbs
def store_execution_output_data_ex( execution_id, action_ref, runner_ref, data, output_type="output", timestamp=None ): timestamp = timestamp or date_utils.get_datetime_utc_now() output_db = ActionExecutionOutputDB( execution_id=execution_id, action_ref=action_ref, runner_ref=runner_ref, timestamp=timestamp, output_type=output_type, data=data, ) output_db = ActionExecutionOutput.add_or_update( output_db, publish=True, dispatch_trigger=False ) return output_db
def store_execution_output_data(execution_db, action_db, data, output_type='output', timestamp=None): """ Store output from an execution as a new document in the collection. """ execution_id = str(execution_db.id) action_ref = action_db.ref runner_ref = getattr(action_db, 'runner_type', {}).get('name', 'unknown') timestamp = timestamp or date_utils.get_datetime_utc_now() output_db = ActionExecutionOutputDB(execution_id=execution_id, action_ref=action_ref, runner_ref=runner_ref, timestamp=timestamp, output_type=output_type, data=data) output_db = ActionExecutionOutput.add_or_update(output_db, publish=True, dispatch_trigger=False) return output_db
def insert_mock_data(): output_params['data'] = 'stdout mid 1\n' output_db = ActionExecutionOutputDB(**output_params) ActionExecutionOutput.add_or_update(output_db)
def test_get_output_running_execution(self): # Retrieve lister instance to avoid race with listener connection not being established # early enough for tests to pass. # NOTE: This only affects tests where listeners are not pre-initialized. listener = get_listener(name='execution_output') eventlet.sleep(1.0) # Test the execution output API endpoint for execution which is running (blocking) status = action_constants.LIVEACTION_STATUS_RUNNING timestamp = date_utils.get_datetime_utc_now() action_execution_db = ActionExecutionDB(start_timestamp=timestamp, end_timestamp=timestamp, status=status, action={'ref': 'core.local'}, runner={'name': 'local-shell-cmd'}, liveaction={'ref': 'foo'}) action_execution_db = ActionExecution.add_or_update(action_execution_db) output_params = dict(execution_id=str(action_execution_db.id), action_ref='core.local', runner_ref='dummy', timestamp=timestamp, output_type='stdout', data='stdout before start\n') # Insert mock output object output_db = ActionExecutionOutputDB(**output_params) ActionExecutionOutput.add_or_update(output_db, publish=False) def insert_mock_data(): output_params['data'] = 'stdout mid 1\n' output_db = ActionExecutionOutputDB(**output_params) ActionExecutionOutput.add_or_update(output_db) # Since the API endpoint is blocking (connection is kept open until action finishes), we # spawn an eventlet which eventually finishes the action. def publish_action_finished(action_execution_db): # Insert mock output object output_params['data'] = 'stdout pre finish 1\n' output_db = ActionExecutionOutputDB(**output_params) ActionExecutionOutput.add_or_update(output_db) eventlet.sleep(1.0) # Transition execution to completed state so the connection closes action_execution_db.status = action_constants.LIVEACTION_STATUS_SUCCEEDED action_execution_db = ActionExecution.add_or_update(action_execution_db) eventlet.spawn_after(0.2, insert_mock_data) eventlet.spawn_after(1.5, publish_action_finished, action_execution_db) # Retrieve data while execution is running - endpoint return new data once it's available # and block until the execution finishes resp = self.app.get('/v1/executions/%s/output' % (str(action_execution_db.id)), expect_errors=False) self.assertEqual(resp.status_int, 200) events = self._parse_response(resp.text) self.assertEqual(len(events), 4) self.assertEqual(events[0][1]['data'], 'stdout before start\n') self.assertEqual(events[1][1]['data'], 'stdout mid 1\n') self.assertEqual(events[2][1]['data'], 'stdout pre finish 1\n') self.assertEqual(events[3][0], 'EOF') # Once the execution is in completed state, existing output should be returned immediately resp = self.app.get('/v1/executions/%s/output' % (str(action_execution_db.id)), expect_errors=False) self.assertEqual(resp.status_int, 200) events = self._parse_response(resp.text) self.assertEqual(len(events), 4) self.assertEqual(events[0][1]['data'], 'stdout before start\n') self.assertEqual(events[1][1]['data'], 'stdout mid 1\n') self.assertEqual(events[2][1]['data'], 'stdout pre finish 1\n') self.assertEqual(events[3][0], 'EOF') listener.shutdown()
def test_garbage_collection(self): now = date_utils.get_datetime_utc_now() status = action_constants.LIVEACTION_STATUS_SUCCEEDED # Insert come mock ActionExecutionDB objects with start_timestamp < TTL defined in the # config old_executions_count = 15 ttl_days = 30 # > 20 timestamp = (now - datetime.timedelta(days=ttl_days)) for index in range(0, old_executions_count): action_execution_db = ActionExecutionDB( start_timestamp=timestamp, end_timestamp=timestamp, status=status, action={'ref': 'core.local'}, runner={'name': 'local-shell-cmd'}, liveaction={'ref': 'foo'}) ActionExecution.add_or_update(action_execution_db) stdout_db = ActionExecutionOutputDB(execution_id=str( action_execution_db.id), action_ref='core.local', runner_ref='dummy', timestamp=timestamp, output_type='stdout', data='stdout') ActionExecutionOutput.add_or_update(stdout_db) stderr_db = ActionExecutionOutputDB(execution_id=str( action_execution_db.id), action_ref='core.local', runner_ref='dummy', timestamp=timestamp, output_type='stderr', data='stderr') ActionExecutionOutput.add_or_update(stderr_db) # Insert come mock ActionExecutionDB objects with start_timestamp > TTL defined in the # config new_executions_count = 5 ttl_days = 2 # < 20 timestamp = (now - datetime.timedelta(days=ttl_days)) for index in range(0, new_executions_count): action_execution_db = ActionExecutionDB( start_timestamp=timestamp, end_timestamp=timestamp, status=status, action={'ref': 'core.local'}, runner={'name': 'local-shell-cmd'}, liveaction={'ref': 'foo'}) ActionExecution.add_or_update(action_execution_db) stdout_db = ActionExecutionOutputDB(execution_id=str( action_execution_db.id), action_ref='core.local', runner_ref='dummy', timestamp=timestamp, output_type='stdout', data='stdout') ActionExecutionOutput.add_or_update(stdout_db) stderr_db = ActionExecutionOutputDB(execution_id=str( action_execution_db.id), action_ref='core.local', runner_ref='dummy', timestamp=timestamp, output_type='stderr', data='stderr') ActionExecutionOutput.add_or_update(stderr_db) # Insert some mock output objects where start_timestamp > action_executions_output_ttl new_output_count = 5 ttl_days = 15 # > 10 and < 20 timestamp = (now - datetime.timedelta(days=ttl_days)) for index in range(0, new_output_count): action_execution_db = ActionExecutionDB( start_timestamp=timestamp, end_timestamp=timestamp, status=status, action={'ref': 'core.local'}, runner={'name': 'local-shell-cmd'}, liveaction={'ref': 'foo'}) ActionExecution.add_or_update(action_execution_db) stdout_db = ActionExecutionOutputDB(execution_id=str( action_execution_db.id), action_ref='core.local', runner_ref='dummy', timestamp=timestamp, output_type='stdout', data='stdout') ActionExecutionOutput.add_or_update(stdout_db) stderr_db = ActionExecutionOutputDB(execution_id=str( action_execution_db.id), action_ref='core.local', runner_ref='dummy', timestamp=timestamp, output_type='stderr', data='stderr') ActionExecutionOutput.add_or_update(stderr_db) execs = ActionExecution.get_all() self.assertEqual( len(execs), (old_executions_count + new_executions_count + new_output_count)) stdout_dbs = ActionExecutionOutput.query(output_type='stdout') self.assertEqual( len(stdout_dbs), (old_executions_count + new_executions_count + new_output_count)) stderr_dbs = ActionExecutionOutput.query(output_type='stderr') self.assertEqual( len(stderr_dbs), (old_executions_count + new_executions_count + new_output_count)) # Start garbage collector process = self._start_garbage_collector() # Give it some time to perform garbage collection and kill it eventlet.sleep(15) process.send_signal(signal.SIGKILL) self.remove_process(process=process) # Old executions and corresponding objects should have been garbage collected execs = ActionExecution.get_all() self.assertEqual(len(execs), (new_executions_count + new_output_count)) # Collection for output objects older than 10 days is also enabled, so those objects # should be deleted as well stdout_dbs = ActionExecutionOutput.query(output_type='stdout') self.assertEqual(len(stdout_dbs), (new_executions_count)) stderr_dbs = ActionExecutionOutput.query(output_type='stderr') self.assertEqual(len(stderr_dbs), (new_executions_count))
def test_garbage_collection(self): now = date_utils.get_datetime_utc_now() status = action_constants.LIVEACTION_STATUS_SUCCEEDED # Insert come mock ActionExecutionDB objects with start_timestamp < TTL defined in the # config old_executions_count = 15 ttl_days = 30 # > 20 timestamp = (now - datetime.timedelta(days=ttl_days)) for index in range(0, old_executions_count): action_execution_db = ActionExecutionDB(start_timestamp=timestamp, end_timestamp=timestamp, status=status, action={'ref': 'core.local'}, runner={'name': 'local-shell-cmd'}, liveaction={'ref': 'foo'}) ActionExecution.add_or_update(action_execution_db) stdout_db = ActionExecutionOutputDB(execution_id=str(action_execution_db.id), action_ref='core.local', runner_ref='dummy', timestamp=timestamp, output_type='stdout', data='stdout') ActionExecutionOutput.add_or_update(stdout_db) stderr_db = ActionExecutionOutputDB(execution_id=str(action_execution_db.id), action_ref='core.local', runner_ref='dummy', timestamp=timestamp, output_type='stderr', data='stderr') ActionExecutionOutput.add_or_update(stderr_db) # Insert come mock ActionExecutionDB objects with start_timestamp > TTL defined in the # config new_executions_count = 5 ttl_days = 2 # < 20 timestamp = (now - datetime.timedelta(days=ttl_days)) for index in range(0, new_executions_count): action_execution_db = ActionExecutionDB(start_timestamp=timestamp, end_timestamp=timestamp, status=status, action={'ref': 'core.local'}, runner={'name': 'local-shell-cmd'}, liveaction={'ref': 'foo'}) ActionExecution.add_or_update(action_execution_db) stdout_db = ActionExecutionOutputDB(execution_id=str(action_execution_db.id), action_ref='core.local', runner_ref='dummy', timestamp=timestamp, output_type='stdout', data='stdout') ActionExecutionOutput.add_or_update(stdout_db) stderr_db = ActionExecutionOutputDB(execution_id=str(action_execution_db.id), action_ref='core.local', runner_ref='dummy', timestamp=timestamp, output_type='stderr', data='stderr') ActionExecutionOutput.add_or_update(stderr_db) # Insert some mock output objects where start_timestamp > action_executions_output_ttl new_output_count = 5 ttl_days = 15 # > 10 and < 20 timestamp = (now - datetime.timedelta(days=ttl_days)) for index in range(0, new_output_count): action_execution_db = ActionExecutionDB(start_timestamp=timestamp, end_timestamp=timestamp, status=status, action={'ref': 'core.local'}, runner={'name': 'local-shell-cmd'}, liveaction={'ref': 'foo'}) ActionExecution.add_or_update(action_execution_db) stdout_db = ActionExecutionOutputDB(execution_id=str(action_execution_db.id), action_ref='core.local', runner_ref='dummy', timestamp=timestamp, output_type='stdout', data='stdout') ActionExecutionOutput.add_or_update(stdout_db) stderr_db = ActionExecutionOutputDB(execution_id=str(action_execution_db.id), action_ref='core.local', runner_ref='dummy', timestamp=timestamp, output_type='stderr', data='stderr') ActionExecutionOutput.add_or_update(stderr_db) execs = ActionExecution.get_all() self.assertEqual(len(execs), (old_executions_count + new_executions_count + new_output_count)) stdout_dbs = ActionExecutionOutput.query(output_type='stdout') self.assertEqual(len(stdout_dbs), (old_executions_count + new_executions_count + new_output_count)) stderr_dbs = ActionExecutionOutput.query(output_type='stderr') self.assertEqual(len(stderr_dbs), (old_executions_count + new_executions_count + new_output_count)) # Start garbage collector process = self._start_garbage_collector() # Give it some time to perform garbage collection and kill it eventlet.sleep(15) process.send_signal(signal.SIGKILL) self.remove_process(process=process) # Old executions and corresponding objects should have been garbage collected execs = ActionExecution.get_all() self.assertEqual(len(execs), (new_executions_count + new_output_count)) # Collection for output objects older than 10 days is also enabled, so those objects # should be deleted as well stdout_dbs = ActionExecutionOutput.query(output_type='stdout') self.assertEqual(len(stdout_dbs), (new_executions_count)) stderr_dbs = ActionExecutionOutput.query(output_type='stderr') self.assertEqual(len(stderr_dbs), (new_executions_count))
def test_get_output_running_execution(self): # Retrieve lister instance to avoid race with listener connection not being established # early enough for tests to pass. # NOTE: This only affects tests where listeners are not pre-initialized. listener = get_listener(name='execution_output') eventlet.sleep(1.0) # Test the execution output API endpoint for execution which is running (blocking) status = action_constants.LIVEACTION_STATUS_RUNNING timestamp = date_utils.get_datetime_utc_now() action_execution_db = ActionExecutionDB( start_timestamp=timestamp, end_timestamp=timestamp, status=status, action={'ref': 'core.local'}, runner={'name': 'local-shell-cmd'}, liveaction={'ref': 'foo'}) action_execution_db = ActionExecution.add_or_update( action_execution_db) output_params = dict(execution_id=str(action_execution_db.id), action_ref='core.local', runner_ref='dummy', timestamp=timestamp, output_type='stdout', data='stdout before start\n') # Insert mock output object output_db = ActionExecutionOutputDB(**output_params) ActionExecutionOutput.add_or_update(output_db, publish=False) def insert_mock_data(): output_params['data'] = 'stdout mid 1\n' output_db = ActionExecutionOutputDB(**output_params) ActionExecutionOutput.add_or_update(output_db) # Since the API endpoint is blocking (connection is kept open until action finishes), we # spawn an eventlet which eventually finishes the action. def publish_action_finished(action_execution_db): # Insert mock output object output_params['data'] = 'stdout pre finish 1\n' output_db = ActionExecutionOutputDB(**output_params) ActionExecutionOutput.add_or_update(output_db) eventlet.sleep(1.0) # Transition execution to completed state so the connection closes action_execution_db.status = action_constants.LIVEACTION_STATUS_SUCCEEDED action_execution_db = ActionExecution.add_or_update( action_execution_db) eventlet.spawn_after(0.2, insert_mock_data) eventlet.spawn_after(1.5, publish_action_finished, action_execution_db) # Retrieve data while execution is running - endpoint return new data once it's available # and block until the execution finishes resp = self.app.get('/v1/executions/%s/output' % (str(action_execution_db.id)), expect_errors=False) self.assertEqual(resp.status_int, 200) events = self._parse_response(resp.text) self.assertEqual(len(events), 4) self.assertEqual(events[0][1]['data'], 'stdout before start\n') self.assertEqual(events[1][1]['data'], 'stdout mid 1\n') self.assertEqual(events[2][1]['data'], 'stdout pre finish 1\n') self.assertEqual(events[3][0], 'EOF') # Once the execution is in completed state, existing output should be returned immediately resp = self.app.get('/v1/executions/%s/output' % (str(action_execution_db.id)), expect_errors=False) self.assertEqual(resp.status_int, 200) events = self._parse_response(resp.text) self.assertEqual(len(events), 4) self.assertEqual(events[0][1]['data'], 'stdout before start\n') self.assertEqual(events[1][1]['data'], 'stdout mid 1\n') self.assertEqual(events[2][1]['data'], 'stdout pre finish 1\n') self.assertEqual(events[3][0], 'EOF') listener.shutdown()
def insert_mock_data(): output_params["data"] = "stdout mid 1\n" output_db = ActionExecutionOutputDB(**output_params) ActionExecutionOutput.add_or_update(output_db)
def test_get_output_running_execution(self): # Test the execution output API endpoint for execution which is running (blocking) status = action_constants.LIVEACTION_STATUS_RUNNING timestamp = date_utils.get_datetime_utc_now() action_execution_db = ActionExecutionDB(start_timestamp=timestamp, end_timestamp=timestamp, status=status, action={'ref': 'core.local'}, runner={'name': 'run-local'}, liveaction={'ref': 'foo'}) action_execution_db = ActionExecution.add_or_update(action_execution_db) output_params = dict(execution_id=str(action_execution_db.id), action_ref='core.local', runner_ref='dummy', timestamp=timestamp, output_type='stdout', data='stdout before start\n') # Insert mock output object output_db = ActionExecutionOutputDB(**output_params) ActionExecutionOutput.add_or_update(output_db) def insert_mock_data(): output_params['data'] = 'stdout mid 1\n' output_db = ActionExecutionOutputDB(**output_params) ActionExecutionOutput.add_or_update(output_db) pass # Since the API endpoint is blocking (connection is kept open until action finishes), we # spawn an eventlet which eventually finishes the action. def publish_action_finished(action_execution_db): # Insert mock output object output_params['data'] = 'stdout pre finish 1\n' output_db = ActionExecutionOutputDB(**output_params) ActionExecutionOutput.add_or_update(output_db) # Transition execution to completed state so the connection closes action_execution_db.status = action_constants.LIVEACTION_STATUS_SUCCEEDED action_execution_db = ActionExecution.add_or_update(action_execution_db) eventlet.spawn_after(0.2, insert_mock_data) eventlet.spawn_after(1.5, publish_action_finished, action_execution_db) resp = self.app.get('/v1/executions/%s/output' % (str(action_execution_db.id)), expect_errors=False) self.assertEqual(resp.status_int, 200) lines = resp.text.strip().split('\n') self.assertEqual(len(lines), 3) self.assertEqual(lines[0], 'stdout before start') self.assertEqual(lines[1], 'stdout mid 1') self.assertEqual(lines[2], 'stdout pre finish 1') # Once the execution is in completed state, existing output should be returned immediately resp = self.app.get('/v1/executions/%s/output' % (str(action_execution_db.id)), expect_errors=False) self.assertEqual(resp.status_int, 200) lines = resp.text.strip().split('\n') self.assertEqual(len(lines), 3) self.assertEqual(lines[0], 'stdout before start') self.assertEqual(lines[1], 'stdout mid 1') self.assertEqual(lines[2], 'stdout pre finish 1')