Files
codex-app-server/cloud/tests/test_chv_muse_p1_resident.py
T
host da8d0c29fd round-12: fix integration fallout (P9 gate x P1, P7 check x P2/P4 fixtures)
- P1 resident tests: P9's inference gate is a precondition of
  _run_with_vm, so _RealExecCase.make_executor now configures a
  default inference origin (CHV_INFERENCE_ORIGIN=https://xgapi.lol
  + CHV_INFERENCE_ALLOW_HOSTS=xgapi.lol) and a public fake resolver
  (same setup as P9's GateTest). No assertion changed; the gate's
  fail-closed behavior on missing origin stays pinned by P9's own
  ask test. 9 resident tests fixed (7 errors + 2 failures).
- P2/P4 dry-run fixtures: P7's build.sh hard check requires
  chv-memory.py in the repo; add it to both fixtures' copy lists.
  2 failures fixed.
- No production code changed in this commit (test setup only).
2026-11-07 00:43:50 +00:00

744 lines
30 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 常驻池(feat-chv-muse-p1)测试。
覆盖 cloud/chv/resident_pool.py、executor 的常驻接线
(_run_with_vm 常驻/冷启动两路、finally 语义)与
worker_adapter.reconcile_resident_pool facade。全部用假
执行器/假 VMM,绝不起真实 VM、不连真实网络。
断言点(按任务书):
- acquire/resume 失败回落冷启动,失败条目丢弃;
- release 只 pause 不销毁,pause 失败条目留 running;
- registry 损坏 quarantine、单坏条目不连坐;
- 重启后条目一律 orphan 不复用,只能 reconcile 清理;
- _run_with_vm 常驻命中跑完 pause、冷启动跑完 shutdown,
客内抛错时两路 finally 都执行;
- 带密钥 env / 未启用 / 建池失败时回落冷启动,任务不丢;
- 每用户隔离:release 只动本用户条目;
- 空闲回收只动超阈值 paused 条目,阈值 0 即关闭;
- WarmPool 实验模块不动(wired_to_dispatch 仍 False)。
"""
import json
import os
import re
import tempfile
import unittest
from types import SimpleNamespace
from unittest import mock
from cloud.chv import worker_adapter
from cloud.chv.errors import ChvFailure
from cloud.chv.executor import CloudHypervisorExecutor
from cloud.chv.experimental_pool import WarmPool
from cloud.chv.resident_pool import (
ResidentPool,
reconcile_resident_orphans_for_executor,
resident_task_for_user,
resident_user_key,
)
class _FakeExecutor:
"""ResidentPool 用的鸭子型执行器:记录调用,可注入失败。
wait 失败时模拟真实语义:先自行 shutdown 再抛错
(wait_guest_ready 的失败路径就是 stop_vm 后 raise)。
"""
def __init__(self, state_dir, env=None):
self.state_dir = state_dir
self._env = env or {}
self.resumes = []
self.pauses = []
self.wakes = []
self.waits = []
self.shutdowns = []
self.hibernates = []
self.emits = []
self.resume_fail = False
self.wait_fail = False
self.wake_fail = False
self.pause_fail = False
self.hibernate_fail = False
self.shutdown_fail = False
def vm_name(self, task_or_name):
raw = task_or_name.get("id") if isinstance(
task_or_name, dict) else str(task_or_name)
safe = re.sub(r"[^A-Za-z0-9_.-]", "-", raw)
if safe.startswith("chv-"):
return safe
return "chv-" + safe
def resume_vm(self, task_or_name):
self.resumes.append(self.vm_name(task_or_name))
if self.resume_fail:
raise RuntimeError("resume boom")
return True
def pause_vm(self, task_or_name):
self.pauses.append(self.vm_name(task_or_name))
if self.pause_fail:
raise RuntimeError("pause boom")
return True
def wake_vm(self, task_or_name):
self.wakes.append(self.vm_name(task_or_name))
if self.wake_fail:
raise RuntimeError("wake boom")
return {"vm": self.vm_name(task_or_name), "mode": "cold"}
def wait_guest_ready(self, task):
self.waits.append(self.vm_name(task))
if self.wait_fail:
self.shutdown_vm(task)
raise ChvFailure("guest_not_ready", "ssh 未就绪")
return True
def shutdown_vm(self, task_or_name):
self.shutdowns.append(self.vm_name(task_or_name))
if self.shutdown_fail:
raise RuntimeError("shutdown boom")
return True
def hibernate_vm(self, task_or_name, snapshot_url):
self.hibernates.append(
(self.vm_name(task_or_name), snapshot_url))
if self.hibernate_fail:
raise RuntimeError("hibernate boom")
return {"vm": self.vm_name(task_or_name),
"state": "hibernated", "snapshot": snapshot_url}
def _emit(self, event, task, detail="", kind=None):
self.emits.append(event)
def _public_resolver(host, port):
"""假解析器:公网 IP(与 P9 测试同款,供推理门放行用)。"""
return ["93.184.216.34"]
def _write(path, content):
with open(path, "w") as fh:
fh.write(content)
return path
def _registry_path(state_dir):
return os.path.join(state_dir, "resident-pool.json")
class ResidentKeyTest(unittest.TestCase):
def test_user_key_sanitizes_and_defaults(self):
self.assertEqual(resident_user_key(None), "default")
self.assertEqual(resident_user_key(""), "default")
self.assertEqual(resident_user_key("alice"), "alice")
self.assertEqual(resident_user_key("a/b c"), "a-b-c")
self.assertEqual(resident_task_for_user("alice"),
{"id": "resident-alice"})
self.assertEqual(resident_task_for_user(None),
{"id": "resident-default"})
class ResidentPoolAcquireTest(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.fake = _FakeExecutor(self.tmp.name)
def tearDown(self):
self.tmp.cleanup()
def _provisioned_pool(self, user="alice"):
pool = ResidentPool(self.fake)
got = pool.provision(user)
self.assertEqual(got["mode"], "resident")
return pool
def test_provision_then_acquire_then_release(self):
pool = self._provisioned_pool()
self.assertEqual(self.fake.wakes, ["chv-resident-alice"])
self.assertEqual(self.fake.pauses, ["chv-resident-alice"])
self.assertEqual(pool.paused_count(), 1)
got = pool.acquire("alice")
self.assertEqual(got["mode"], "resident")
self.assertEqual(got["vm"], "chv-resident-alice")
self.assertEqual(got["task"], {"id": "resident-alice"})
self.assertEqual(self.fake.resumes, ["chv-resident-alice"])
self.assertEqual(self.fake.waits, ["chv-resident-alice"])
self.assertEqual(pool.paused_count(), 0)
# running 中的条目不接受第二个 acquire(回落冷启动)。
self.assertEqual(pool.acquire("alice")["mode"], "cold")
self.assertEqual(len(self.fake.resumes), 1)
# release 只 pause,不销毁。
self.assertTrue(pool.release("alice"))
self.assertEqual(
self.fake.pauses,
["chv-resident-alice", "chv-resident-alice"])
self.assertEqual(self.fake.shutdowns, [])
self.assertEqual(pool.paused_count(), 1)
# 再取仍是同一台 VM。
got = pool.acquire("alice")
self.assertEqual(got["vm"], "chv-resident-alice")
def test_resume_failure_falls_back_to_cold_and_drops_entry(self):
pool = self._provisioned_pool()
self.fake.resume_fail = True
got = pool.acquire("alice")
self.assertEqual(got, {"mode": "cold", "vm": None,
"task": None})
self.assertEqual(pool.paused_count(), 0)
with open(_registry_path(self.tmp.name)) as fh:
self.assertEqual(json.load(fh), {})
def test_wait_failure_falls_back_to_cold_and_drops_entry(self):
pool = self._provisioned_pool()
self.fake.wait_fail = True
got = pool.acquire("alice")
self.assertEqual(got["mode"], "cold")
self.assertEqual(pool.paused_count(), 0)
# wait 的失败路径已自行 stop_vm(模拟真实语义)。
self.assertEqual(self.fake.shutdowns,
["chv-resident-alice"])
with open(_registry_path(self.tmp.name)) as fh:
self.assertEqual(json.load(fh), {})
def test_release_without_running_entry_is_false(self):
pool = self._provisioned_pool()
self.assertFalse(pool.release("alice"))
self.assertFalse(pool.release("nobody"))
self.assertEqual(self.fake.pauses, ["chv-resident-alice"])
def test_release_pause_failure_keeps_entry_running(self):
pool = self._provisioned_pool()
pool.acquire("alice")
self.fake.pause_fail = True
self.assertFalse(pool.release("alice"))
# 不删条目、不销毁:下次 acquire 仍是 running→cold,
# VM 本身没被 shutdown,留待 worker 关闭时清理。
self.assertEqual(self.fake.shutdowns, [])
self.assertEqual(pool.acquire("alice")["mode"], "cold")
def test_provision_is_idempotent_and_per_user_isolated(self):
pool = ResidentPool(self.fake)
self.assertEqual(pool.provision("alice")["mode"], "resident")
self.assertEqual(pool.provision("bob")["mode"], "resident")
self.assertEqual(pool.provision("alice")["mode"], "resident")
self.assertEqual(self.fake.wakes.count("chv-resident-alice"), 1)
self.assertEqual(self.fake.wakes.count("chv-resident-bob"), 1)
self.assertEqual(pool.paused_count(), 2)
# release 只动本用户条目。
self.assertFalse(pool.release("bob")) # bob 未 running
pool.acquire("alice")
self.assertTrue(pool.release("alice"))
self.assertEqual(pool.paused_count(), 2)
got = pool.acquire("bob")
self.assertEqual(got["vm"], "chv-resident-bob")
self.assertEqual(pool.paused_count(), 1)
self.assertEqual(self.fake.resumes, ["chv-resident-alice",
"chv-resident-bob"])
def test_provision_wake_failure_falls_back_and_cleans_up(self):
pool = ResidentPool(self.fake)
self.fake.wake_fail = True
got = pool.provision("alice")
self.assertEqual(got, {"mode": "cold", "vm": None,
"task": None})
# 建池失败尽力 shutdown,不留半醒 VM 与条目。
self.assertEqual(self.fake.shutdowns,
["chv-resident-alice"])
self.assertEqual(pool.paused_count(), 0)
with open(_registry_path(self.tmp.name)) as fh:
self.assertEqual(json.load(fh), {})
class ResidentPoolRegistryTest(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.fake = _FakeExecutor(self.tmp.name)
def tearDown(self):
self.tmp.cleanup()
def test_corrupt_registry_is_quarantined(self):
path = _write(_registry_path(self.tmp.name), "{not json")
pool = ResidentPool(self.fake)
self.assertTrue(pool.registry_corrupt)
self.assertEqual(pool.paused_count(), 0)
self.assertEqual(pool.orphan_count(), 0)
self.assertTrue(os.path.exists(path + ".corrupt"))
self.assertFalse(os.path.exists(path))
def test_top_level_non_dict_is_corrupt(self):
path = _write(_registry_path(self.tmp.name), "[1, 2]")
pool = ResidentPool(self.fake)
self.assertTrue(pool.registry_corrupt)
self.assertTrue(os.path.exists(path + ".corrupt"))
def test_bad_entries_dropped_without_tainting_good_ones(self):
_write(_registry_path(self.tmp.name), json.dumps({
"good": {"state": "paused", "vm": "chv-resident-good",
"user_id": "good"},
"no-vm": {"state": "paused"},
"not-a-dict": "x",
"wrong-state": {"state": "flying",
"vm": "chv-resident-x"},
}))
pool = ResidentPool(self.fake)
self.assertEqual(pool.registry_corrupt_entries, 3)
self.assertEqual(pool.orphan_count(), 1)
self.assertEqual(pool.paused_count(), 0)
def test_restart_never_reuses_entries(self):
pool1 = ResidentPool(self.fake)
pool1.provision("alice")
pool2 = ResidentPool(self.fake)
self.assertEqual(pool2.orphan_count(), 1)
self.assertEqual(pool2.paused_count(), 0)
# 新池绝不把上一世条目发给任务。
self.assertEqual(pool2.acquire("alice")["mode"], "cold")
self.assertEqual(self.fake.resumes, [])
cleaned = pool2.reconcile_orphans()
self.assertEqual(cleaned, ["chv-resident-alice"])
self.assertEqual(self.fake.shutdowns,
["chv-resident-alice"])
with open(_registry_path(self.tmp.name)) as fh:
self.assertEqual(json.load(fh), {})
def test_idle_minutes_env_parsing(self):
self.assertEqual(
ResidentPool(self.fake).idle_minutes, 0)
fake = _FakeExecutor(
self.tmp.name, env={"CHV_RESIDENT_IDLE_MINUTES": "45"})
self.assertEqual(ResidentPool(fake).idle_minutes, 45)
fake = _FakeExecutor(
self.tmp.name, env={"CHV_RESIDENT_IDLE_MINUTES": "junk"})
self.assertEqual(ResidentPool(fake).idle_minutes, 0)
fake = _FakeExecutor(
self.tmp.name, env={"CHV_RESIDENT_IDLE_MINUTES": "-5"})
self.assertEqual(ResidentPool(fake).idle_minutes, 0)
pool = ResidentPool(self.fake, idle_minutes=10)
self.assertEqual(pool.idle_minutes, 10)
class ResidentPoolIdleTest(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.fake = _FakeExecutor(self.tmp.name)
def tearDown(self):
self.tmp.cleanup()
def test_idle_disabled_by_default(self):
pool = ResidentPool(self.fake)
pool.provision("alice")
import time
self.assertEqual(
pool.reclaim_idle(now=time.time() + 10 ** 9), [])
self.assertEqual(self.fake.hibernates, [])
def test_overdue_paused_entry_is_hibernated(self):
import time
pool = ResidentPool(self.fake, idle_minutes=30)
pool.provision("alice")
pool.provision("bob")
now = time.time() + 31 * 60
reclaimed = pool.reclaim_idle(now=now)
self.assertEqual(reclaimed, ["chv-resident-alice",
"chv-resident-bob"])
self.assertEqual(len(self.fake.hibernates), 2)
for vm, url in self.fake.hibernates:
self.assertTrue(url.startswith("file://"))
self.assertIn(self.tmp.name, url)
self.assertTrue(url.endswith(
os.path.join(vm, "resident.snapshot")))
self.assertEqual(pool.paused_count(), 0)
with open(_registry_path(self.tmp.name)) as fh:
self.assertEqual(json.load(fh), {})
def test_not_yet_idle_entry_is_kept(self):
import time
pool = ResidentPool(self.fake, idle_minutes=30)
pool.provision("alice")
self.assertEqual(
pool.reclaim_idle(now=time.time() + 10 * 60), [])
self.assertEqual(pool.paused_count(), 1)
def test_hibernate_failure_keeps_entry_for_retry(self):
import time
pool = ResidentPool(self.fake, idle_minutes=30)
pool.provision("alice")
self.fake.hibernate_fail = True
self.assertEqual(
pool.reclaim_idle(now=time.time() + 31 * 60), [])
self.assertEqual(pool.paused_count(), 1)
class ResidentFacadeTest(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.fake = _FakeExecutor(self.tmp.name)
def tearDown(self):
self.tmp.cleanup()
def test_module_facade_cleans_and_empties_registry(self):
_write(_registry_path(self.tmp.name), json.dumps({
"a": {"state": "paused", "vm": "chv-resident-a"},
"b": {"state": "running", "vm": "chv-resident-b"},
"c": {"state": "provisioning", "vm": "chv-resident-c"},
"d": {"state": "warm", "vm": "chv-resident-d"},
"e": {"state": "paused"},
"f": "not-a-dict",
}))
cleaned = reconcile_resident_orphans_for_executor(self.fake)
self.assertEqual(cleaned, ["chv-resident-a", "chv-resident-b",
"chv-resident-c"])
self.assertEqual(self.fake.shutdowns, cleaned)
with open(_registry_path(self.tmp.name)) as fh:
self.assertEqual(json.load(fh), {})
self.assertIn("resident_pool_reconcile", self.fake.emits)
def test_module_facade_without_registry_is_empty(self):
self.assertEqual(
reconcile_resident_orphans_for_executor(self.fake), [])
self.assertEqual(self.fake.shutdowns, [])
def test_module_facade_without_state_dir_is_empty(self):
fake = _FakeExecutor(None)
fake.state_dir = None
self.assertEqual(
reconcile_resident_orphans_for_executor(fake), [])
class WorkerAdapterFacadeTest(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.fake = _FakeExecutor(self.tmp.name)
self.audits = []
def tearDown(self):
self.tmp.cleanup()
def _audit(self, project_id, event, detail):
self.audits.append((project_id, event, detail))
def test_facade_cleans_resident_registry(self):
# worker_adapter 的 isinstance 门要求真执行器:用假
# 的 shutdown 替身包一层真执行器实例(只借类型)。
ex = _RealExecCase.make_executor(self.tmp.name, self.tmp.name)
ex.shutdown_vm = self.fake.shutdown_vm
ex._emit = self.fake._emit
_write(_registry_path(self.tmp.name), json.dumps({
"a": {"state": "paused", "vm": "chv-resident-a"},
"b": {"state": "running", "vm": "chv-resident-b"},
}))
cleaned = worker_adapter.reconcile_resident_pool(
ex, self._audit, "startup")
self.assertEqual(cleaned, ["chv-resident-a", "chv-resident-b"])
self.assertEqual(self.fake.shutdowns, cleaned)
self.assertTrue(any(
event == "chv_resident_pool_reconcile"
for _p, event, _d in self.audits))
with open(_registry_path(self.tmp.name)) as fh:
self.assertEqual(json.load(fh), {})
def test_facade_never_constructs_resident_pool(self):
ex = _RealExecCase.make_executor(self.tmp.name, self.tmp.name)
ex.shutdown_vm = self.fake.shutdown_vm
ex._emit = self.fake._emit
_write(_registry_path(self.tmp.name), json.dumps({
"a": {"state": "paused", "vm": "chv-resident-a"},
}))
with mock.patch(
"cloud.chv.resident_pool.ResidentPool",
side_effect=AssertionError("must not construct")):
cleaned = worker_adapter.reconcile_resident_pool(
ex, self._audit, "shutdown")
self.assertEqual(cleaned, ["chv-resident-a"])
def test_facade_ignores_non_chv_executor(self):
cleaned = worker_adapter.reconcile_resident_pool(
object(), self._audit, "startup")
self.assertEqual(cleaned, [])
self.assertEqual(self.audits, [])
def test_facade_does_not_touch_warm_pool_reconcile(self):
# reconcile_warm_pool 仍走 warm-pool.json,与常驻无关。
ex = _RealExecCase.make_executor(self.tmp.name, self.tmp.name)
ex.shutdown_vm = self.fake.shutdown_vm
ex._emit = self.fake._emit
warm_path = os.path.join(self.tmp.name, "warm-pool.json")
_write(warm_path, json.dumps({
"w": {"state": "warm", "vm": "chv-warm-1",
"task_id": "w"},
}))
cleaned = worker_adapter.reconcile_warm_pool(
ex, self._audit, "startup")
self.assertEqual(cleaned, ["chv-warm-1"])
self.assertFalse(os.path.exists(_registry_path(self.tmp.name)))
def _write_file(path, content=b"x"):
with open(path, "wb") as fh:
fh.write(content)
os.chmod(path, 0o755)
return path
class _RealExecCase(unittest.TestCase):
"""真执行器 + 全方法替身:测 _run_with_vm 的接线本身,
不测 VMM。"""
@staticmethod
def make_executor(state_dir, base_dir, env_extra=None):
# round-12:P9 推理门是 _run_with_vm 的前置条件——本类
# 的任务都不带 model_provider,须配默认推理 origin +
# 公网解析器才放行(与 P9 GateTest 同款;未配时门应
# fail-closed,见 test_chv_muse_p9 的 ask 用例——这里
# 测的是常驻接线本身,不是门的行为,所以配好放行)。
env = {"CHV_EGRESS_PROXY": "http://10.0.0.1:8888",
"CHV_HOST_KEY_MODE": "keyscan",
"CHV_SSH_FORWARD": "1",
"CHV_INFERENCE_ORIGIN": "https://xgapi.lol",
"CHV_INFERENCE_ALLOW_HOSTS": "xgapi.lol"}
if env_extra:
env.update(env_extra)
cpuinfo = os.path.join(base_dir, "cpuinfo")
with open(cpuinfo, "w") as fh:
fh.write("flags : fpu vmx sse\n")
ex = CloudHypervisorExecutor(
binary=_write_file(os.path.join(base_dir,
"cloud-hypervisor")),
ch_remote=_write_file(os.path.join(base_dir, "ch-remote")),
kernel=_write_file(os.path.join(base_dir, "vmlinux")),
rootfs=_write_file(os.path.join(base_dir, "disk.raw"),
b"R" * 100),
ssh_key=_write_file(os.path.join(base_dir, "id_chv")),
kvm_path=_write_file(os.path.join(base_dir, "kvm")),
cpuinfo_path=cpuinfo,
state_dir=state_dir,
sleeper=lambda s: None, env=env)
ex.audit_callback = lambda e, t, d, k=None: None
ex.sentinel_resolver = _public_resolver
return ex
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.state_dir = os.path.join(self.tmp.name, "state")
self.calls = []
def tearDown(self):
self.tmp.cleanup()
def _stubbed_exec(self, env_extra=None, wake_fail_resident=False):
ex = self.make_executor(self.state_dir, self.tmp.name, env_extra)
calls = self.calls
def wake(task, extra_env=None):
calls.append(("wake", ex.vm_name(task)))
if wake_fail_resident and ex.vm_name(task).startswith(
"chv-resident-"):
raise RuntimeError("provision boom")
return {"vm": ex.vm_name(task), "mode": "cold"}
def pause(task_or_name):
calls.append(("pause", ex.vm_name(task_or_name)))
return True
def resume(task_or_name):
calls.append(("resume", ex.vm_name(task_or_name)))
return True
def wait(task):
calls.append(("wait", ex.vm_name(task)))
return True
def shutdown(task_or_name):
calls.append(("shutdown", ex.vm_name(task_or_name)))
return True
def run_guest(task, inner_args, extra_env=None, **kwargs):
calls.append(("guest", task["id"], list(inner_args)))
return {"task_id": task["id"], "status": "completed",
"stdout": "ok", "vm": ex.vm_name(task)}
def run_guest_goal(task, inner_args, extra_env=None, **kwargs):
calls.append(("guest-goal", task["id"], list(inner_args)))
return {"task_id": task["id"], "status": "completed",
"goal_met": True, "vm": ex.vm_name(task)}
ex.wake_vm = wake
ex.pause_vm = pause
ex.resume_vm = resume
ex.wait_guest_ready = wait
ex.shutdown_vm = shutdown
ex._run_guest = run_guest
ex._run_guest_goal = run_guest_goal
return ex
class RunWithVmResidentTest(_RealExecCase):
def test_first_task_provisions_and_second_reuses(self):
ex = self._stubbed_exec()
task = {"id": "task-1", "prompt": "hi"}
result = ex._run_with_vm(task, ["dispatch", "--task", "hi"])
self.assertEqual(result["status"], "completed")
# 常驻伪任务跑命令,但 task_id 改回真实任务。
self.assertEqual(result["task_id"], "task-1")
self.assertEqual(result["vm"], "chv-resident-default")
kinds = [c[0] for c in self.calls]
self.assertEqual(kinds, ["wake", "pause", "resume", "wait",
"guest", "pause"])
self.assertEqual(self.calls[0][1], "chv-resident-default")
self.assertEqual(self.calls[4][1], "resident-default")
# 第二个任务复用同一台常驻 VM,不再 wake。
self.calls.clear()
task2 = {"id": "task-2", "prompt": "hi2"}
result2 = ex._run_with_vm(task2, ["dispatch", "--task", "hi2"])
self.assertEqual(result2["task_id"], "task-2")
self.assertEqual(result2["vm"], "chv-resident-default")
self.assertEqual([c[0] for c in self.calls],
["resume", "wait", "guest", "pause"])
# 落盘条目是 paused,可供下次 acquire。
with open(_registry_path(self.state_dir)) as fh:
data = json.load(fh)
self.assertEqual(data["default"]["state"], "paused")
self.assertEqual(data["default"]["vm"], "chv-resident-default")
def test_goal_path_runs_on_resident_and_rewrites_task_id(self):
ex = self._stubbed_exec()
task = {"id": "goal-1", "prompt": "g"}
result = ex._run_with_vm(task, ["goal", "--task", "g"],
goal=True)
self.assertEqual(result["status"], "completed")
self.assertEqual(result["task_id"], "goal-1")
self.assertTrue(result["goal_met"])
self.assertIn(("guest-goal", "resident-default",
["goal", "--task", "g"]), self.calls)
def test_dispatch_task_flows_through_resident(self):
ex = self._stubbed_exec()
result = ex.dispatch_task({"id": "d-1", "prompt": "hello"})
self.assertEqual(result["status"], "completed")
self.assertEqual(result["task_id"], "d-1")
self.assertEqual(result["vm"], "chv-resident-default")
def test_per_user_vms_are_isolated(self):
ex = self._stubbed_exec()
ex._run_with_vm({"id": "t-a", "user_id": "alice",
"prompt": "x"}, ["dispatch"])
ex._run_with_vm({"id": "t-b", "user_id": "bob",
"prompt": "x"}, ["dispatch"])
wakes = [c[1] for c in self.calls if c[0] == "wake"]
self.assertEqual(wakes, ["chv-resident-alice",
"chv-resident-bob"])
with open(_registry_path(self.state_dir)) as fh:
data = json.load(fh)
self.assertEqual(set(data), {"alice", "bob"})
def test_disabled_flag_goes_cold(self):
ex = self._stubbed_exec(
env_extra={"CHV_RESIDENT_ENABLED": "0"})
result = ex._run_with_vm({"id": "task-1", "prompt": "hi"},
["dispatch"])
self.assertEqual(result["status"], "completed")
self.assertEqual(result["task_id"], "task-1")
kinds = [c[0] for c in self.calls]
self.assertEqual(kinds, ["wake", "guest", "shutdown"])
self.assertEqual(self.calls[0][1], "chv-task-1")
self.assertIsNone(getattr(ex, "_resident_pool", None))
self.assertFalse(os.path.exists(
_registry_path(self.state_dir)))
def test_secret_env_goes_cold(self):
ex = self._stubbed_exec()
result = ex._run_with_vm(
{"id": "task-1", "prompt": "hi"}, ["dispatch"],
extra_env={"SUB2API_API_KEY": "sekret"})
self.assertEqual(result["status"], "completed")
kinds = [c[0] for c in self.calls]
self.assertEqual(kinds, ["wake", "guest", "shutdown"])
self.assertFalse(os.path.exists(
_registry_path(self.state_dir)))
def test_provision_failure_falls_back_to_cold(self):
ex = self._stubbed_exec(wake_fail_resident=True)
result = ex._run_with_vm({"id": "task-1", "prompt": "hi"},
["dispatch"])
self.assertEqual(result["status"], "completed")
self.assertEqual(result["task_id"], "task-1")
kinds = [c[0] for c in self.calls]
# 建池 wake 失败(尽力 shutdown)→ 冷启动照常跑任务。
self.assertEqual(kinds, ["wake", "shutdown", "wake",
"guest", "shutdown"])
self.assertEqual(self.calls[1][1], "chv-resident-default")
self.assertEqual(self.calls[2][1], "chv-task-1")
def test_guest_error_still_pauses_resident_in_finally(self):
ex = self._stubbed_exec()
def boom(task, inner_args, extra_env=None, **kwargs):
raise RuntimeError("guest boom")
ex._run_guest = boom
with self.assertRaises(RuntimeError):
ex._run_with_vm({"id": "task-1", "prompt": "hi"},
["dispatch"])
kinds = [c[0] for c in self.calls]
self.assertEqual(kinds, ["wake", "pause", "resume", "wait",
"pause"])
self.assertEqual(self.calls[-1][1], "chv-resident-default")
def test_guest_error_still_shuts_down_cold_in_finally(self):
ex = self._stubbed_exec(
env_extra={"CHV_RESIDENT_ENABLED": "0"})
def boom(task, inner_args, extra_env=None, **kwargs):
raise RuntimeError("guest boom")
ex._run_guest = boom
with self.assertRaises(RuntimeError):
ex._run_with_vm({"id": "task-1", "prompt": "hi"},
["dispatch"])
self.assertEqual([c[0] for c in self.calls],
["wake", "shutdown"])
def test_wake_failure_propagates_without_shutdown(self):
ex = self._stubbed_exec(
env_extra={"CHV_RESIDENT_ENABLED": "0"})
def wake_fail(task, extra_env=None):
raise ChvFailure("vm_create_failed", "no vm")
ex.wake_vm = wake_fail
with self.assertRaises(ChvFailure):
ex._run_with_vm({"id": "task-1", "prompt": "hi"},
["dispatch"])
self.assertEqual(self.calls, [])
class WarmPoolUntouchedTest(unittest.TestCase):
def test_wired_to_dispatch_still_false(self):
self.assertFalse(WarmPool.wired_to_dispatch)
def test_executor_source_never_imports_experimental(self):
import ast
from pathlib import Path
tree = ast.parse((Path(__file__).resolve().parents[2]
/ "cloud" / "chv" / "executor.py").read_text())
for node in ast.walk(tree):
if isinstance(node, ast.Import):
for alias in node.names:
self.assertNotIn(alias.name, (
"cloud.chv.pool",
"cloud.chv.experimental_pool",
"cloud.chv.orphans"))
if isinstance(node, ast.ImportFrom):
self.assertNotIn(node.module, (
"cloud.chv.pool",
"cloud.chv.experimental_pool",
"cloud.chv.orphans"))
if __name__ == "__main__":
unittest.main()