mirror of
https://gitee.com/wanwujie/deer-flow
synced 2026-04-23 22:24:46 +08:00
74 lines
3.4 KiB
Python
74 lines
3.4 KiB
Python
|
|
"""Tests for AioSandboxProvider mount helpers."""
|
||
|
|
|
||
|
|
import importlib
|
||
|
|
from unittest.mock import MagicMock, patch
|
||
|
|
|
||
|
|
from deerflow.config.paths import Paths
|
||
|
|
|
||
|
|
# ── ensure_thread_dirs ───────────────────────────────────────────────────────
|
||
|
|
|
||
|
|
|
||
|
|
def test_ensure_thread_dirs_creates_acp_workspace(tmp_path):
|
||
|
|
"""ACP workspace directory must be created alongside user-data dirs."""
|
||
|
|
paths = Paths(base_dir=tmp_path)
|
||
|
|
paths.ensure_thread_dirs("thread-1")
|
||
|
|
|
||
|
|
assert (tmp_path / "threads" / "thread-1" / "user-data" / "workspace").exists()
|
||
|
|
assert (tmp_path / "threads" / "thread-1" / "user-data" / "uploads").exists()
|
||
|
|
assert (tmp_path / "threads" / "thread-1" / "user-data" / "outputs").exists()
|
||
|
|
assert (tmp_path / "threads" / "thread-1" / "acp-workspace").exists()
|
||
|
|
|
||
|
|
|
||
|
|
def test_ensure_thread_dirs_acp_workspace_is_world_writable(tmp_path):
|
||
|
|
"""ACP workspace must be chmod 0o777 so the ACP subprocess can write into it."""
|
||
|
|
paths = Paths(base_dir=tmp_path)
|
||
|
|
paths.ensure_thread_dirs("thread-2")
|
||
|
|
|
||
|
|
acp_dir = tmp_path / "threads" / "thread-2" / "acp-workspace"
|
||
|
|
mode = oct(acp_dir.stat().st_mode & 0o777)
|
||
|
|
assert mode == oct(0o777)
|
||
|
|
|
||
|
|
|
||
|
|
# ── _get_thread_mounts ───────────────────────────────────────────────────────
|
||
|
|
|
||
|
|
|
||
|
|
def _make_provider(tmp_path):
|
||
|
|
"""Build a minimal AioSandboxProvider instance without starting the idle checker."""
|
||
|
|
aio_mod = importlib.import_module("deerflow.community.aio_sandbox.aio_sandbox_provider")
|
||
|
|
with patch.object(aio_mod.AioSandboxProvider, "_start_idle_checker"):
|
||
|
|
provider = aio_mod.AioSandboxProvider.__new__(aio_mod.AioSandboxProvider)
|
||
|
|
provider._config = {}
|
||
|
|
provider._sandboxes = {}
|
||
|
|
provider._lock = MagicMock()
|
||
|
|
provider._idle_checker_stop = MagicMock()
|
||
|
|
return provider
|
||
|
|
|
||
|
|
|
||
|
|
def test_get_thread_mounts_includes_acp_workspace(tmp_path, monkeypatch):
|
||
|
|
"""_get_thread_mounts must include /mnt/acp-workspace (read-only) for docker sandbox."""
|
||
|
|
aio_mod = importlib.import_module("deerflow.community.aio_sandbox.aio_sandbox_provider")
|
||
|
|
monkeypatch.setattr(aio_mod, "get_paths", lambda: Paths(base_dir=tmp_path))
|
||
|
|
|
||
|
|
mounts = aio_mod.AioSandboxProvider._get_thread_mounts("thread-3")
|
||
|
|
|
||
|
|
container_paths = {m[1]: (m[0], m[2]) for m in mounts}
|
||
|
|
|
||
|
|
assert "/mnt/acp-workspace" in container_paths, "ACP workspace mount is missing"
|
||
|
|
expected_host = str(tmp_path / "threads" / "thread-3" / "acp-workspace")
|
||
|
|
actual_host, read_only = container_paths["/mnt/acp-workspace"]
|
||
|
|
assert actual_host == expected_host
|
||
|
|
assert read_only is True, "ACP workspace should be read-only inside the sandbox"
|
||
|
|
|
||
|
|
|
||
|
|
def test_get_thread_mounts_includes_user_data_dirs(tmp_path, monkeypatch):
|
||
|
|
"""Baseline: user-data mounts must still be present after the ACP workspace change."""
|
||
|
|
aio_mod = importlib.import_module("deerflow.community.aio_sandbox.aio_sandbox_provider")
|
||
|
|
monkeypatch.setattr(aio_mod, "get_paths", lambda: Paths(base_dir=tmp_path))
|
||
|
|
|
||
|
|
mounts = aio_mod.AioSandboxProvider._get_thread_mounts("thread-4")
|
||
|
|
container_paths = {m[1] for m in mounts}
|
||
|
|
|
||
|
|
assert "/mnt/user-data/workspace" in container_paths
|
||
|
|
assert "/mnt/user-data/uploads" in container_paths
|
||
|
|
assert "/mnt/user-data/outputs" in container_paths
|