You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

174 lines
9.0 KiB

2 weeks ago
import sys
import io
import requests
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
TOKEN = sys.argv[1]
BASE = "http://localhost:8080"
H = {"Authorization": f"Bearer {TOKEN}"}
OPP_ID = 999999999001
results = []
def check(name, resp, expect_code=0):
try:
d = resp.json()
ok = d.get("code") == expect_code
results.append((name, "OK" if ok else "FAIL", d.get("code"), str(d.get("message", ""))[:80]))
except Exception:
results.append((name, "FAIL", "parse_err", resp.text[:80]))
def check_page(name, resp):
try:
d = resp.json()
ok = d.get("code") == 0
data = d.get("data", {}) or {}
has_content = "content" in data
has_total = "total" in data
status = "OK" if (ok and has_content and has_total) else "FAIL"
results.append((name, status, d.get("code"), f"content:{has_content} total:{has_total}"))
except Exception:
results.append((name, "FAIL", "parse_err", resp.text[:80]))
# ===== 列表 =====
check_page("POST /api/opportunity/page",
requests.post(f"{BASE}/api/opportunity/page", headers=H, data={"pageNum": 1, "pageSize": 5}))
check_page("POST /api/opportunity/page?viewType=pool",
requests.post(f"{BASE}/api/opportunity/page", headers=H, data={"pageNum": 1, "pageSize": 5, "viewType": "pool"}))
# ===== 新建 =====
r = requests.post(f"{BASE}/api/opportunity", headers=H, data={"opportunityName": "端到端回归", "oppSource": "opp_source_02"})
check("POST /api/opportunity 新建", r)
# ===== 详情 + 编辑 =====
check("GET /api/opportunity/detail",
requests.get(f"{BASE}/api/opportunity/detail", headers=H, params={"id": OPP_ID}))
check("POST /api/opportunity/edit",
requests.post(f"{BASE}/api/opportunity/edit", headers=H,
data={"id": OPP_ID, "oppName": "端到端编辑验证", "remark": "e2e"}))
# ===== 状态机 =====
# 新建初始状态为"推进中",按实际出边顺序测:
# 推进中 -> pause -> resume -> handover -> release-pool -> claim -> release-pool -> assign -> close -> reopen
r_sm = requests.post(f"{BASE}/api/opportunity", headers=H,
data={"opportunityName": "sm-e2e", "oppSource": "opp_source_02"})
sm = r_sm.json().get("data") if r_sm.json().get("code") == 0 else None
if sm:
check("POST /pause (推进中->暂缓中)",
requests.post(f"{BASE}/api/opportunity/pause", headers=H, data={"id": sm, "pauseReason": "e2e"}))
check("POST /resume (暂缓中->推进中)",
requests.post(f"{BASE}/api/opportunity/resume", headers=H, data={"id": sm}))
check("POST /handover (推进中自环)",
requests.post(f"{BASE}/api/opportunity/handover", headers=H,
data={"id": sm, "expectedOwnerUserId": "739564171091247104",
"newOwnerUserId": "739564171091247104"}))
check("POST /release-pool (推进中->待领取)",
requests.post(f"{BASE}/api/opportunity/release-pool", headers=H, data={"id": sm, "poolReason": "e2e"}))
check("POST /claim (待领取->推进中)",
requests.post(f"{BASE}/api/opportunity/claim", headers=H, data={"id": sm}))
# release-pool 再次入池,然后 assign
requests.post(f"{BASE}/api/opportunity/release-pool", headers=H, data={"id": sm, "poolReason": "e2e-assign"})
check("POST /assign (待领取->推进中)",
requests.post(f"{BASE}/api/opportunity/assign", headers=H,
data={"id": sm, "userId": "739564171091247104"}))
check("POST /close (推进中->已关闭)",
requests.post(f"{BASE}/api/opportunity/close", headers=H, data={"id": sm, "closeReason": "e2e"}))
check("POST /reopen (已关闭->推进中)",
requests.post(f"{BASE}/api/opportunity/reopen", headers=H, data={"id": sm, "reopenReason": "e2e"}))
else:
for n in ["pause", "resume", "handover", "release-pool", "claim", "assign", "close", "reopen"]:
results.append((f"POST /{n}", "SKIP", "skip", "新建失败跳过"))
# ===== 方案卡 / 阶段 =====
check("GET /api/opportunity/scheme-card/list",
requests.get(f"{BASE}/api/opportunity/scheme-card/list", headers=H, params={"oppId": OPP_ID}))
check("GET /api/opportunity/stage/progress",
requests.get(f"{BASE}/api/opportunity/stage/progress", headers=H, params={"oppId": OPP_ID}))
# ===== 子域 =====
check("GET /customer/list",
requests.get(f"{BASE}/api/opportunity/customer/list", headers=H, params={"oppId": OPP_ID}))
check_page("POST /follow/page",
requests.post(f"{BASE}/api/opportunity/follow/page", headers=H,
data={"oppId": OPP_ID, "pageNum": 1, "pageSize": 5}))
r3 = requests.post(f"{BASE}/api/opportunity/follow/add", headers=H, data={
"oppId": OPP_ID, "followContent": "e2e跟进", "followTime": "2026-08-27 16:00:00",
"followWay": "PHONE", "customerId": 1})
check("POST /follow/add", r3)
fid = r3.json().get("data") if r3.json().get("code") == 0 else None
detail2 = requests.get(f"{BASE}/api/opportunity/detail", headers=H, params={"id": OPP_ID}).json()
lvft = detail2.get("data", {}).get("lastValidFollowTime", "")
lvft_ok = "2026-08-27" in str(lvft) if lvft else False
results.append(("last_valid_follow_time刷新", "OK" if lvft_ok else "FAIL", 0, f"={lvft}"))
if fid:
check("POST /follow/delete",
requests.post(f"{BASE}/api/opportunity/follow/delete", headers=H, params={"id": fid}))
log_resp = requests.post(f"{BASE}/api/opportunity/oplog/page", headers=H,
data={"oppId": OPP_ID, "pageNum": 1, "pageSize": 10}).json()
logs = log_resp.get("data", {}).get("content", [])
has_log = any(l.get("opKind") == "ROW_DELETE" for l in logs)
results.append(("deleteFollow写ROW_DELETE oplog", "OK" if has_log else "FAIL", 0, f"logs={len(logs)}"))
check_page("POST /site-survey/page",
requests.post(f"{BASE}/api/opportunity/site-survey/page", headers=H,
data={"oppId": OPP_ID, "pageNum": 1, "pageSize": 5}))
check("GET /attachment/list",
requests.get(f"{BASE}/api/opportunity/attachment/list", headers=H, params={"oppId": OPP_ID}))
check("GET /team/list",
requests.get(f"{BASE}/api/opportunity/team/list", headers=H, params={"oppId": OPP_ID}))
check_page("POST /oplog/page",
requests.post(f"{BASE}/api/opportunity/oplog/page", headers=H,
data={"oppId": OPP_ID, "pageNum": 1, "pageSize": 5}))
# ===== 协作 =====
check("POST /focus",
requests.post(f"{BASE}/api/opportunity/focus", headers=H, params={"oppId": OPP_ID}))
check("POST /unfocus",
requests.post(f"{BASE}/api/opportunity/unfocus", headers=H, params={"oppId": OPP_ID}))
check("POST /view-touch",
requests.post(f"{BASE}/api/opportunity/view-touch", headers=H, params={"oppId": OPP_ID}))
check("POST /board/stage-summary",
requests.post(f"{BASE}/api/opportunity/board/stage-summary", headers=H))
check("POST /board/cards",
requests.post(f"{BASE}/api/opportunity/board/cards", headers=H, data={"stageId": 0, "offset": 0, "limit": 5}))
# ===== 规则族 =====
check_page("POST /api/rule/opp-stage-template/page",
requests.post(f"{BASE}/api/rule/opp-stage-template/page", headers=H, data={"pageNum": 1, "pageSize": 5}))
check_page("POST /api/rule/opp-scheme-template/page",
requests.post(f"{BASE}/api/rule/opp-scheme-template/page", headers=H, data={"pageNum": 1, "pageSize": 5}))
check_page("POST /api/rule/opp-pool-rule/page",
requests.post(f"{BASE}/api/rule/opp-pool-rule/page", headers=H, data={"pageNum": 1, "pageSize": 5}))
check("GET /api/rule/opp-stage-template/versions",
requests.get(f"{BASE}/api/rule/opp-stage-template/versions", headers=H, params={"id": 747831302652166144}))
check("GET /api/rule/opp-scheme-template/versions",
requests.get(f"{BASE}/api/rule/opp-scheme-template/versions", headers=H, params={"id": 747831301075107840}))
check("GET /api/rule/opp-pool-rule/versions",
requests.get(f"{BASE}/api/rule/opp-pool-rule/versions", headers=H, params={"id": 999}))
# ===== 附件上限校验 =====
for i in range(10):
requests.post(f"{BASE}/api/opportunity/attachment/add", headers=H,
data={"oppId": OPP_ID, "fileId": 50000 + i, "bizType": "FOLLOW_UP", "bizId": 555})
over = requests.post(f"{BASE}/api/opportunity/attachment/add", headers=H,
data={"oppId": OPP_ID, "fileId": 59999, "bizType": "FOLLOW_UP", "bizId": 555})
d2 = over.json()
results.append(("附件10个上限校验", "OK" if d2.get("code") != 0 else "FAIL",
d2.get("code"), d2.get("message", "")[:50]))
# ===== 输出 =====
passed = sum(1 for _, s, _, _ in results if s == "OK")
failed = sum(1 for _, s, _, _ in results if s == "FAIL")
skipped = sum(1 for _, s, _, _ in results if s == "SKIP")
print(f"\n{'=' * 65}")
print(f"端到端回归:OK={passed} FAIL={failed} SKIP={skipped}{len(results)}")
print(f"{'=' * 65}")
for name, status, code, msg in results:
icon = {"OK": "[OK] ", "FAIL": "[FAIL]", "SKIP": "[SKIP]"}[status]
print(f"{icon} {name} | code:{code} | {msg}")