"""autoscaler unit 与生产主机现行 unit 的同步回归。 背景:仓库版 deploy/autoscaler/codex-autoscaler.service 的 ExecStart 长期只带 --websearch-mcp,而生产主机现行 unit 在此之外还带 --seed-skills --imagegen-mcp --playwright-mcp(2026-11-01 主机只读核对: 主机 ExecStart = 仓库版 ExecStart + 这三项,别无差异)。 仓库版滞后意味着按仓库重装会静默丢掉技能播种与两路 MCP。 本文件只读仓库内两个文件,不碰主机、不联网、不跑 worker: - unit 的 worker 侧(`--` 之后)必须含全部四项 MCP/技能播种 flag; - worker 侧所有 --flag 必须在 cloud/worker.py 里有 add_argument 定义, 防止拼写漂移导致 worker 启动即报未知参数; - 四项 flag 绝不能出现在 scaler 侧(`--` 之前),它们是 worker 参数。 """ import os import unittest REPO_ROOT = os.path.dirname(os.path.dirname(os.path.dirname( os.path.abspath(__file__)))) UNIT_PATH = os.path.join(REPO_ROOT, "deploy", "autoscaler", "codex-autoscaler.service") WORKER_PATH = os.path.join(REPO_ROOT, "cloud", "worker.py") # 生产主机现行 unit 带的 worker 侧 MCP/技能播种四项。 MCP_SEED_FLAGS = ("--websearch-mcp", "--seed-skills", "--imagegen-mcp", "--playwright-mcp") def _execstart(): with open(UNIT_PATH, encoding="utf-8") as f: lines = [ln.rstrip("\n") for ln in f] starts = [ln for ln in lines if ln.startswith("ExecStart=")] assert len(starts) == 1, "unit 应恰好有一行 ExecStart,实得 %d 行" % len(starts) return starts[0][len("ExecStart="):] def _split_sides(): cmd = _execstart() assert cmd.startswith("/usr/bin/python3 -m cloud.autoscaler"), \ "unit 应以 cloud.autoscaler 启动,实得:%s" % cmd[:60] parts = cmd.split(" -- ", 1) assert len(parts) == 2, "ExecStart 缺少 scaler/worker 分隔符 ' -- '" return parts[0], parts[1] def _flag_tokens(side): """side 里以 -- 开头的 token(去重前顺序保留,含 =value 形式剥离)。""" flags = [] for tok in side.split(): if tok.startswith("--"): flags.append(tok.split("=", 1)[0]) return flags class TestAutoscalerUnitSync(unittest.TestCase): def test_worker_side_includes_all_four_mcp_seed_flags(self): _, worker_side = _split_sides() flags = _flag_tokens(worker_side) for flag in MCP_SEED_FLAGS: self.assertIn(flag, flags, "worker 侧缺 %s,仓库 unit 已滞后于生产主机" % flag) def test_worker_side_flags_have_no_duplicates(self): _, worker_side = _split_sides() flags = _flag_tokens(worker_side) self.assertEqual(len(flags), len(set(flags)), "worker 侧 flag 重复:%s" % (flags,)) def test_worker_side_flags_are_defined_in_worker_parser(self): _, worker_side = _split_sides() with open(WORKER_PATH, encoding="utf-8") as f: worker_src = f.read() for flag in _flag_tokens(worker_side): self.assertIn('add_argument("%s"' % flag, worker_src, "%s 未在 cloud/worker.py 定义,worker 会报未知参数" % flag) def test_mcp_seed_flags_not_on_scaler_side(self): scaler_side, _ = _split_sides() flags = _flag_tokens(scaler_side) for flag in MCP_SEED_FLAGS: self.assertNotIn(flag, flags, "%s 不应出现在 scaler 侧(`--` 之前)" % flag) def test_worker_side_keeps_docker_runtime_runsc(self): _, worker_side = _split_sides() tokens = worker_side.split() self.assertIn("--docker-runtime", tokens) self.assertEqual(tokens[tokens.index("--docker-runtime") + 1], "runsc") if __name__ == "__main__": unittest.main()