"""run_parallel.py 单测(CI 第二阶段覆盖率:基线 0%)。 不跑真实 client.py/codex:只断言 main() 拼出的子进程命令 (可执行文件、client.py 路径、cwd 解析、sandbox 默认值、 approval-policy、codex-home 透传)与成功计数/返回码—— 命令构造与汇总正是本文件的全部逻辑。 """ import io import json import os import sys import tempfile import unittest from contextlib import redirect_stdout from unittest import mock import run_parallel as rp_mod class FakePopen: seen = [] def __init__(self, cmd): self.cmd = cmd FakePopen.seen.append(cmd) self._rc = 0 def wait(self): return self._rc class RunParallelTest(unittest.TestCase): def _run(self, jobs, extra_args): FakePopen.seen = [] with tempfile.TemporaryDirectory() as tmp: jobs_path = os.path.join(tmp, "jobs.json") with open(jobs_path, "w", encoding="utf-8") as f: json.dump(jobs, f) argv = ["run_parallel.py", "--jobs", jobs_path] + extra_args with mock.patch.object(rp_mod.subprocess, "Popen", FakePopen), \ mock.patch.object(sys, "argv", argv): out = io.StringIO() with redirect_stdout(out): rc = rp_mod.main() return rc, list(FakePopen.seen), out.getvalue() def test_commands_and_all_success(self): jobs = [{"cwd": "job-a", "prompt": "review a"}, {"cwd": "/tmp/abs-b", "prompt": "review b", "sandbox": "workspace-write"}] rc, seen, out = self._run(jobs, ["--codex-home", "/tmp/ch"]) self.assertEqual(rc, 0) self.assertEqual(len(seen), 2) client = os.path.join(rp_mod.HERE, "client.py") self.assertEqual(seen[0], [sys.executable, client, "--prompt", "review a", "--cwd", os.path.join(rp_mod.HERE, "job-a"), "--sandbox", "read-only", "--approval-policy", "never", "--codex-home", "/tmp/ch"]) self.assertEqual(seen[1][5], "/tmp/abs-b") self.assertEqual(seen[1][7], "workspace-write") self.assertIn("2/2", out) def test_one_failure_returns_1(self): class FailingPopen(FakePopen): def __init__(self, cmd): super().__init__(cmd) self._idx = len(FakePopen.seen) def wait(self): return 1 if self._idx == 2 else 0 jobs = [{"cwd": "/tmp/a", "prompt": "x"}, {"cwd": "/tmp/b", "prompt": "y"}] FakePopen.seen = [] with tempfile.TemporaryDirectory() as tmp: jobs_path = os.path.join(tmp, "jobs.json") with open(jobs_path, "w", encoding="utf-8") as f: json.dump(jobs, f) with mock.patch.object(rp_mod.subprocess, "Popen", FailingPopen), \ mock.patch.object(sys, "argv", ["run_parallel.py", "--jobs", jobs_path]): out = io.StringIO() with redirect_stdout(out): rc = rp_mod.main() self.assertEqual(rc, 1) self.assertIn("1/2", out.getvalue()) def test_empty_jobs_returns_0(self): rc, seen, out = self._run([], []) self.assertEqual(rc, 0) self.assertEqual(seen, []) self.assertIn("0/0", out) if __name__ == "__main__": unittest.main()