| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081 |
- """契约一致校验(DB vs API 等价)。
- 对同一 mdp_std_* 表,比较 DB 路线批次(sync_batch_id LIKE 前缀 CT_DB_%)与
- API 路线批次(CT_API_%)在 source_biz_key 上的集合与行数是否一致。
- 用法:
- python verify_contract.py --table mdp_std_purchase_receipt
- # 自定义批次前缀:
- python verify_contract.py --table mdp_std_so --db-prefix CT_DB_ --api-prefix CT_API_
- 退出码:0=一致;1=不一致;2=两侧任一为空(未跑入站)。
- 前置:DB 路线与 API 路线两次入站都已完成,且分别以 CT_DB_/CT_API_ 前缀写入
- mdp_std_*.sync_batch_id(见任务书 §附录 E.2 / §附录 I 回归步骤)。
- """
- import argparse
- import sys
- from _db import query
- def main():
- ap = argparse.ArgumentParser()
- ap.add_argument("--table", required=True, help="目标 mdp_std_* 表名")
- ap.add_argument("--db-prefix", default="CT_DB_")
- ap.add_argument("--api-prefix", default="CT_API_")
- ap.add_argument("--key", default="source_biz_key", help="业务键列,默认 source_biz_key")
- args = ap.parse_args()
- t, k = args.table, args.key
- counts = query(
- f"""
- SELECT 'db' AS src, COUNT(*) AS row_cnt, COUNT(DISTINCT {k}) AS key_cnt
- FROM {t} WHERE sync_batch_id LIKE %s
- UNION ALL
- SELECT 'api', COUNT(*), COUNT(DISTINCT {k})
- FROM {t} WHERE sync_batch_id LIKE %s
- """,
- (args.db_prefix + "%", args.api_prefix + "%"),
- )
- by = {r["src"]: r for r in counts}
- db, api = by.get("db"), by.get("api")
- print(f"[counts] db={db} api={api}")
- if not db or not api or db["row_cnt"] == 0 or api["row_cnt"] == 0:
- print("[FAIL] 某一侧为空:请先分别跑 DB 与 API 入站。", file=sys.stderr)
- return 2
- only_db = query(
- f"""
- SELECT {k} AS biz FROM {t} WHERE sync_batch_id LIKE %s
- AND {k} NOT IN (SELECT {k} FROM {t} WHERE sync_batch_id LIKE %s)
- """,
- (args.db_prefix + "%", args.api_prefix + "%"),
- )
- only_api = query(
- f"""
- SELECT {k} AS biz FROM {t} WHERE sync_batch_id LIKE %s
- AND {k} NOT IN (SELECT {k} FROM {t} WHERE sync_batch_id LIKE %s)
- """,
- (args.api_prefix + "%", args.db_prefix + "%"),
- )
- ok = True
- if db["key_cnt"] != api["key_cnt"]:
- print(f"[FAIL] 键数不等:db={db['key_cnt']} api={api['key_cnt']}", file=sys.stderr)
- ok = False
- if only_db:
- print(f"[FAIL] DB 有 API 无 ({len(only_db)}):{[r['biz'] for r in only_db[:20]]}", file=sys.stderr)
- ok = False
- if only_api:
- print(f"[FAIL] API 有 DB 无 ({len(only_api)}):{[r['biz'] for r in only_api[:20]]}", file=sys.stderr)
- ok = False
- if ok:
- print("[PASS] DB 与 API 路线 source_biz_key 集合与行数一致。")
- return 0
- return 1
- if __name__ == "__main__":
- sys.exit(main())
|