test_env.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. from __future__ import annotations
  2. import dataclasses
  3. import time
  4. from pathlib import Path
  5. from unittest import mock
  6. import pytest
  7. import yaml
  8. import docker
  9. import docker.errors
  10. from sweagent import CONFIG_DIR
  11. from sweagent.environment.swe_env import EnvHook, EnvironmentArguments
  12. from .conftest import swe_env_context
  13. @pytest.mark.slow
  14. def test_init_swe_env(test_env_args):
  15. with swe_env_context(test_env_args) as env:
  16. env.reset()
  17. @pytest.mark.slow
  18. def test_init_swe_env_conservative_clone(test_env_args):
  19. with mock.patch.dict("os.environ", {"SWE_AGENT_CLONE_METHOD": "full"}):
  20. with swe_env_context(test_env_args) as env:
  21. env.reset()
  22. @pytest.mark.slow
  23. def test_init_swe_env_non_persistent(test_env_args):
  24. test_env_args = dataclasses.replace(test_env_args, container_name=None)
  25. with swe_env_context(test_env_args) as env:
  26. env.reset()
  27. @pytest.mark.slow
  28. def test_init_swe_env_cached_task_image(test_env_args):
  29. test_env_args = dataclasses.replace(test_env_args, cache_task_images=True, container_name=None)
  30. start = time.perf_counter()
  31. with swe_env_context(test_env_args) as env:
  32. env.reset()
  33. duration_no_cache = time.perf_counter() - start
  34. start = time.perf_counter()
  35. # now it should be cached, so let's run again
  36. image_prefix = None
  37. with swe_env_context(test_env_args) as env:
  38. env.reset()
  39. image_prefix = env.cached_image_prefix
  40. assert image_prefix
  41. duration_cache = time.perf_counter() - start
  42. assert duration_cache < duration_no_cache
  43. # Retrieve all images with a prefix "prefix"
  44. client = docker.from_env()
  45. # Remove the images
  46. for image in client.images.list():
  47. if not image.tags:
  48. continue
  49. if not image.tags[0].startswith(image_prefix):
  50. continue
  51. client.images.remove(image.id)
  52. @pytest.mark.slow
  53. def test_execute_setup_script(tmp_path, test_env_args):
  54. test_script = "echo 'hello world'"
  55. script_path = Path(tmp_path / "test_script.sh")
  56. script_path.write_text(test_script)
  57. test_env_args = dataclasses.replace(test_env_args, environment_setup=script_path)
  58. with swe_env_context(test_env_args) as env:
  59. env.reset()
  60. @pytest.mark.slow
  61. def test_read_file(tmp_path, test_env_args):
  62. with swe_env_context(test_env_args) as env:
  63. env.reset()
  64. content = env.read_file(Path("tests/filetoread.txt"))
  65. assert content.splitlines()[-1].strip() == "SWEEnv.read_file"
  66. @pytest.mark.slow
  67. def test_execute_environment(tmp_path, test_env_args, capsys):
  68. test_env = {
  69. "python": "3.11",
  70. "packages": "pytest",
  71. "pip_packages": ["tox"],
  72. "install": "python -m pip install --upgrade pip && python -m pip install -e .",
  73. }
  74. env_config_path = Path(tmp_path / "env_config.yml")
  75. env_config_path.write_text(yaml.dump(test_env))
  76. # Make sure we don't use persistent container, else we might have already installed the conda environment
  77. test_env_args = dataclasses.replace(test_env_args, environment_setup=env_config_path, container_name=None)
  78. with swe_env_context(test_env_args) as env:
  79. env.reset()
  80. out = capsys.readouterr().out
  81. print(out)
  82. assert "Cloned python conda environment" not in out
  83. @pytest.mark.slow
  84. def test_execute_environment_default(test_env_args):
  85. env_config_paths = (CONFIG_DIR / "environment_setup").iterdir()
  86. assert env_config_paths
  87. # Make sure we don't use persistent container, else we might have already installed the conda environment
  88. test_env_args = dataclasses.replace(test_env_args, container_name=None)
  89. for env_config_path in env_config_paths:
  90. if env_config_path.name == "django.yaml":
  91. continue
  92. if env_config_path.suffix not in [".yaml", ".yml", ".sh"]:
  93. continue
  94. print(env_config_path)
  95. test_env_args = dataclasses.replace(test_env_args, environment_setup=env_config_path)
  96. with swe_env_context(test_env_args) as env:
  97. env.reset()
  98. @pytest.mark.slow
  99. def test_execute_environment_clone_python(tmp_path, test_env_args, capsys):
  100. """This should clone the existing python 3.10 conda environment for speedup"""
  101. test_env = {
  102. "python": "3.10",
  103. "packages": "pytest",
  104. "pip_packages": ["tox"],
  105. "install": "python -m pip install --upgrade pip && python -m pip install -e .",
  106. }
  107. env_config_path = Path(tmp_path / "env_config.yml")
  108. env_config_path.write_text(yaml.dump(test_env))
  109. # Make sure we don't use persistent container, else we might have already installed the conda environment
  110. test_env_args = dataclasses.replace(test_env_args, environment_setup=env_config_path, container_name=None)
  111. with swe_env_context(test_env_args) as env:
  112. env.reset()
  113. out = capsys.readouterr().out
  114. print(out)
  115. assert "Cloned python conda environment" in out
  116. @pytest.mark.slow
  117. def test_open_pr(test_env_args):
  118. test_env_args = dataclasses.replace(
  119. test_env_args,
  120. data_path="https://github.com/swe-agent/test-repo/issues/1",
  121. repo_path="",
  122. )
  123. with swe_env_context(test_env_args) as env:
  124. env.reset()
  125. env.open_pr(_dry_run=True, trajectory=[])
  126. @pytest.mark.slow
  127. def test_interrupt_close(test_env_args):
  128. with swe_env_context(test_env_args) as env:
  129. env.reset()
  130. env.interrupt()
  131. @pytest.mark.slow
  132. def test_communicate_old(test_env_args):
  133. with mock.patch.dict("os.environ", {"SWE_AGENT_COMMUNICATE_METHOD": "processes"}):
  134. with swe_env_context(test_env_args) as env:
  135. env.reset()
  136. @pytest.mark.slow
  137. def test_env_with_hook(test_env_args):
  138. with swe_env_context(test_env_args) as env:
  139. env.add_hook(EnvHook())
  140. env.reset()
  141. def test_invalid_config():
  142. with pytest.raises(ValueError, match=".*Not allowed.*"):
  143. EnvironmentArguments(
  144. data_path=".",
  145. container_name="test",
  146. cache_task_images=True,
  147. )