Why: an update that stops the old process and overwrites the binary cannot get the previous version back, and a migration the old binary cannot read must be refused before that stop. CI also had no fixed RDM SHA to build from. Evidence: python3 -m unittest tests.test_svc_identity tests.test_svc_recover tests.test_svc_deploy_txn tests.test_lifecycle_pin passed. make test-lifecycle exits 2 when AGENT_PG_TEST_DSN is unset. Impact: installs land in releases/<rid> and current switches with mv -T. Deploy keeps the desired state and rolls back a non-terminal journal. Schema compatFloor above the installed target is refused unless --migrate-schema --confirm is paired with a backup. test-lifecycle fails closed without PostgreSQL and an RDM checkout. Login stays NOT_RUN. Refs: recovery plan r3.1 D2 and D3; Backend feature/d1-identity-open Co-authored-by: Cursor <cursoragent@cursor.com>
49 lines
1.8 KiB
Python
49 lines
1.8 KiB
Python
"""真实 Dev/RDM 组合门禁。由 make test-lifecycle 调用。
|
||
|
||
缺 PostgreSQL、RDM 源码或制品时直接失败,不静默跳过。
|
||
RDM 登录依赖账户 CLI 公共化(账户方案 U7/U5),当前标 NOT_RUN,本套件因此不能报完成。
|
||
"""
|
||
import os
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
ROOT = Path(__file__).resolve().parents[3]
|
||
PIN = Path(__file__).resolve().parent / "rdm.pin"
|
||
|
||
|
||
def main():
|
||
missing = []
|
||
if not os.environ.get("AGENT_PG_TEST_DSN"):
|
||
missing.append("AGENT_PG_TEST_DSN")
|
||
if not os.environ.get("SVC_RDM_SRC_DIR") or not Path(os.environ.get("SVC_RDM_SRC_DIR", "")).is_dir():
|
||
missing.append("SVC_RDM_SRC_DIR")
|
||
if not (ROOT / "bin" / "agent-system").is_file() and not os.environ.get("SVC_DEV_BIN"):
|
||
missing.append("Dev 制品(make build 或 SVC_DEV_BIN)")
|
||
print("组合清单")
|
||
print("pin", PIN.read_text().strip())
|
||
print("login NOT_RUN:RDM 二进制没有 user/apikey,工作台登录依赖账户 CLI 公共化")
|
||
scenarios = [
|
||
"双向混合批次更新",
|
||
"无 manifest 各入口一致",
|
||
"legacy/缺行/不匹配停服前拒绝",
|
||
"两次裸重启与换端口换版本换目录",
|
||
"构建失败与启动失败回滚",
|
||
"中断对账",
|
||
"PG 绑定与跨实例错绑拒绝",
|
||
"凭据不进 cmdline/日志",
|
||
"RDM 页面、rdm.ping、升级前领域数据仍在",
|
||
"登录",
|
||
]
|
||
for name in scenarios:
|
||
state = "NOT_RUN" if missing or name == "登录" else "PENDING"
|
||
print("%s %s" % (state, name))
|
||
if missing or True:
|
||
# 登录依赖未就绪时保持未完成。缺环境同样失败。
|
||
print("test-lifecycle 未完成。缺:%s" % (", ".join(missing) if missing else "登录入口"))
|
||
return 1
|
||
return 0
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|