conftest.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import asyncio
  2. import os
  3. import time
  4. import pytest
  5. from pytest import TempPathFactory
  6. from openhands.core.config import AppConfig, SandboxConfig, load_from_env
  7. from openhands.events import EventStream
  8. from openhands.runtime.client.runtime import EventStreamRuntime
  9. from openhands.runtime.plugins import AgentSkillsRequirement, JupyterRequirement
  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. else:
  28. raise ValueError(f'Invalid runtime: {runtime}')
  29. # This assures that all tests run together per runtime, not alternating between them,
  30. # which cause errors (especially outside GitHub actions).
  31. @pytest.fixture(scope='module', params=get_box_classes())
  32. def box_class(request):
  33. time.sleep(2)
  34. return request.param
  35. # TODO: We will change this to `run_as_user` when `ServerRuntime` is deprecated.
  36. # since `EventStreamRuntime` supports running as an arbitrary user.
  37. @pytest.fixture(scope='module', params=[True, False])
  38. def run_as_openhands(request):
  39. time.sleep(1)
  40. return request.param
  41. @pytest.fixture(scope='module', params=[True, False])
  42. def enable_auto_lint(request):
  43. time.sleep(1)
  44. return request.param
  45. @pytest.fixture(scope='module', params=None)
  46. def container_image(request):
  47. time.sleep(1)
  48. env_image = os.environ.get('SANDBOX_CONTAINER_IMAGE')
  49. if env_image:
  50. request.param = env_image
  51. else:
  52. if not hasattr(request, 'param'): # prevent runtime AttributeError
  53. request.param = None
  54. if request.param is None:
  55. request.param = request.config.getoption('--container-image')
  56. if request.param is None:
  57. request.param = pytest.param(
  58. 'nikolaik/python-nodejs:python3.11-nodejs22',
  59. 'python:3.11-bookworm',
  60. 'node:22-bookworm',
  61. 'golang:1.23-bookworm',
  62. )
  63. print(f'Container image: {request.param}')
  64. return request.param
  65. @pytest.fixture
  66. async def runtime(temp_dir, box_class, run_as_openhands):
  67. runtime = await _load_runtime(temp_dir, box_class, run_as_openhands)
  68. yield runtime
  69. await runtime.close()
  70. await asyncio.sleep(1)
  71. async def _load_runtime(
  72. temp_dir,
  73. box_class,
  74. run_as_openhands: bool = True,
  75. enable_auto_lint: bool = False,
  76. container_image: str | None = None,
  77. browsergym_eval_env: str | None = None,
  78. ) -> Runtime:
  79. sid = 'test'
  80. cli_session = 'main_test'
  81. # AgentSkills need to be initialized **before** Jupyter
  82. # otherwise Jupyter will not access the proper dependencies installed by AgentSkills
  83. plugins = [AgentSkillsRequirement(), JupyterRequirement()]
  84. config = AppConfig(
  85. workspace_base=temp_dir,
  86. workspace_mount_path=temp_dir,
  87. sandbox=SandboxConfig(
  88. use_host_network=True,
  89. browsergym_eval_env=browsergym_eval_env,
  90. ),
  91. )
  92. load_from_env(config, os.environ)
  93. config.run_as_openhands = run_as_openhands
  94. config.sandbox.enable_auto_lint = enable_auto_lint
  95. file_store = get_file_store(config.file_store, config.file_store_path)
  96. event_stream = EventStream(cli_session, file_store)
  97. if container_image is not None:
  98. config.sandbox.container_image = container_image
  99. runtime = box_class(
  100. config=config,
  101. event_stream=event_stream,
  102. sid=sid,
  103. plugins=plugins,
  104. container_image=container_image,
  105. )
  106. await runtime.ainit()
  107. await asyncio.sleep(1)
  108. return runtime
  109. # Export necessary function
  110. __all__ = ['_load_runtime']