Skip to content

Commit 5eb5fac

Browse files
committed
tests
1 parent 41b79da commit 5eb5fac

File tree

3 files changed

+109
-12
lines changed

3 files changed

+109
-12
lines changed

eval_protocol/cli.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,16 @@ def parse_args(args=None):
447447
action="store_true",
448448
help="Non-interactive: if multiple tests exist and no --entry, fails with guidance",
449449
)
450+
local_test_parser.add_argument(
451+
"--docker-build-extra",
452+
default="",
453+
help="Extra flags to pass to 'docker build' (quoted string, e.g. \"--no-cache --pull --progress=plain\")",
454+
)
455+
local_test_parser.add_argument(
456+
"--docker-run-extra",
457+
default="",
458+
help="Extra flags to pass to 'docker run' (quoted string, e.g. \"--env-file .env --memory=8g\")",
459+
)
450460

451461
# Run command (for Hydra-based evaluations)
452462
# This subparser intentionally defines no arguments itself.

eval_protocol/cli_commands/local_test.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import os
33
import subprocess
44
import sys
5+
import shlex
56
from typing import List
67

78
from .upload import _discover_tests, _prompt_select
@@ -24,24 +25,25 @@ def _run_pytest_host(pytest_target: str) -> int:
2425
return proc.returncode
2526

2627

