merge(chv-muse-round12): 合入 round-11 修复轮 HEAD 50cae2a (RETEST6 全绿)

按 hunk 合入,不整文件覆盖。冲突 3 处:
- chv-guest/build.sh:取 P4 的 copy-in(cdp-broker/guard/blocklist/
  chv-memory)+ cdp-broker service/enable 三件;取 R11 的 git
  config(去掉 credential.helper store,层 5);tmpfiles 两边
  并存(/run/chv/ask-queue + /run/chv-browser)。
- chv-guest/chv-browser.py:P4 架构保留(CDP broker 客户端 +
  guard 模块);取 R11 两处仍适用的运行期修复:BROWSER_SOCK
  移进 /run/chv-browser(缺陷 4,合入后的 broker 已指该路径)
  与 handle_request 认 op=browser/action 透传;R11 的直连
  Playwright 代码(validate_url/truncate_aria/_load_playwright/
  _page snapshot)由 P4 取代,不带回。
- cloud/tests/test_chv_muse_p2.py:truncate 三测取 P4 的
  GUARD.truncate_a11y(dict 树);FakeCdpBroker 取 P4 版,删
  R11 的 FakePage 系列;干跑夹具取 R11 的 _fixture 调用,并
  给 _fixture 补 P4 四件(否则合入后 build.sh fail-fast)。

合入内移植(R11 修复在 P4 里移了位置,不移植即静默丢失):
- chv-guest/chv-cdp-broker.py:_load_playwright 返回
  sync_playwright()(原 R11 在 chv-browser.py 修过的同形
  bug);回归测试由 test_p2 移植到 test_chv_muse_p4.py。
- test_chv_muse_p2.py:HOST 由模块级 eager 改懒加载(_host()):
  host.py 顶层 import queue 会把 stdlib queue 缓进 sys.modules,
  使同进程后加载的 test_queue_sandbox 取不到 cloud/queue.py
  遮蔽而 ImportError(全量唯一失败)。

未移植(见报告):R11 的 Page.aria_snapshot() 纠正未进
chv-cdp-broker.py(仍调 accessibility.snapshot(),且 guard
的 dict 树 API 须配套改,属 P4 返工,不在本轮合入做)。

全量 cloud 套件:2522 tests OK (skipped=10),基线 a6f9597
为 2474 OK (skipped=12);+48 来自 R11 新增测试(p2 +36、
p3 +7、closeup +3、gaps +1、p4 +1 移植)。
This commit is contained in:
host committed 2026-11-07 18:13:31 +00:00
commit 9da74c2a78
24 files changed
+1949 -217

No files matched your search

+41 -3
View File
@@ -509,6 +509,40 @@ class CdpBrokerTest(unittest.TestCase):
self.assertTrue(broker.close()["ok"])
self.assertFalse(broker.snapshot()["ok"])
def test_load_playwright_returns_called_cm(self):
# round-11 复测回归,由合入 round-12 时从 test_chv_muse_p2
# 移植到此处:_load_playwright 曾返回裸 sync_playwright
# 函数(未调用),_ensure_browser 对它调 __enter__ 即
# AttributeError,open 永远失败;单测的假工厂直接返回带
# __enter__ 的对象,盖不住这个形状。现 _load_playwright
# 必须返回调用后的上下文管理器。
import types
calls = []
class FakeCM:
def __enter__(self):
return self
def __exit__(self, *exc):
return False
cm = FakeCM()
def sync_playwright():
calls.append("called")
return cm
fake_api = types.ModuleType("playwright.sync_api")
fake_api.sync_playwright = sync_playwright
fake_pkg = types.ModuleType("playwright")
fake_pkg.sync_api = fake_api
sys.modules["playwright"] = fake_pkg
sys.modules["playwright.sync_api"] = fake_api
self.addCleanup(sys.modules.pop, "playwright.sync_api", None)
self.addCleanup(sys.modules.pop, "playwright", None)
self.assertIs(CDP._load_playwright(), cm)
self.assertEqual(calls, ["called"])
class FakeCdpBroker:
"""假 CDP broker:按 canned 响应表回包,记录收到的请求。"""
@@ -718,14 +752,18 @@ class BuildDryRunTest(unittest.TestCase):
"chv-cdp-broker.py", "chv_browser_guard.py",
"browser-blocklist.txt",
"authd.py", "git-credential-chv-authd",
"chv-authd.service", "chv-memory.py"):
# 合入 round-11 时补:build.sh 的 P3 预检硬要求
# authd_init_stub.py 在仓(缺一即 exit 1)。
"chv-authd.service", "authd_init_stub.py",
"chv-memory.py"):
shutil.copy2(ROOT / "chv-guest" / name,
os.path.join(guest, name))
shutil.copy2(ROOT / "host.py", os.path.join(repo, "host.py"))
# round-12:合入后的 build.sh 要求 P3 客机三件套在仓里
# round-12:合入后的 build.sh 要求 P3 客机四件套在仓里
# (硬失败),云端叶子模块只警告、不失败——夹具一并拷入,
# 与 P2 夹具同口径。
# 与 P2 夹具同口径(含 errors.py,使 P3 叶子段落跑到)。
for rel in ("cloud/chv/authd.py", "cloud/chv/sentinel.py",
"cloud/chv/errors.py",
"cloud/__init__.py", "cloud/chv/__init__.py"):
dest = os.path.join(repo, rel)
os.makedirs(os.path.dirname(dest), exist_ok=True)