feat(chv): 阶段 3 浏览器服务化——持久 profile + CDP + 多会话 + JPEG 截图 + 双浏览器
- chv-browser:launch_persistent_context,profile 固定数据盘 /home/chv/workspace/.chv-browser-profile(未挂载回落本机盘并明说); CDP --remote-debugging-port 9222(op cdp 返回 webSocketDebuggerUrl); 多会话每会话一页;截图 JPEG q70、viewport 宽封顶 1280、diff_only 整帧相同跳过;mount_full/unmount_full 切 full/shell 引擎,full 未装或起不来回落 shell 并明说。 - chv-data-mount:挂载后预建 profile 目录(chv-browser:chv-browser 0700)。 - build.sh:chv-browser 单元 Restart=always、After cloud-final.service。 - chv-execd:codex 环境白名单加 CHV_BROWSER_ 前缀。 - 测试:新增 test_chv_opt_stage3.py(20 项);P2 假实现改为持久 上下文 + JPEG;stage2 的 Restart=always 计数 3→4。 - 全量回归 2032 过 skipped=8。
This commit is contained in:
1 parent
6a65c94254
commit
1188e4b000
7 files changed
+821
-72
No files matched your search
@@ -559,7 +559,11 @@ class BrowserTest(unittest.TestCase):
|
||||
self.assertTrue(snap["ok"])
|
||||
shot = agent.screenshot()
|
||||
self.assertTrue(shot["ok"])
|
||||
self.assertTrue(shot["path"].endswith(".png"))
|
||||
self.assertTrue(shot["path"].endswith(".jpg"))
|
||||
self.assertEqual(shot["format"], "jpeg")
|
||||
self.assertEqual(shot["quality"], 70)
|
||||
self.assertEqual(shot["width"], 1280)
|
||||
self.assertTrue(shot["size"] > 0)
|
||||
self.assertTrue(os.path.exists(shot["path"]))
|
||||
self.assertTrue(agent.close()["ok"])
|
||||
|
||||
@@ -586,14 +590,30 @@ class FakePage:
|
||||
return {"role": "WebArea", "name": "Example Domain",
|
||||
"children": [{"role": "heading", "name": "Example"}]}
|
||||
|
||||
def screenshot(self, path=None):
|
||||
with open(path, "wb") as fh:
|
||||
fh.write(b"\x89PNG")
|
||||
def screenshot(self, path=None, type=None, quality=None):
|
||||
data = b"\xff\xd8\xff\xe0FAKEJPEG"
|
||||
if path:
|
||||
with open(path, "wb") as fh:
|
||||
fh.write(data)
|
||||
return data
|
||||
|
||||
def close(self):
|
||||
self._closed = True
|
||||
|
||||
|
||||
class FakeContext:
|
||||
"""阶段 3:持久上下文(launch_persistent_context 的返回值)。"""
|
||||
|
||||
def __init__(self, page):
|
||||
self._page = page
|
||||
|
||||
def new_page(self):
|
||||
return self._page
|
||||
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
|
||||
class FakeBrowser:
|
||||
def __init__(self, page):
|
||||
self._page = page
|
||||
@@ -609,6 +629,8 @@ class FakeEntered:
|
||||
def __init__(self, page):
|
||||
self.chromium = mock.Mock()
|
||||
self.chromium.launch.return_value = FakeBrowser(page)
|
||||
self.chromium.launch_persistent_context.return_value = \
|
||||
FakeContext(page)
|
||||
|
||||
|
||||
class FakePlaywright:
|
||||
|
||||
Reference in new issue
Block a user