conftest.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import os
  2. import time
  3. import pytest
  4. from pytest import TempPathFactory
  5. from openhands.core.config import AppConfig, SandboxConfig, load_from_env
  6. from openhands.events import EventStream
  7. from openhands.runtime.client.runtime import EventStreamRuntime
  8. from openhands.runtime.plugins import AgentSkillsRequirement, JupyterRequirement
  9. from openhands.runtime.remote.runtime import RemoteRuntime
  10. from openhands.runtime.runtime import Runtime
  11. from openhands.storage import get_file_store
  12. @pytest.fixture(autouse=True)
  13. def print_method_name(request):
  14. print('\n########################################################################')
  15. print(f'Running test: {request.node.name}')
  16. print('########################################################################')
  17. yield
  18. @pytest.fixture
  19. def temp_dir(tmp_path_factory: TempPathFactory) -> str:
  20. return str(tmp_path_factory.mktemp('test_runtime'))
  21. TEST_RUNTIME = os.getenv('TEST_RUNTIME', 'eventstream')
  22. # Depending on TEST_RUNTIME, feed the appropriate box class(es) to the test.
  23. def get_box_classes():
  24. runtime = TEST_RUNTIME
  25. if runtime.lower() == 'eventstream':
  26. return [EventStreamRuntime]
  27. elif runtime.lower() == 'remote':
  28. return [RemoteRuntime]
  29. else:
  30. raise ValueError(f'Invalid runtime: {runtime}')
  31. # This assures that all tests run together per runtime, not alternating between them,
  32. # which cause errors (especially outside GitHub actions).
  33. @pytest.fixture(scope='module', params=get_box_classes())
  34. def box_class(request):
  35. time.sleep(2)
  36. return request.param
  37. # TODO: We will change this to `run_as_user` when `ServerRuntime` is deprecated.
  38. # since `EventStreamRuntime` supports running as an arbitrary user.
  39. @pytest.fixture(scope='module', params=[True, False])
  40. def run_as_openhands(request):
  41. time.sleep(1)
  42. return request.param
  43. @pytest.fixture(scope='module', params=[True, False])
  44. def enable_auto_lint(request):
  45. time.sleep(1)
  46. return request.param
  47. @pytest.fixture(scope='module', params=None)
  48. def base_container_image(request):
  49. time.sleep(1)
  50. env_image = os.environ.get('SANDBOX_BASE_CONTAINER_IMAGE')
  51. if env_image:
  52. request.param = env_image
  53. else:
  54. if not hasattr(request, 'param'): # prevent runtime AttributeError
  55. request.param = None
  56. if request.param is None and hasattr(request.config, 'sandbox'):
  57. try:
  58. request.param = request.config.sandbox.getoption(
  59. '--base_container_image'
  60. )
  61. except ValueError:
  62. request.param = None
  63. if request.param is None:
  64. request.param = pytest.param(
  65. 'nikolaik/python-nodejs:python3.11-nodejs22',
  66. 'python:3.11-bookworm',
  67. 'node:22-bookworm',
  68. 'golang:1.23-bookworm',
  69. )
  70. print(f'Container image: {request.param}')
  71. return request.param
  72. @pytest.fixture
  73. def runtime(temp_dir, box_class, run_as_openhands):
  74. runtime = _load_runtime(temp_dir, box_class, run_as_openhands)
  75. yield runtime
  76. runtime.close()
  77. time.sleep(1)
  78. def _load_runtime(
  79. temp_dir,
  80. box_class,
  81. run_as_openhands: bool = True,
  82. enable_auto_lint: bool = False,
  83. base_container_image: str | None = None,
  84. browsergym_eval_env: str | None = None,
  85. ) -> Runtime:
  86. sid = 'test'
  87. cli_session = 'main_test'
  88. # AgentSkills need to be initialized **before** Jupyter
  89. # otherwise Jupyter will not access the proper dependencies installed by AgentSkills
  90. plugins = [AgentSkillsRequirement(), JupyterRequirement()]
  91. config = AppConfig(
  92. workspace_base=temp_dir,
  93. workspace_mount_path=temp_dir,
  94. sandbox=SandboxConfig(
  95. use_host_network=True,
  96. browsergym_eval_env=browsergym_eval_env,
  97. ),
  98. )
  99. load_from_env(config, os.environ)
  100. config.run_as_openhands = run_as_openhands
  101. config.sandbox.enable_auto_lint = enable_auto_lint
  102. if base_container_image is not None:
  103. config.sandbox.base_container_image = base_container_image
  104. file_store = get_file_store(config.file_store, config.file_store_path)
  105. event_stream = EventStream(cli_session, file_store)
  106. runtime = box_class(
  107. config=config,
  108. event_stream=event_stream,
  109. sid=sid,
  110. plugins=plugins,
  111. )
  112. time.sleep(1)
  113. return runtime
  114. # Export necessary function
  115. __all__ = ['_load_runtime']