from unittest.mock import MagicMock, patch def test_resolve_isolation_owner_prefers_user_id(): from api.services.browser_runtime_manager import resolve_isolation_owner owner = resolve_isolation_owner( "docker-per-principal", task_id="task-1", metadata={"user_id": "user-7", "session_id": "session-9"}, thread_id="thread-1", ) assert owner == "user-7" def test_resolve_isolation_owner_uses_task_for_per_task_mode(): from api.services.browser_runtime_manager import resolve_isolation_owner owner = resolve_isolation_owner( "docker-per-task", task_id="task-42", metadata={"user_id": "user-7"}, thread_id="thread-1", ) assert owner == "task-42" def test_hash_runtime_owner_is_stable(): from api.services.browser_runtime_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_runtime(monkeypatch): from api.services import browser_runtime_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_runtime_manager.ensure_browser_runtime( task_id="task-1", metadata={"user_id": "user-7"}, thread_id="thread-1", ) 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(monkeypatch): from api.services import browser_runtime_manager monkeypatch.setenv("BROWSER_USE_ISOLATION_MODE", "docker-per-principal") monkeypatch.setenv("BROWSER_RUNTIME_IMAGE", "browser-use-browser-runtime:test") monkeypatch.setenv("BROWSER_RUNTIME_NETWORK", "browser-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_runtime_manager, "_load_registry", return_value={"runtimes": {}}), patch.object(browser_runtime_manager, "_save_registry", side_effect=lambda payload: saved_registry.update(payload)), patch.object(browser_runtime_manager, "_run_docker", side_effect=fake_run_docker), patch.object(browser_runtime_manager, "_wait_for_runtime") as mock_wait, ): runtime = browser_runtime_manager.ensure_browser_runtime( task_id="task-1", metadata={"user_id": "user-7"}, thread_id="thread-1", ) assert runtime["isolation_mode"] == "docker-per-principal" assert runtime["cdp_url"].startswith("http://browser-use-browser-") assert runtime["rpc_url"].startswith("http://browser-use-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 assert "browser-use-browser-runtime:test" in run_commands[0] mock_wait.assert_called_once()