a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
238 lines
8.3 KiB
Python
238 lines
8.3 KiB
Python
"""Unit tests for eval/environments/gortex_docker.py.
|
|
|
|
Tests focus on pure logic (cache key, failure recording, properties)
|
|
and mock Docker interactions to avoid requiring a running Docker daemon.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import io
|
|
import tarfile
|
|
from pathlib import Path
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
|
|
import sys
|
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
|
|
|
from environments.gortex_docker import (
|
|
DEFAULT_EVAL_SERVER_PORT,
|
|
DEFAULT_GORTEX_TIMEOUT,
|
|
GortexDockerEnvironment,
|
|
_make_cache_key,
|
|
)
|
|
|
|
|
|
# -- _make_cache_key ---------------------------------------------------------
|
|
|
|
class TestMakeCacheKey:
|
|
def test_basic(self):
|
|
assert _make_cache_key("django", "abc123") == "django_abc123"
|
|
|
|
def test_slash_in_repo_name(self):
|
|
assert _make_cache_key("django/django", "abc123") == "django__django_abc123"
|
|
|
|
def test_deterministic(self):
|
|
k1 = _make_cache_key("repo", "commit")
|
|
k2 = _make_cache_key("repo", "commit")
|
|
assert k1 == k2
|
|
|
|
def test_different_inputs_different_keys(self):
|
|
k1 = _make_cache_key("repo_a", "commit1")
|
|
k2 = _make_cache_key("repo_b", "commit2")
|
|
assert k1 != k2
|
|
|
|
|
|
# -- GortexDockerEnvironment init -------------------------------------------
|
|
|
|
class TestInit:
|
|
def test_defaults(self):
|
|
env = GortexDockerEnvironment(image="test:latest")
|
|
assert env.image == "test:latest"
|
|
assert env.enable_gortex is True
|
|
assert env.gortex_timeout == DEFAULT_GORTEX_TIMEOUT
|
|
assert env.eval_server_port == DEFAULT_EVAL_SERVER_PORT
|
|
assert env._container is None
|
|
assert env._gortex_ready is False
|
|
|
|
def test_gortex_disabled(self):
|
|
env = GortexDockerEnvironment(image="test:latest", enable_gortex=False)
|
|
assert env.enable_gortex is False
|
|
|
|
def test_custom_params(self):
|
|
env = GortexDockerEnvironment(
|
|
image="swe:v1",
|
|
gortex_binary="/tmp/gortex",
|
|
gortex_timeout=60,
|
|
eval_server_port=9999,
|
|
cache_dir="/tmp/cache",
|
|
instance_id="django__django-1234",
|
|
)
|
|
assert env.gortex_binary == Path("/tmp/gortex")
|
|
assert env.gortex_timeout == 60
|
|
assert env.eval_server_port == 9999
|
|
assert env.cache_dir == Path("/tmp/cache")
|
|
assert env.instance_id == "django__django-1234"
|
|
|
|
|
|
# -- setup / failure recording -----------------------------------------------
|
|
|
|
class TestRecordFailure:
|
|
def test_returns_failure_dict(self):
|
|
env = GortexDockerEnvironment(image="test:latest", instance_id="test-123")
|
|
result = env._record_failure("something broke")
|
|
assert result["exit_status"] == "setup_failure"
|
|
assert result["instance_id"] == "test-123"
|
|
assert "something broke" in result["setup_error"]
|
|
assert result["submission"] == ""
|
|
|
|
def test_sets_setup_error(self):
|
|
env = GortexDockerEnvironment(image="test:latest")
|
|
env._record_failure("timeout")
|
|
assert env.setup_error == "timeout"
|
|
|
|
|
|
# -- is_ready property -------------------------------------------------------
|
|
|
|
class TestIsReady:
|
|
def test_not_ready_no_container(self):
|
|
env = GortexDockerEnvironment(image="test:latest")
|
|
assert env.is_ready is False
|
|
|
|
def test_ready_when_gortex_disabled(self):
|
|
env = GortexDockerEnvironment(image="test:latest", enable_gortex=False)
|
|
env._container = MagicMock() # simulate running container
|
|
assert env.is_ready is True
|
|
|
|
def test_not_ready_gortex_enabled_but_not_setup(self):
|
|
env = GortexDockerEnvironment(image="test:latest", enable_gortex=True)
|
|
env._container = MagicMock()
|
|
assert env.is_ready is False
|
|
|
|
def test_ready_gortex_enabled_and_setup(self):
|
|
env = GortexDockerEnvironment(image="test:latest", enable_gortex=True)
|
|
env._container = MagicMock()
|
|
env._gortex_ready = True
|
|
assert env.is_ready is True
|
|
|
|
|
|
# -- extract_patch -----------------------------------------------------------
|
|
|
|
class TestExtractPatch:
|
|
def test_no_container(self):
|
|
env = GortexDockerEnvironment(image="test:latest")
|
|
assert env.extract_patch() == ""
|
|
|
|
def test_successful_diff(self):
|
|
env = GortexDockerEnvironment(image="test:latest")
|
|
mock_container = MagicMock()
|
|
mock_container.exec_run.return_value = (0, b"diff --git a/foo.py b/foo.py\n+hello\n")
|
|
env._container = mock_container
|
|
patch = env.extract_patch()
|
|
assert "diff --git" in patch
|
|
assert "+hello" in patch
|
|
|
|
def test_failed_diff(self):
|
|
env = GortexDockerEnvironment(image="test:latest")
|
|
mock_container = MagicMock()
|
|
mock_container.exec_run.return_value = (1, b"error")
|
|
env._container = mock_container
|
|
assert env.extract_patch() == ""
|
|
|
|
def test_exception_returns_empty(self):
|
|
env = GortexDockerEnvironment(image="test:latest")
|
|
mock_container = MagicMock()
|
|
mock_container.exec_run.side_effect = RuntimeError("boom")
|
|
env._container = mock_container
|
|
assert env.extract_patch() == ""
|
|
|
|
|
|
# -- teardown ----------------------------------------------------------------
|
|
|
|
class TestTeardown:
|
|
def test_teardown_stops_and_removes(self):
|
|
env = GortexDockerEnvironment(image="test:latest")
|
|
mock_container = MagicMock()
|
|
mock_client = MagicMock()
|
|
env._container = mock_container
|
|
env._client = mock_client
|
|
env.teardown()
|
|
mock_container.stop.assert_called_once()
|
|
mock_container.remove.assert_called_once()
|
|
mock_client.close.assert_called_once()
|
|
assert env._container is None
|
|
assert env._client is None
|
|
|
|
def test_teardown_no_container(self):
|
|
env = GortexDockerEnvironment(image="test:latest")
|
|
env.teardown() # should not raise
|
|
|
|
|
|
# -- exec_run ----------------------------------------------------------------
|
|
|
|
class TestExecRun:
|
|
def test_no_container(self):
|
|
env = GortexDockerEnvironment(image="test:latest")
|
|
code, output = env.exec_run("echo hello")
|
|
assert code == 1
|
|
assert "not running" in output.lower()
|
|
|
|
def test_string_command_wrapped_in_bash(self):
|
|
env = GortexDockerEnvironment(image="test:latest")
|
|
mock_container = MagicMock()
|
|
mock_container.exec_run.return_value = (0, b"hello\n")
|
|
env._container = mock_container
|
|
code, output = env.exec_run("echo hello")
|
|
assert code == 0
|
|
assert output == "hello\n"
|
|
# Verify it was wrapped in bash -c
|
|
call_args = mock_container.exec_run.call_args
|
|
assert call_args[0][0] == ["bash", "-c", "echo hello"]
|
|
|
|
def test_list_command_passed_directly(self):
|
|
env = GortexDockerEnvironment(image="test:latest")
|
|
mock_container = MagicMock()
|
|
mock_container.exec_run.return_value = (0, b"ok")
|
|
env._container = mock_container
|
|
code, output = env.exec_run(["ls", "-la"])
|
|
assert code == 0
|
|
call_args = mock_container.exec_run.call_args
|
|
assert call_args[0][0] == ["ls", "-la"]
|
|
|
|
|
|
# -- setup with gortex disabled ---------------------------------------------
|
|
|
|
class TestSetupGortexDisabled:
|
|
@patch("environments.gortex_docker.docker")
|
|
def test_setup_skips_gortex(self, mock_docker):
|
|
mock_client = MagicMock()
|
|
mock_container = MagicMock()
|
|
mock_container.short_id = "abc123"
|
|
mock_client.containers.run.return_value = mock_container
|
|
mock_docker.from_env.return_value = mock_client
|
|
|
|
env = GortexDockerEnvironment(image="test:latest", enable_gortex=False)
|
|
result = env.setup()
|
|
assert result is None
|
|
assert env._container is mock_container
|
|
|
|
|
|
# -- setup container launch failure ------------------------------------------
|
|
|
|
class TestSetupContainerFailure:
|
|
@patch("environments.gortex_docker.docker")
|
|
def test_container_launch_failure(self, mock_docker):
|
|
mock_client = MagicMock()
|
|
mock_client.containers.run.side_effect = RuntimeError("Docker not running")
|
|
mock_docker.from_env.return_value = mock_client
|
|
|
|
env = GortexDockerEnvironment(
|
|
image="test:latest",
|
|
instance_id="fail-instance",
|
|
)
|
|
result = env.setup()
|
|
assert result is not None
|
|
assert result["exit_status"] == "setup_failure"
|
|
assert "fail-instance" in result["instance_id"]
|