"""worker 首轮目录树注入单测:只改内存副本,跳过规则与来源。 不跑真实模型、不派发:直接调 _apply_tree_injection,Worker 用 test_worker 同款最小构造(db 在临时目录、假 host.py)。 """ import os import sys import tempfile import unittest from pathlib import Path try: from cloud.server import init_db from cloud.worker import Worker except ImportError: sys.path.insert(0, str(Path(__file__).resolve().parents[2])) from cloud.server import init_db from cloud.worker import Worker def _completed_runner(cmd): from types import SimpleNamespace return SimpleNamespace(returncode=0, stdout="ok", stderr="") class TreeInjectionTestCase(unittest.TestCase): def setUp(self): self.tmp = tempfile.TemporaryDirectory() self.db_path = os.path.join(self.tmp.name, "control.db") init_db(self.db_path) self.repo = os.path.join(self.tmp.name, "repo") os.makedirs(os.path.join(self.repo, "pkg")) Path(self.repo, "pkg", "mod.py").write_text("x", encoding="utf-8") Path(self.repo, "README.md").write_text("hi", encoding="utf-8") os.makedirs(os.path.join(self.repo, ".git")) self.worker = Worker( self.db_path, "/fake/host.py", runner=_completed_runner, env={"XCM_API_KEY": "test-placeholder"}) def tearDown(self): self.tmp.cleanup() def _task(self, **over): task = {"id": "t1", "project_id": "p1", "prompt": "做一件事", "repo": self.repo} task.update(over) return task def test_injects_snapshot_and_keeps_prompt(self): out = self.worker._apply_tree_injection(self._task()) self.assertTrue(out["_tree_injected"]) self.assertTrue(out["prompt"].endswith("做一件事")) self.assertIn("[项目目录结构:仓库检出顶层快照", out["prompt"]) self.assertIn("pkg/", out["prompt"]) self.assertIn("mod.py", out["prompt"]) self.assertNotIn(".git", out["prompt"]) # 原任务不被改动:注入只改内存副本。 original = self._task() self.worker._apply_tree_injection(original) self.assertEqual(original["prompt"], "做一件事") self.assertNotIn("_tree_injected", original) def test_goal_task_updates_goal_too(self): out = self.worker._apply_tree_injection( self._task(goal_mode=1, goal="目标")) self.assertIn("[项目目录结构", out["goal"]) self.assertTrue(out["goal"].endswith("目标")) def test_skip_coordinator_resume_fork_and_no_source(self): for over in ({"coordinator_parts": [{"name": "a"}]}, {"_resume": True}, {"_goal_resume_breakpoint": True}, {"forked_from": "parent"}): out = self.worker._apply_tree_injection(self._task(**over)) self.assertEqual(out["prompt"], "做一件事", over) self.assertNotIn("_tree_injected", out) out = self.worker._apply_tree_injection( self._task(repo="/nonexistent/repo")) self.assertEqual(out["prompt"], "做一件事") self.assertNotIn("_tree_injected", out) def test_tenant_missing_checkout_with_repo_url_never_falls_back(self): # 租户 + 有 repo_url + 检出缺失时,绝不回落到 test_repo # 模板快照(那会误导);repo_url 为空时才回落。 from cloud.sandbox import DockerExecutor test_repo = os.path.join(self.tmp.name, "test-repo") os.makedirs(test_repo) Path(test_repo, "sample.py").write_text("x", encoding="utf-8") self.worker.tenant_isolation = True self.worker.executor = DockerExecutor.__new__(DockerExecutor) self.worker.tenants_root = os.path.join(self.tmp.name, "tenants") self.worker._tenant_dirs = lambda pid: {"test_repo": test_repo} task = self._task(repo="/var/lib/codex-app-server/repos/p1") self.worker._project_repo_url = lambda pid: "https://example.invalid/r.git" self.assertIsNone(self.worker._tree_snapshot_source(task)) self.worker._project_repo_url = lambda pid: None self.assertEqual(self.worker._tree_snapshot_source(task), test_repo) def test_empty_repo_no_section(self): empty = os.path.join(self.tmp.name, "empty") os.makedirs(empty) out = self.worker._apply_tree_injection(self._task(repo=empty)) self.assertEqual(out["prompt"], "做一件事") self.assertNotIn("_tree_injected", out) if __name__ == "__main__": unittest.main()