Merge origin/develop and integrate browser isolation
This commit is contained in:
parent
50589232d6
commit
ebba5d04a4
13 changed files with 812 additions and 251 deletions
140
hermes_code/tests/tools/test_browser_use_isolation.py
Normal file
140
hermes_code/tests/tools/test_browser_use_isolation.py
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
"""Tests for browser-use Docker isolation manager."""
|
||||
|
||||
import json
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
|
||||
def test_resolve_isolation_owner_prefers_honcho_session_key():
|
||||
from tools.browser_use_manager import resolve_isolation_owner
|
||||
|
||||
owner = resolve_isolation_owner(
|
||||
"docker-per-principal",
|
||||
task_id="task-1",
|
||||
honcho_session_key="telegram:chat:user",
|
||||
)
|
||||
|
||||
assert owner == "telegram:chat:user"
|
||||
|
||||
|
||||
def test_resolve_isolation_owner_uses_task_for_per_task_mode():
|
||||
from tools.browser_use_manager import resolve_isolation_owner
|
||||
|
||||
owner = resolve_isolation_owner(
|
||||
"docker-per-task",
|
||||
task_id="task-42",
|
||||
honcho_session_key="telegram:chat:user",
|
||||
)
|
||||
|
||||
assert owner == "task-42"
|
||||
|
||||
|
||||
def test_hash_runtime_owner_is_stable():
|
||||
from tools.browser_use_manager import hash_runtime_owner
|
||||
|
||||
assert hash_runtime_owner("owner-1") == hash_runtime_owner("owner-1")
|
||||
assert hash_runtime_owner("owner-1") != hash_runtime_owner("owner-2")
|
||||
|
||||
|
||||
def test_shared_mode_returns_shared_cdp_url(monkeypatch):
|
||||
from tools import browser_use_manager
|
||||
|
||||
monkeypatch.setenv("BROWSER_USE_ISOLATION_MODE", "shared")
|
||||
monkeypatch.setenv("BROWSER_URL", "http://shared-browser:9333")
|
||||
monkeypatch.setenv("BROWSER_USE_RPC_URL", "http://shared-browser:8787/run")
|
||||
monkeypatch.setenv("BROWSER_VIEW_BASE_URL", "https://viewer.example.com")
|
||||
|
||||
runtime = browser_use_manager.ensure_isolated_browser_runtime(
|
||||
task_id="task-1",
|
||||
honcho_session_key="session-key",
|
||||
)
|
||||
|
||||
assert runtime["cdp_url"] == "http://shared-browser:9333"
|
||||
assert runtime["rpc_url"] == "http://shared-browser:8787/run"
|
||||
assert runtime["browser_view"] == "https://viewer.example.com/vnc.html?path=websockify"
|
||||
assert runtime["isolation_mode"] == "shared"
|
||||
|
||||
|
||||
def test_isolated_mode_starts_container_and_waits_for_cdp(monkeypatch):
|
||||
from tools import browser_use_manager
|
||||
|
||||
monkeypatch.setenv("BROWSER_USE_ISOLATION_MODE", "docker-per-principal")
|
||||
monkeypatch.setenv("BROWSER_RUNTIME_IMAGE", "hermes-browser-runtime:test")
|
||||
monkeypatch.setenv("BROWSER_RUNTIME_NETWORK", "hermes-net")
|
||||
monkeypatch.setenv("BROWSER_VIEW_BASE_URL", "https://viewer.example.com")
|
||||
|
||||
saved_registry = {}
|
||||
docker_calls = []
|
||||
|
||||
def fake_run_docker(args, check=True):
|
||||
docker_calls.append(args)
|
||||
if args[:2] == ["inspect", "-f"]:
|
||||
return MagicMock(returncode=1, stdout="", stderr="")
|
||||
if args[:1] == ["inspect"]:
|
||||
return MagicMock(returncode=1, stdout="", stderr="")
|
||||
return MagicMock(returncode=0, stdout="ok", stderr="")
|
||||
|
||||
with (
|
||||
patch.object(browser_use_manager, "_load_registry", return_value={"runtimes": {}}),
|
||||
patch.object(browser_use_manager, "_save_registry", side_effect=lambda payload: saved_registry.update(payload)),
|
||||
patch.object(browser_use_manager, "_run_docker", side_effect=fake_run_docker),
|
||||
patch.object(browser_use_manager, "_wait_for_cdp") as mock_wait,
|
||||
):
|
||||
runtime = browser_use_manager.ensure_isolated_browser_runtime(
|
||||
task_id="task-1",
|
||||
honcho_session_key="telegram:chat:user",
|
||||
)
|
||||
|
||||
assert runtime["isolation_mode"] == "docker-per-principal"
|
||||
assert runtime["cdp_url"].startswith("http://hermes-browser-")
|
||||
assert runtime["rpc_url"].startswith("http://hermes-browser-")
|
||||
assert runtime["rpc_url"].endswith(":8787/run")
|
||||
assert "/view/" in runtime["browser_view"]
|
||||
assert saved_registry["runtimes"]
|
||||
run_commands = [call for call in docker_calls if call[:2] == ["run", "-d"]]
|
||||
assert run_commands, "expected docker run to be invoked"
|
||||
assert "hermes-browser-runtime:test" in run_commands[0]
|
||||
mock_wait.assert_called_once()
|
||||
|
||||
|
||||
def test_browser_use_tool_routes_via_runtime_rpc_and_cleans_up():
|
||||
from tools import browser_use_tool
|
||||
|
||||
rpc_response = json.dumps({"success": True, "result": "done"}).encode("utf-8")
|
||||
fake_http_response = MagicMock()
|
||||
fake_http_response.read.return_value = rpc_response
|
||||
fake_http_response.__enter__.return_value = fake_http_response
|
||||
fake_http_response.__exit__.return_value = False
|
||||
|
||||
with (
|
||||
patch.object(
|
||||
browser_use_tool,
|
||||
"ensure_isolated_browser_runtime",
|
||||
return_value={
|
||||
"cdp_url": "http://isolated:9222",
|
||||
"rpc_url": "http://isolated:8787/run",
|
||||
"browser_view": "https://viewer.example.com/view/abc",
|
||||
"isolation_mode": "docker-per-principal",
|
||||
},
|
||||
) as mock_runtime,
|
||||
patch.object(browser_use_tool.request, "urlopen", return_value=fake_http_response) as mock_urlopen,
|
||||
patch.object(browser_use_tool, "cleanup_browser_use_runtime") as mock_cleanup,
|
||||
):
|
||||
result = browser_use_tool.registry.dispatch(
|
||||
"internet_browser",
|
||||
{"task": "open example.com"},
|
||||
task_id="task-7",
|
||||
honcho_session_key="telegram:123",
|
||||
)
|
||||
|
||||
payload = json.loads(result)
|
||||
assert payload["success"] is True
|
||||
assert payload["result"] == "done"
|
||||
assert payload["browser_view"] == "https://viewer.example.com/view/abc"
|
||||
assert payload["isolation_mode"] == "docker-per-principal"
|
||||
mock_runtime.assert_called_once()
|
||||
request_obj = mock_urlopen.call_args.args[0]
|
||||
assert request_obj.full_url == "http://isolated:8787/run"
|
||||
call = mock_runtime.call_args
|
||||
assert call.kwargs["task_id"] == "task-7"
|
||||
assert call.kwargs["honcho_session_key"] == "telegram:123"
|
||||
mock_cleanup.assert_called_once_with(task_id="task-7", honcho_session_key="telegram:123")
|
||||
Loading…
Add table
Add a link
Reference in a new issue