Skip to content

Commit

Permalink
simplify test bash session in favor of runtime test
Browse files Browse the repository at this point in the history
  • Loading branch information
xingyaoww committed Nov 19, 2024
1 parent 153a501 commit 796a100
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 74 deletions.
90 changes: 90 additions & 0 deletions tests/runtime/test_bash.py
Original file line number Diff line number Diff line change
Expand Up @@ -593,3 +593,93 @@ def test_ansi_escape_codes(temp_dir, runtime_cls, run_as_openhands):
assert 'Red Text' in obs.content
finally:
_close_test_runtime(runtime)


def test_command_output_continuation(temp_dir, runtime_cls, run_as_openhands):
runtime = _load_runtime(temp_dir, runtime_cls, run_as_openhands)
try:
# Start a command that produces output slowly
action = CmdRunAction('for i in {1..5}; do echo $i; sleep 3; done')
action.timeout = 2 # Set timeout to 2 seconds
obs = runtime.run_action(action)
assert obs.content.strip() == '1'
assert obs.metadata.prefix == ''
assert '[The command timed out after 2 seconds.' in obs.metadata.suffix

# Continue watching output
action = CmdRunAction('')
action.timeout = 2
obs = runtime.run_action(action)
assert '[Command output continued from previous command]' in obs.metadata.prefix
assert obs.content.strip() == '2'
assert '[The command timed out after 2 seconds.' in obs.metadata.suffix

# Continue until completion
for expected in ['3', '4', '5']:
action = CmdRunAction('')
action.timeout = 2
obs = runtime.run_action(action)
assert (
'[Command output continued from previous command]'
in obs.metadata.prefix
)
assert obs.content.strip() == expected
assert '[The command timed out after 2 seconds.' in obs.metadata.suffix

# Final empty command to complete
action = CmdRunAction('')
obs = runtime.run_action(action)
assert '[The command completed with exit code 0.]' in obs.metadata.suffix
finally:
_close_test_runtime(runtime)


def test_long_running_command_follow_by_execute(
temp_dir, runtime_cls, run_as_openhands
):
runtime = _load_runtime(temp_dir, runtime_cls, run_as_openhands)
try:
# Test command that produces output slowly
action = CmdRunAction('for i in {1..3}; do echo $i; sleep 3; done')
action.timeout = 2
action.blocking = False
obs = runtime.run_action(action)
assert '1' in obs.content # First number should appear before timeout
assert obs.metadata.exit_code == -1 # -1 indicates command is still running
assert '[The command timed out after 2 seconds.' in obs.metadata.suffix
assert obs.metadata.prefix == ''

# Continue watching output
action = CmdRunAction('')
action.timeout = 2
obs = runtime.run_action(action)
assert '2' in obs.content
assert (
obs.metadata.prefix == '[Command output continued from previous command]\n'
)
assert '[The command timed out after 2 seconds.' in obs.metadata.suffix
assert obs.metadata.exit_code == -1 # -1 indicates command is still running

# Test command that produces no output
action = CmdRunAction('sleep 15')
action.timeout = 2
obs = runtime.run_action(action)
assert '3' in obs.content
assert (
obs.metadata.prefix == '[Command output continued from previous command]\n'
)
assert '[The command timed out after 2 seconds.' in obs.metadata.suffix
assert obs.metadata.exit_code == -1 # -1 indicates command is still running
finally:
_close_test_runtime(runtime)


def test_empty_command_errors(temp_dir, runtime_cls, run_as_openhands):
runtime = _load_runtime(temp_dir, runtime_cls, run_as_openhands)
try:
# Test empty command without previous command
obs = runtime.run_action(CmdRunAction(''))
assert isinstance(obs, ErrorObservation)
assert 'No previous command to continue from' in obs.content
finally:
_close_test_runtime(runtime)
74 changes: 0 additions & 74 deletions tests/unit/test_bash_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

