feat: CHV 审核修复 P2(范围恢复为全做)
P2-1:preflight reuse/CPU/内存校验块小提取为 _preflight_config_checks(纯移动,深耦合处如实停)。 P2-2:build_vm_command 降级为私有 _build_vm_command; Docker goal 内联解析顶部加正典分叉说明 + 同步检查清单。 P2-3:gaps grep 文本断言改成真实 Worker._run_attempt 行为断言。P2-4:README/build.sh 口径对齐(章节顺序、 BUILDINFO 名字列表、Node.js 不装写实)。P2-5:stop_vm 删除失败记审计。P2-6:CPU/内存校验统一进 preflight。 测试:原 84 + 新增 33 = 117 项,mock,无真 VM。
This commit is contained in:
1 parent
9771ed9e8c
commit
445376743d
9 files changed
+169
-44
No files matched your search
@@ -15,6 +15,7 @@ import sys
|
||||
import tempfile
|
||||
import threading
|
||||
import unittest
|
||||
from unittest import mock
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
|
||||
@@ -550,5 +551,44 @@ class ExecuteDeadPortTest(ChvFixCase):
|
||||
self.assertEqual(ctx.exception.kind, "vm_not_running")
|
||||
|
||||
|
||||
# -- P2 配置校验时机 / 文档口径 ------------------------------------------
|
||||
class ConfigTimingAndDocsTest(ChvFixCase):
|
||||
def test_preflight_rejects_bad_cpu_and_memory(self):
|
||||
ex = self.make_exec(cpus="abc")
|
||||
with self.assertRaises(ChvFailure) as ctx:
|
||||
ex.preflight()
|
||||
self.assertEqual(ctx.exception.kind, "config_invalid")
|
||||
ex2 = self.make_exec(memory="not-a-size")
|
||||
with self.assertRaises(ChvFailure) as ctx2:
|
||||
ex2.preflight()
|
||||
self.assertEqual(ctx2.exception.kind, "config_invalid")
|
||||
|
||||
def test_stop_cleanup_failure_is_audited(self):
|
||||
ex = self.make_exec()
|
||||
ex.stop_vm({"id": "ck"})
|
||||
os.makedirs(os.path.join(self.state_dir, "chv-ck", "seed"),
|
||||
exist_ok=True)
|
||||
with mock.patch("cloud.chv.executor.shutil.rmtree",
|
||||
side_effect=OSError("rm failed")):
|
||||
ex.stop_vm({"id": "ck"})
|
||||
self.assertTrue(any(e == "vm_key_cleanup_failed"
|
||||
for e, _, _, _ in self.audit))
|
||||
|
||||
def test_readme_sections_in_order_and_buildinfo_honest(self):
|
||||
readme = Path(__file__).resolve().parents[2] \
|
||||
/ "chv-guest" / "README.md"
|
||||
text = readme.read_text()
|
||||
self.assertLess(text.index("## 5. Host key"),
|
||||
text.index("## 6. 与执行器的对接"))
|
||||
self.assertIn("contents: [清单逐项名]", text)
|
||||
self.assertIn("Node.js 不装", text)
|
||||
|
||||
def test_manual_vm_command_is_private(self):
|
||||
ex = self.make_exec()
|
||||
self.assertFalse(hasattr(ex, "build_vm_command"))
|
||||
cmd = ex._build_vm_command({"id": "t"})
|
||||
self.assertIn("--api-socket", cmd)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -175,13 +175,40 @@ class BreakpointWiringTest(ChvGapCase):
|
||||
ssh_calls = [c for c in self.calls if c and c[0] == "ssh"]
|
||||
self.assertTrue(any("--model-provider" in c for c in ssh_calls))
|
||||
|
||||
def test_worker_branch_uses_hasattr_not_only_local(self):
|
||||
# worker.py 通用分支的文字证据:Local 优先、其次 hasattr。
|
||||
worker_path = Path(__file__).resolve().parents[1] / "worker.py"
|
||||
text = worker_path.read_text()
|
||||
self.assertIn("_call_goal_resume_breakpoint", text)
|
||||
self.assertIn("hasattr(", text)
|
||||
self.assertIn("goal_resume_breakpoint_task", text)
|
||||
def test_worker_breakpoint_branch_calls_generic_executor(self):
|
||||
# feat-chv-fix(P2-3):不再用源码 grep 充数,改为行为
|
||||
# 断言——真实 Worker._run_attempt 走通用断点分支,调到
|
||||
# 非 Local 执行器的 goal_resume_breakpoint_task,并把
|
||||
# 结果原样返回(参数、守卫顺序、返回值都覆盖)。
|
||||
from cloud.server import init_db
|
||||
db_path = os.path.join(self.dir, "control.db")
|
||||
init_db(db_path)
|
||||
seen = {}
|
||||
|
||||
class FakeGeneric:
|
||||
def goal_resume_breakpoint_task(self, task,
|
||||
model_provider=None,
|
||||
extra_env=None):
|
||||
seen["provider"] = model_provider
|
||||
seen["task_id"] = task["id"]
|
||||
return {"executor": "generic", "task_id": task["id"],
|
||||
"status": "completed", "stdout": "",
|
||||
"stderr": "", "returncode": 0,
|
||||
"host_status": None, "goal_met": True,
|
||||
"goal_error": None}
|
||||
|
||||
worker = Worker(db_path, "/fake/host.py",
|
||||
executor=FakeGeneric(),
|
||||
env={"XCM_API_KEY": "test-placeholder"})
|
||||
task = {"id": "bp-behav", "project_id": "p1",
|
||||
"prompt": "续跑", "goal_mode": 1,
|
||||
"_goal_resume_breakpoint": True}
|
||||
result, error = worker._run_attempt(task)
|
||||
self.assertIsNone(error)
|
||||
self.assertEqual(result["status"], "completed")
|
||||
self.assertTrue(result["goal_met"])
|
||||
self.assertEqual(seen["task_id"], "bp-behav")
|
||||
self.assertNotIn("executor 不支持", str(result))
|
||||
|
||||
|
||||
# -- (2) reconcile_orphans 接线 ---------------------------------------
|
||||
|
||||
@@ -264,7 +264,8 @@ class ConfigCommandTest(ChvCase):
|
||||
|
||||
def test_manual_vm_command_shape(self):
|
||||
ex = self.make_exec()
|
||||
cmd = ex.build_vm_command(self._task())
|
||||
self.assertFalse(hasattr(ex, "build_vm_command"))
|
||||
cmd = ex._build_vm_command(self._task())
|
||||
self.assertEqual(cmd[0], self.binary)
|
||||
self.assertIn("--api-socket", cmd)
|
||||
self.assertIn("--cpus", cmd)
|
||||
|
||||
Reference in new issue
Block a user