test_ipython.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import pathlib
  2. import tempfile
  3. from unittest.mock import MagicMock, call, patch
  4. import pytest
  5. from opendevin.core.config import SandboxConfig
  6. from opendevin.events.action import IPythonRunCellAction
  7. from opendevin.events.observation import IPythonRunCellObservation
  8. from opendevin.runtime.docker.ssh_box import DockerSSHBox
  9. from opendevin.runtime.plugins import JupyterRequirement
  10. from opendevin.runtime.server.runtime import ServerRuntime
  11. @pytest.fixture
  12. def temp_dir(monkeypatch):
  13. # get a temporary directory
  14. with tempfile.TemporaryDirectory() as temp_dir:
  15. pathlib.Path().mkdir(parents=True, exist_ok=True)
  16. yield temp_dir
  17. @pytest.mark.asyncio
  18. async def test_run_python_backticks():
  19. # Create a mock event_stream
  20. mock_event_stream = MagicMock()
  21. test_code = "print('Hello, `World`!\n')"
  22. # Mock the asynchronous sandbox execute method
  23. mock_sandbox_execute = MagicMock()
  24. mock_sandbox_execute.side_effect = [
  25. (0, ''), # Initial call during DockerSSHBox initialization
  26. (0, ''), # Initial call during DockerSSHBox initialization
  27. (0, ''), # Initial call during DockerSSHBox initialization
  28. (0, ''), # Write command
  29. (0, test_code), # Execute command
  30. ]
  31. # Set up the patches for the runtime and sandbox
  32. with patch(
  33. 'opendevin.runtime.docker.ssh_box.DockerSSHBox.execute',
  34. new=mock_sandbox_execute,
  35. ):
  36. # Initialize the runtime with the mock event_stream
  37. runtime = ServerRuntime(
  38. sandbox_config=SandboxConfig(box_type='ssh', persist_sandbox=False),
  39. event_stream=mock_event_stream,
  40. )
  41. # Define the test action with a simple IPython command
  42. action = IPythonRunCellAction(code=test_code)
  43. # Call the run_ipython method with the test action
  44. result = await runtime.run_action(action)
  45. # Assert that the result is an instance of IPythonRunCellObservation
  46. assert isinstance(result, IPythonRunCellObservation)
  47. # Assert that the execute method was called with the correct commands
  48. expected_write_command = (
  49. "cat > /tmp/opendevin_jupyter_temp.py <<'EOL'\n" f'{test_code}\n' 'EOL'
  50. )
  51. expected_execute_command = 'cat /tmp/opendevin_jupyter_temp.py | execute_cli'
  52. mock_sandbox_execute.assert_has_calls(
  53. [
  54. call('mkdir -p /tmp'),
  55. call('git config --global user.name "OpenDevin"'),
  56. call('git config --global user.email "opendevin@all-hands.dev"'),
  57. call(expected_write_command),
  58. call(expected_execute_command),
  59. ]
  60. )
  61. assert (
  62. test_code == result.content
  63. ), f'The output should contain the expected print output, got: {result.content}'
  64. def test_sandbox_jupyter_plugin_backticks(temp_dir):
  65. box = DockerSSHBox(
  66. config=SandboxConfig(),
  67. persist_sandbox=False,
  68. workspace_mount_path=temp_dir,
  69. sandbox_workspace_dir='/workspace',
  70. cache_dir='/tmp/cache',
  71. run_as_devin=True,
  72. )
  73. box.init_plugins([JupyterRequirement])
  74. test_code = "print('Hello, `World`!')"
  75. expected_write_command = (
  76. "cat > /tmp/opendevin_jupyter_temp.py <<'EOL'\n" f'{test_code}\n' 'EOL'
  77. )
  78. expected_execute_command = 'cat /tmp/opendevin_jupyter_temp.py | execute_cli'
  79. exit_code, output = box.execute(expected_write_command)
  80. exit_code, output = box.execute(expected_execute_command)
  81. print(output)
  82. assert exit_code == 0, 'The exit code should be 0 for ' + box.__class__.__name__
  83. assert output.strip() == 'Hello, `World`!', (
  84. 'The output should be the same as the input for ' + box.__class__.__name__
  85. )
  86. box.close()