Files
codex-app-server/cloud/tests/test_chv_arch95plus.py
T

180 lines
6.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""CHV 架构 9.5+ 提升轨测试(feat-chv-arch95plus,堆叠于 #252)。
只用标准库与 mock,绝不启动真实 VM;测试里只用 FAKE
占位密钥,绝无真实密钥。覆盖:长函数提取后的行为不变、
WarmPool facade 不调实验接口、#215 对齐接口形状、审计
失败计数不中断、只读字段 chv_vm_dead 的派生规则、
lockfile 校验脚本的通过/漂移/空清单。
"""
import json
import logging
import os
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path
try:
from cloud.chv.compat215 import resolve_inside, tmpfs_isolated
from cloud.chv.hardening import validate_snapshot_url
from cloud.chv.pool import reconcile_orphans_for_executor
from cloud.sandbox import CloudHypervisorExecutor
from cloud.server import _task_to_dict
except ImportError:
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
from cloud.chv.compat215 import resolve_inside, tmpfs_isolated
from cloud.chv.hardening import validate_snapshot_url
from cloud.chv.pool import reconcile_orphans_for_executor
from cloud.sandbox import CloudHypervisorExecutor
from cloud.server import _task_to_dict
def _row(**kw):
base = {
"id": "t1", "project_id": "p1", "prompt": "x",
"status": "interrupted", "idempotency_key": None,
"depends_on": "[]", "priority": 0, "created_by": "u",
"created_at": 0, "updated_at": 0, "last_heartbeat": 0,
}
base.update(kw)
return base
class FakeExecutor:
def __init__(self):
self.acquire_called = False
self.prewarm_called = False
def shutdown_vm(self, vm):
return True
def _emit(self, *args, **kwargs):
pass
class Compat215Test(unittest.TestCase):
def test_resolve_inside_blocks_escape_and_symlink(self):
with tempfile.TemporaryDirectory() as d:
inside = os.path.join(d, "a.txt")
with open(inside, "w") as fh:
fh.write("x")
self.assertEqual(resolve_inside(d, "a.txt"), inside)
self.assertIsNone(resolve_inside(d, "../outside"))
self.assertIsNone(resolve_inside(d, "/etc/passwd"))
self.assertEqual(resolve_inside(d, ""), d)
def test_tmpfs_isolated_chv_and_unknown_fail_closed(self):
isolated, _ = tmpfs_isolated("cloud-hypervisor", "/tmp")
self.assertFalse(isolated)
isolated, _ = tmpfs_isolated("unknown-kind", "/tmp")
self.assertFalse(isolated)
def test_snapshot_url_uses_resolve_inside(self):
with tempfile.TemporaryDirectory() as d:
state = os.path.join(d, "state")
os.makedirs(state)
path = os.path.join(state, "s.raw")
with open(path, "w") as fh:
fh.write("x")
self.assertEqual(
validate_snapshot_url("file://" + path, state), path)
with self.assertRaises(Exception):
validate_snapshot_url(
"file:///etc/passwd", state)
def test_no_timeout_or_quota_map(self):
import cloud.chv.compat215 as m
self.assertFalse(hasattr(m, "resolve_module_timeout"))
self.assertFalse(hasattr(m, "decide"))
class PoolFacadeTest(unittest.TestCase):
def test_facade_only_reconciles_never_acquires(self):
# facade 内部构造 WarmPool:用假执行器 + 空 registry,
# 只要它不调 acquire/prewarm 就返回 [] 且不炸。
ex = FakeExecutor()
# WarmPool 构造需要 state_dir 属性;没有则 registry 为空
ex.state_dir = tempfile.mkdtemp()
ex.warm_pool_size = 0
ex.snapshot_url = None
result = reconcile_orphans_for_executor(ex)
self.assertEqual(result, [])
self.assertFalse(ex.acquire_called)
self.assertFalse(ex.prewarm_called)
class AuditCounterTest(unittest.TestCase):
def test_emit_failure_counts_and_does_not_raise(self):
ex = CloudHypervisorExecutor.__new__(CloudHypervisorExecutor)
ex.audit_callback = lambda *a, **k: (_ for _ in ()).throw(
RuntimeError("db down"))
ex.audit_failure_count = 0
# _emit 不抛异常(任务不因此中断),计数 +1
ex._emit("vm_boot", {"id": "t1"}, "vm=chv-t1")
self.assertEqual(ex.audit_failure_count, 1)
ex._emit("vm_boot", {"id": "t1"}, "vm=chv-t1")
self.assertEqual(ex.audit_failure_count, 2)
class ChvVmDeadFieldTest(unittest.TestCase):
def test_only_chv_with_vm_death_reason_returns_true(self):
row = _row(executor="cloud-hypervisor",
interrupted_reason="VM 中途死亡,任务未完成")
d = _task_to_dict(row)
self.assertTrue(d.get("chv_vm_dead"))
row2 = _row(executor="cloud-hypervisor",
interrupted_reason="quota")
self.assertNotIn("chv_vm_dead", _task_to_dict(row2))
row3 = _row(executor="docker",
interrupted_reason="VM 中途死亡,任务未完成")
self.assertNotIn("chv_vm_dead", _task_to_dict(row3))
row4 = _row(executor="cloud-hypervisor",
interrupted_reason=None)
self.assertNotIn("chv_vm_dead", _task_to_dict(row4))
class LockfileScriptTest(unittest.TestCase):
def _run(self, data, extra=None):
with tempfile.TemporaryDirectory() as d:
p = os.path.join(d, "BUILDINFO.json")
with open(p, "w") as fh:
json.dump(data, fh)
script = str(Path(__file__).resolve().parents[2]
/ "chv-guest" / "check_lockfile.py")
cmd = [sys.executable, script, p] + (extra or [])
return subprocess.run(cmd, capture_output=True, text=True)
def test_pass_and_empty_and_drift(self):
good = {"tag": "t", "versions": {"dpkg": ["a 1"],
"pip": ["b==2"]}}
self.assertEqual(self._run(good, ["--tag", "t"]).returncode, 0)
bad = {"tag": "t", "versions": {"dpkg": [], "pip": []}}
self.assertNotEqual(self._run(bad).returncode, 0)
with tempfile.TemporaryDirectory() as d:
frozen = os.path.join(d, "frozen.json")
with open(frozen, "w") as fh:
json.dump({"dpkg": ["missing 9"], "pip": []}, fh)
self.assertNotEqual(
self._run(good, ["--frozen", frozen]).returncode, 0)
class LongFunctionTest(unittest.TestCase):
def test_no_chv_function_over_50_lines(self):
import ast
base = Path(__file__).resolve().parents[2] / "cloud" / "chv"
over = []
for f in base.glob("*.py"):
tree = ast.parse(f.read_text())
for node in ast.walk(tree):
if isinstance(node, ast.FunctionDef):
n = node.end_lineno - node.lineno + 1
if n > 50:
over.append("%s:%s:%d" % (f.name, node.name, n))
self.assertEqual(over, [])
if __name__ == "__main__":
unittest.main()