27-
def _build_docker_image(dockerfile_path: str, image_tag: str) -> bool:
28+
def _build_docker_image(dockerfile_path: str, image_tag: str, build_extras: List[str] | None = None) -> bool:
2829
context_dir = os.path.dirname(dockerfile_path)
2930
print(f"Building Docker image '{image_tag}' from {dockerfile_path} ...")
3031
try:
31-
proc = subprocess.run(
32-
["docker", "build", "-t", image_tag, "-f", dockerfile_path, context_dir],
33-
stdout=subprocess.PIPE,
34-
stderr=subprocess.STDOUT,
35-
text=True,
36-
)
32+
base_cmd = ["docker", "build"]
33+
if build_extras:
34+
base_cmd += build_extras
35+
base_cmd += ["-t", image_tag, "-f", dockerfile_path, context_dir]
36+
proc = subprocess.run(base_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
3737
print(proc.stdout)
3838
return proc.returncode == 0
3939
except FileNotFoundError:
4040
print("Error: docker not found in PATH. Install Docker or use --ignore-docker.")
4141
return False
4242

4343

44-
def _run_pytest_in_docker(project_root: str, image_tag: str, pytest_target: str) -> int:
44+
def _run_pytest_in_docker(
45+
project_root: str, image_tag: str, pytest_target: str, run_extras: List[str] | None = None
46+
) -> int:
4547
workdir = "/workspace"
4648
# Host HOME logs directory to map into container
4749
host_home = os.path.expanduser("~")
@@ -73,6 +75,8 @@ def _run_pytest_in_docker(project_root: str, image_tag: str, pytest_target: str)
7375
cmd += ["--user", f"{uid}:{gid}"]
7476
except Exception:
7577
pass
78+
if run_extras:
79+
cmd += run_extras
7680
cmd += [image_tag, "pytest", pytest_target, "-vs"]
7781
print("Running in Docker:", " ".join(cmd))
7882
try:
@@ -126,6 +130,10 @@ def local_test_command(args: argparse.Namespace) -> int:
126130
pytest_target = rel
127131

128132
ignore_docker = bool(getattr(args, "ignore_docker", False))
133+
build_extras_str = getattr(args, "docker_build_extra", "") or ""
134+
run_extras_str = getattr(args, "docker_run_extra", "") or ""
135+
build_extras = shlex.split(build_extras_str) if build_extras_str else []
136+
run_extras = shlex.split(run_extras_str) if run_extras_str else []
129137
if ignore_docker:
130138
if not pytest_target:
131139
print("Error: Failed to resolve a pytest target to run.")
@@ -146,14 +154,14 @@ def local_test_command(args: argparse.Namespace) -> int:
146154
except Exception:
147155
pass
148156
image_tag = "ep-evaluator:local"
149-
ok = _build_docker_image(dockerfiles[0], image_tag)
157+
ok = _build_docker_image(dockerfiles[0], image_tag, build_extras=build_extras)
150158
if not ok:
151159
print("Docker build failed. See logs above.")
152160
return 1
153161
if not pytest_target:
154162
print("Error: Failed to resolve a pytest target to run.")
155163
return 1
156-
return _run_pytest_in_docker(project_root, image_tag, pytest_target)
164+
return _run_pytest_in_docker(project_root, image_tag, pytest_target, run_extras=run_extras)
157165

158166
# No Dockerfile: run on host
159167
if not pytest_target:

tests/test_cli_local_test.py

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,11 @@ def test_local_test_builds_and_runs_in_docker(tmp_path, monkeypatch):
9595
from eval_protocol.cli_commands import local_test as lt
9696

9797
monkeypatch.setattr(lt, "_find_dockerfiles", lambda root: [str(project / "Dockerfile")])
98-
monkeypatch.setattr(lt, "_build_docker_image", lambda dockerfile, tag, platform=None: True)
98+
monkeypatch.setattr(lt, "_build_docker_image", lambda dockerfile, tag, build_extras=None: True)
9999

100100
captured = {"target": "", "image": ""}
101101

102-
def _fake_run_docker(root: str, image_tag: str, pytest_target: str, platform=None) -> int:
102+
def _fake_run_docker(root: str, image_tag: str, pytest_target: str, run_extras=None) -> int:
103103
captured["target"] = pytest_target
104104
captured["image"] = image_tag
105105
return 0
@@ -143,3 +143,82 @@ def _fake_host(target: str) -> int:
143143
rc = lt.local_test_command(args) # pyright: ignore[reportArgumentType]
144144
assert rc == 0
145145
assert called["host"] is True
146+
147+
148+
def test_local_test_passes_docker_build_extra(tmp_path, monkeypatch):
149+
project = tmp_path / "proj"
150+
project.mkdir()
151+
monkeypatch.chdir(project)
152+
153+
test_file = project / "metric" / "test_build_extra.py"
154+
test_file.parent.mkdir(parents=True, exist_ok=True)
155+
test_file.write_text("def test_dummy():\n assert True\n", encoding="utf-8")
156+
157+
from eval_protocol.cli_commands import local_test as lt
158+
159+
monkeypatch.setattr(lt, "_find_dockerfiles", lambda root: [str(project / "Dockerfile")])
160+
161+
captured = {"extras": None}
162+
163+
def _fake_build(dockerfile, tag, build_extras=None):
164+
captured["extras"] = build_extras
165+
return True
166+
167+
def _fake_run_docker(root: str, image_tag: str, pytest_target: str, run_extras=None) -> int:
168+
return 0
169+
170+
monkeypatch.setattr(lt, "_build_docker_image", _fake_build)
171+
monkeypatch.setattr(lt, "_run_pytest_in_docker", _fake_run_docker)
172+
173+
# Extras string with multiple flags and equals-arg
174+
args = SimpleNamespace(
175+
entry=str(test_file),
176+
ignore_docker=False,
177+
yes=True,
178+
docker_build_extra="--no-cache --pull --progress=plain --build-arg KEY=VAL",
179+
docker_run_extra="",
180+
)
181+
rc = lt.local_test_command(args) # pyright: ignore[reportArgumentType]
182+
assert rc == 0
183+
# Expect split list preserving tokens order
184+
assert captured["extras"] == ["--no-cache", "--pull", "--progress=plain", "--build-arg", "KEY=VAL"]
185+
186+
187+
def test_local_test_passes_docker_run_extra(tmp_path, monkeypatch):
188+
project = tmp_path / "proj"
189+
project.mkdir()
190+
monkeypatch.chdir(project)
191+
192+
test_file = project / "metric" / "test_run_extra.py"
193+
test_file.parent.mkdir(parents=True, exist_ok=True)
194+
test_file.write_text("def test_dummy():\n assert True\n", encoding="utf-8")
195+
196+
from eval_protocol.cli_commands import local_test as lt
197+
198+
monkeypatch.setattr(lt, "_find_dockerfiles", lambda root: [str(project / "Dockerfile")])
199+
monkeypatch.setattr(lt, "_build_docker_image", lambda dockerfile, tag, build_extras=None: True)
200+
201+
captured = {"extras": None}
202+
203+
def _fake_run_docker(root: str, image_tag: str, pytest_target: str, run_extras=None) -> int:
204+
captured["extras"] = run_extras
205+
return 0
206+
207+
monkeypatch.setattr(lt, "_run_pytest_in_docker", _fake_run_docker)
208+
209+
args = SimpleNamespace(
210+
entry=str(test_file),
211+
ignore_docker=False,
212+
yes=True,
213+
docker_build_extra="",
214+
docker_run_extra="--env-file .env --memory=8g --cpus=2 --add-host=host.docker.internal:host-gateway",
215+
)
216+
rc = lt.local_test_command(args) # pyright: ignore[reportArgumentType]
217+
assert rc == 0
218+
assert captured["extras"] == [
219+
"--env-file",
220+
".env",
221+
"--memory=8g",
222+
"--cpus=2",
223+
"--add-host=host.docker.internal:host-gateway",
224+
]

0 commit comments

Comments
 (0)