feat(chv): 完整 Chromium 改装数据盘

根盘只剩 ~600MB,playwright install chromium 装根盘 109 秒后
ENOSPC 失败(2026-11-08 构建 #8 驱动实证)。完整版改装数据盘
/home/chv/workspace/.chv-browsers(9.3G 空闲),仍不 bake 进
base、按需;full 引擎启动时直接传 executable_path(channel 与
executable_path 互斥,且驱动进程启动时才读 env,运行中改 env
无效);status 增 full_browsers_dir,mount 失败报错给数据盘
安装命令。驱动的安装步同步改数据盘并 chown 给 chv-browser。
This commit is contained in:
host committed 2026-11-08 09:45:00 +00:00
1 parent 435664925e
commit 9d986becaf
2 files changed
+135 -27

No files matched your search

+66 -9
View File
@@ -111,7 +111,7 @@ class FakePlaywright:
return False
def _agent(pages, tmp):
def _agent(pages, tmp, full_browsers_dir=None):
ctx = FakeContext(pages)
entered_holder = {}
@@ -126,7 +126,8 @@ def _agent(pages, tmp):
agent = BROWSER.BrowserAgent(
playwright_factory=lambda: PW(), shots_dir=tmp,
profile_dir=os.path.join(tmp, "profile"))
profile_dir=os.path.join(tmp, "profile"),
full_browsers_dir=full_browsers_dir)
return agent, ctx, entered_holder
@@ -172,6 +173,45 @@ class FullPresentTest(unittest.TestCase):
self.assertFalse(BROWSER.full_chromium_present(tmp))
class FullBrowsersDirTest(unittest.TestCase):
def test_resolve_data_disk_path(self):
self.assertEqual(
BROWSER.resolve_full_browsers_dir(True, env={}),
BROWSER.FULL_BROWSERS_DATA_DIR)
def test_resolve_fallback_path(self):
self.assertEqual(
BROWSER.resolve_full_browsers_dir(False, env={}),
BROWSER.FULL_BROWSERS_FALLBACK_DIR)
def test_resolve_env_override_wins(self):
self.assertEqual(
BROWSER.resolve_full_browsers_dir(
True, env={"CHV_BROWSER_FULL_BROWSERS_DIR":
"/data/browsers"}),
"/data/browsers")
def test_executable_found_ignores_headless_shell(self):
with tempfile.TemporaryDirectory() as tmp:
os.makedirs(os.path.join(
tmp, "chromium_headless_shell-1248", "chrome-linux"))
self.assertIsNone(BROWSER.full_chromium_executable(tmp))
exe_dir = os.path.join(
tmp, "chromium-141.0.7390.37", "chrome-linux")
os.makedirs(exe_dir)
exe = os.path.join(exe_dir, "chrome")
open(exe, "w").write("x")
self.assertEqual(BROWSER.full_chromium_executable(tmp), exe)
def test_status_reports_data_disk_dir(self):
with tempfile.TemporaryDirectory() as tmp:
agent, _c, _h = _agent([FakePage()], tmp,
full_browsers_dir=tmp)
st = agent.status()
self.assertEqual(st["full_browsers_dir"], tmp)
self.assertFalse(st["full_present"])
class MultiSessionTest(unittest.TestCase):
def test_two_sessions_do_not_interfere(self):
with tempfile.TemporaryDirectory() as tmp:
@@ -423,25 +463,42 @@ class EngineSwitchTest(unittest.TestCase):
# 回落后 shell 仍可工作。
self.assertTrue(agent.open("https://example.com")["ok"])
def test_mount_unmount_full_switches_channel(self):
def test_mount_unmount_full_uses_executable_path(self):
with tempfile.TemporaryDirectory() as tmp:
agent, _c, holder = _agent([FakePage()], tmp)
with mock.patch.object(BROWSER, "full_chromium_present",
return_value=True):
mounted = agent.mount_full()
exe_dir = os.path.join(
tmp, "chromium-141.0.7390.37", "chrome-linux")
os.makedirs(exe_dir)
exe = os.path.join(exe_dir, "chrome")
open(exe, "w").write("x")
agent, _c, holder = _agent([FakePage()], tmp,
full_browsers_dir=tmp)
mounted = agent.mount_full()
self.assertTrue(mounted["ok"])
self.assertEqual(mounted["engine"], "full")
self.assertTrue(mounted["mounted_full"])
entered = holder["entered"]
self.assertEqual(entered.calls[-1][1].get("channel"),
"chromium")
kwargs = entered.calls[-1][1]
self.assertEqual(kwargs.get("executable_path"), exe)
self.assertNotIn("channel", kwargs)
unmounted = agent.unmount_full()
self.assertTrue(unmounted["ok"])
self.assertEqual(unmounted["engine"], "shell")
self.assertFalse(unmounted["mounted_full"])
self.assertNotIn("channel", entered.calls[-1][1])
self.assertNotIn("executable_path", entered.calls[-1][1])
self.assertTrue(agent.open("https://example.com")["ok"])
def test_mount_full_error_names_data_disk_install(self):
with tempfile.TemporaryDirectory() as tmp:
agent, _c, _h = _agent([FakePage()], tmp,
full_browsers_dir=os.path.join(
tmp, "browsers"))
resp = agent.mount_full()
self.assertFalse(resp["ok"])
self.assertTrue(resp["fallback"])
self.assertIn(os.path.join(tmp, "browsers"),
resp["error"])
def test_handle_request_routes_new_ops(self):
with tempfile.TemporaryDirectory() as tmp:
agent, _c, _h = _agent([FakePage()], tmp)