"""在同一个 sw9 快照上核对优化前后接口,涵盖分页/排序及统计偏好。""" import argparse import json import urllib.parse import urllib.request from pathlib import Path import yaml from sw_database_rehearsal import connect, query def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--runtime", type=Path, required=True) parser.add_argument("--before-url", default="http://127.0.0.1:19002") parser.add_argument("--after-url", default="http://127.0.0.1:19004") parser.add_argument("--output", type=Path, required=True) args = parser.parse_args() if args.runtime.resolve().is_relative_to(Path(__file__).resolve().parents[1]): raise ValueError("原始响应必须保存在仓库外") config = yaml.safe_load((args.runtime / "config.yaml").read_text(encoding="utf-8"))["data"]["database"] if config["name"] != "sw9": raise ValueError("统计偏好测试仅允许 sw9") folder = args.runtime / "parity" folder.mkdir(exist_ok=True) reports = [] def api(base, token, path, params=None, payload=None): url = base + path + ("?" + urllib.parse.urlencode(params, doseq=True) if params else "") request = urllib.request.Request(url, headers={"x-token": token, "Content-Type": "application/json"}, data=json.dumps(payload).encode() if payload is not None else None, method="PUT" if payload is not None else "GET") with urllib.request.urlopen(request, timeout=300) as response: data = json.load(response) if data.get("code") != 0: raise RuntimeError("接口请求失败:" + path) return data["data"] def compare(case, token, group): values = [api(base, token, case["path"], case["params"]) for base in (args.before_url, args.after_url)] name = group + "-" + case["name"] (folder / (name + ".json")).write_text(json.dumps({"case": case, "before": values[0], "after": values[1]}, ensure_ascii=False, indent=2), encoding="utf-8") row = {"case": name, "passed": values[0] == values[1]} reports.append(row) args.output.write_text(json.dumps({"checks": reports, "passed": all(row["passed"] for row in reports)}, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") print(json.dumps(row), flush=True) if not row["passed"]: raise AssertionError("接口数据不一致:" + name) admin = (args.runtime / "new-admin.token").read_text(encoding="utf-8").strip() for case in json.loads((args.runtime / "parity-cases.json").read_text(encoding="utf-8")): compare(case, admin, "admin") token = (args.runtime / "new-level3.token").read_text(encoding="utf-8").strip() user = api(args.before_url, token, "/user/getUserInfo")["userInfo"]["ID"] original_preference = api(args.before_url, token, "/sw/user/preference") cases = json.loads((args.runtime / "cases.json").read_text(encoding="utf-8")) with connect(config) as db: original = query(db, "SELECT * FROM sw9.sys_user_preference WHERE user_id=%s", (user,)) try: for include, dedup in ((True, True), (True, False), (False, True), (False, False)): api(args.before_url, token, "/sw/user/preference", payload={"includeSubPromote": include, "idcardDedup": dedup}) for case in cases: compare(case, token, f"level3-sub{int(include)}-dedup{int(dedup)}") finally: try: api(args.before_url, token, "/sw/user/preference", payload=original_preference) finally: # Restore the row even if the service stopped during verification. if original: row = original[0] query(db, "UPDATE sw9.sys_user_preference SET include_sub_promote=%s,idcard_dedup=%s,update_time=%s WHERE user_id=%s", (row["include_sub_promote"], row["idcard_dedup"], row["update_time"], user)) else: query(db, "DELETE FROM sw9.sys_user_preference WHERE user_id=%s", (user,)) assert query(db, "SELECT * FROM sw9.sys_user_preference WHERE user_id=%s", (user,)) == original if __name__ == "__main__": main()