118 lines
4.0 KiB
Python
118 lines
4.0 KiB
Python
from unittest.mock import MagicMock, patch
|
|
|
|
from deerflow.community.aio_sandbox.local_backend import LocalContainerBackend, _format_container_mount
|
|
|
|
|
|
def test_format_container_mount_uses_mount_syntax_for_docker_windows_paths():
|
|
args = _format_container_mount("docker", "D:/deer-flow/backend/.deer-flow/threads", "/mnt/threads", False)
|
|
|
|
assert args == [
|
|
"--mount",
|
|
"type=bind,src=D:/deer-flow/backend/.deer-flow/threads,dst=/mnt/threads",
|
|
]
|
|
|
|
|
|
def test_format_container_mount_marks_docker_readonly_mounts():
|
|
args = _format_container_mount("docker", "/host/path", "/mnt/path", True)
|
|
|
|
assert args == [
|
|
"--mount",
|
|
"type=bind,src=/host/path,dst=/mnt/path,readonly",
|
|
]
|
|
|
|
|
|
def test_format_container_mount_keeps_volume_syntax_for_apple_container():
|
|
args = _format_container_mount("container", "/host/path", "/mnt/path", True)
|
|
|
|
assert args == [
|
|
"-v",
|
|
"/host/path:/mnt/path:ro",
|
|
]
|
|
|
|
|
|
# ── extra_env injection ──────────────────────────────────────────────────────
|
|
|
|
|
|
def _make_backend(runtime: str = "docker") -> LocalContainerBackend:
|
|
"""Build a minimal LocalContainerBackend without real config."""
|
|
backend = LocalContainerBackend.__new__(LocalContainerBackend)
|
|
backend._runtime = runtime
|
|
backend._container_prefix = "test"
|
|
backend._environment = {}
|
|
backend._config_mounts = []
|
|
backend._base_port = 9000
|
|
backend._image = "test-image:latest"
|
|
return backend
|
|
|
|
|
|
def test_start_container_injects_extra_env(monkeypatch):
|
|
"""_start_container must append -e KEY=VALUE for each extra_env entry."""
|
|
backend = _make_backend()
|
|
|
|
captured: list[list[str]] = []
|
|
|
|
def fake_run(cmd, **_kwargs):
|
|
captured.append(list(cmd))
|
|
result = MagicMock()
|
|
result.returncode = 0
|
|
result.stdout = "fake-container-id\n"
|
|
return result
|
|
|
|
monkeypatch.setattr("deerflow.community.aio_sandbox.local_backend.subprocess.run", fake_run)
|
|
|
|
backend._start_container("c", 9000, extra_env={"THREAD_ID": "thread-abc", "FOO": "bar"})
|
|
|
|
cmd = captured[0]
|
|
assert "-e" in cmd
|
|
env_pairs = {cmd[i + 1] for i in range(len(cmd)) if cmd[i] == "-e"}
|
|
assert "THREAD_ID=thread-abc" in env_pairs
|
|
assert "FOO=bar" in env_pairs
|
|
|
|
|
|
def test_start_container_no_extra_env_does_not_inject(monkeypatch):
|
|
"""_start_container with no extra_env must not add unexpected -e flags."""
|
|
backend = _make_backend()
|
|
|
|
captured: list[list[str]] = []
|
|
|
|
def fake_run(cmd, **_kwargs):
|
|
captured.append(list(cmd))
|
|
result = MagicMock()
|
|
result.returncode = 0
|
|
result.stdout = "fake-container-id\n"
|
|
return result
|
|
|
|
monkeypatch.setattr("deerflow.community.aio_sandbox.local_backend.subprocess.run", fake_run)
|
|
|
|
backend._start_container("c", 9000)
|
|
|
|
cmd = captured[0]
|
|
env_pairs = {cmd[i + 1] for i in range(len(cmd)) if cmd[i] == "-e"}
|
|
assert all("THREAD_ID" not in pair for pair in env_pairs)
|
|
|
|
|
|
def test_start_container_extra_env_overrides_static_env(monkeypatch):
|
|
"""Runtime extra_env values must appear after static env, effectively overriding same-key entries."""
|
|
backend = _make_backend()
|
|
backend._environment = {"MY_VAR": "static"}
|
|
|
|
captured: list[list[str]] = []
|
|
|
|
def fake_run(cmd, **_kwargs):
|
|
captured.append(list(cmd))
|
|
result = MagicMock()
|
|
result.returncode = 0
|
|
result.stdout = "fake-container-id\n"
|
|
return result
|
|
|
|
monkeypatch.setattr("deerflow.community.aio_sandbox.local_backend.subprocess.run", fake_run)
|
|
|
|
backend._start_container("c", 9000, extra_env={"MY_VAR": "runtime"})
|
|
|
|
cmd = captured[0]
|
|
env_pairs = [cmd[i + 1] for i in range(len(cmd)) if cmd[i] == "-e"]
|
|
# Both entries should be present; the runtime one comes after, which Docker respects
|
|
assert "MY_VAR=static" in env_pairs
|
|
assert "MY_VAR=runtime" in env_pairs
|
|
assert env_pairs.index("MY_VAR=runtime") > env_pairs.index("MY_VAR=static")
|