from openhands.core.logger import openhands_logger as logger
from openhands.events.action import CmdRunAction
from openhands.events.observation import ErrorObservation
from openhands.runtime.utils.bash import BashCommandStatus, BashSession


Expand Down Expand Up @@ -54,14 +53,6 @@ def test_basic_command():
assert obs.metadata.prefix == ''
assert session.prev_status == BashCommandStatus.COMPLETED

# Test command with special characters
obs = session.execute(CmdRunAction("echo 'hello world with\nspecial chars'"))
assert 'hello world with\nspecial chars' in obs.content
assert obs.metadata.suffix == '\n\n[The command completed with exit code 0.]'
assert obs.metadata.prefix == ''
assert obs.metadata.exit_code == 0
assert session.prev_status == BashCommandStatus.COMPLETED

# Test multiple commands in sequence
obs = session.execute(CmdRunAction('echo "first" && echo "second" && echo "third"'))
assert 'first\nsecond\nthird' in obs.content
Expand Down Expand Up @@ -251,21 +242,6 @@ def test_empty_command_errors():
session.close()


def test_env_command():
session = BashSession(work_dir=os.getcwd())

# Test empty command without previous command
obs = session.execute(CmdRunAction('env'))
logger.info(obs, extra={'msg_type': 'OBSERVATION'})
assert 'PS1="\n###PS1JSON###' in obs.content or 'PS1=\n###PS1JSON###' in obs.content
assert 'PS2=' in obs.content
assert obs.metadata.exit_code == 0
assert obs.metadata.prefix == ''
assert obs.metadata.suffix == '\n\n[The command completed with exit code 0.]'
assert session.prev_status == BashCommandStatus.COMPLETED
session.close()


def test_command_output_continuation():
session = BashSession(work_dir=os.getcwd(), no_change_timeout_seconds=2)

Expand Down Expand Up @@ -360,53 +336,3 @@ def test_multiline_command():
assert obs.metadata.suffix == '\n\n[The command completed with exit code 0.]'

session.close()


def test_multiple_multiline_commands():
session = BashSession(work_dir=os.getcwd())
try:
cmds = [
'ls -l',
'echo -e "hello\nworld"',
"""echo -e "hello it's me\"""",
"""echo \\
-e 'hello' \\
-v""",
"""echo -e 'hello\\nworld\\nare\\nyou\\nthere?'""",
"""echo -e 'hello\nworld\nare\nyou\n\nthere?'""",
"""echo -e 'hello\nworld "'""",
]
joined_cmds = '\n'.join(cmds)

# Test that running multiple commands at once fails
obs = session.execute(CmdRunAction(joined_cmds))
logger.info(obs, extra={'msg_type': 'OBSERVATION'})
assert isinstance(obs, ErrorObservation)
assert 'Cannot execute multiple commands at once' in obs.content

# Now run each command individually and verify they work
results = []
for cmd in cmds:
obs = session.execute(CmdRunAction(cmd))
logger.info(obs, extra={'msg_type': 'OBSERVATION'})
assert obs.metadata.exit_code == 0
assert obs.metadata.prefix == ''
assert (
obs.metadata.suffix == '\n\n[The command completed with exit code 0.]'
)
results.append(obs.content)

# Verify all expected outputs are present
assert 'total' in results[0] # ls -l
assert 'hello\nworld' in results[1] # echo -e "hello\nworld"
assert "hello it's me" in results[2] # echo -e "hello it\'s me"
assert 'hello -v' in results[3] # echo -e 'hello' -v
assert (
'hello\nworld\nare\nyou\nthere?' in results[4]
) # echo -e 'hello\nworld\nare\nyou\nthere?'
assert (
'hello\nworld\nare\nyou\n\nthere?' in results[5]
) # echo -e with literal newlines
assert 'hello\nworld "' in results[6] # echo -e with quote
finally:
session.close()

0 comments on commit 796a100

Please sign in to comment.