Files
kra-new/scripts/sw_endpoint_parity.py
T

80 lines
4.2 KiB
Python

"""在同一个 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()