90c0d65a16
Co-authored-by: OuYingJun1024 <1034284404@qq.com> Reviewed-on: #11 Co-authored-by: ouzhou <ouzhou@wonderable.ai> Co-committed-by: ouzhou <ouzhou@wonderable.ai>
137 lines
5.5 KiB
Python
137 lines
5.5 KiB
Python
"""比价战绩里程碑测试:进度随成功比价数解锁 / 逐档领奖发金币 / 幂等 / 边界。
|
|
|
|
复用比价记录上报接口造成功记录(每条 trace 一次成功比价),再验里程碑。
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from app.core.rewards import RECORD_MILESTONES
|
|
|
|
|
|
def _login(client, phone: str) -> str:
|
|
client.post("/api/v1/auth/sms/send", json={"phone": phone})
|
|
r = client.post("/api/v1/auth/sms/login", json={"phone": phone, "code": "123456"})
|
|
assert r.status_code == 200, r.text
|
|
return r.json()["access_token"]
|
|
|
|
|
|
def _auth(token: str) -> dict[str, str]:
|
|
return {"Authorization": f"Bearer {token}"}
|
|
|
|
|
|
def _report_success(client, token: str, trace_id: str) -> None:
|
|
"""上报一条成功比价(有非源有效价 → status 派生 success)。"""
|
|
payload = {
|
|
"trace_id": trace_id,
|
|
"business_type": "food",
|
|
"store_name": "测试店",
|
|
"source_platform_id": "taobao_flash",
|
|
"source_price": 30.0,
|
|
"comparison_results": [
|
|
{"platform_id": "meituan", "platform_name": "美团", "price": 25.0,
|
|
"is_source": False, "rank": 1},
|
|
{"platform_id": "taobao_flash", "platform_name": "淘宝闪购", "price": 30.0,
|
|
"is_source": True, "rank": 2},
|
|
],
|
|
}
|
|
r = client.post("/api/v1/compare/record", json=payload, headers=_auth(token))
|
|
assert r.status_code == 200, r.text
|
|
|
|
|
|
def _report_failed(client, token: str, trace_id: str) -> None:
|
|
"""上报一条失败比价(只有源 → status 派生 failed,不计入解锁)。"""
|
|
payload = {
|
|
"trace_id": trace_id,
|
|
"business_type": "food",
|
|
"comparison_results": [
|
|
{"platform_id": "taobao_flash", "platform_name": "淘宝闪购", "price": 30.0,
|
|
"is_source": True, "rank": 1},
|
|
],
|
|
}
|
|
r = client.post("/api/v1/compare/record", json=payload, headers=_auth(token))
|
|
assert r.status_code == 200, r.text
|
|
|
|
|
|
def test_status_empty(client) -> None:
|
|
"""没比价过:成功数 0,所有档 locked,无可领。"""
|
|
token = _login(client, "13800003001")
|
|
r = client.get("/api/v1/compare/milestones", headers=_auth(token))
|
|
assert r.status_code == 200, r.text
|
|
d = r.json()
|
|
assert d["success_count"] == 0
|
|
assert d["claimable_count"] == 0
|
|
assert len(d["milestones"]) == len(RECORD_MILESTONES)
|
|
assert all(m["state"] == "locked" for m in d["milestones"])
|
|
# 第 1 档金币对齐配置
|
|
assert d["milestones"][0]["coin"] == RECORD_MILESTONES[0]
|
|
assert d["milestones"][0]["milestone"] == 1
|
|
|
|
|
|
def test_unlock_progresses_with_success(client) -> None:
|
|
"""成功比价 2 次:前 2 档 active 可领,其余 locked。失败记录不计入。"""
|
|
token = _login(client, "13800003002")
|
|
_report_success(client, token, "s-1")
|
|
_report_success(client, token, "s-2")
|
|
_report_failed(client, token, "f-1") # 失败不计
|
|
|
|
d = client.get("/api/v1/compare/milestones", headers=_auth(token)).json()
|
|
assert d["success_count"] == 2
|
|
assert d["claimable_count"] == 2
|
|
states = [m["state"] for m in d["milestones"]]
|
|
assert states[0] == "active"
|
|
assert states[1] == "active"
|
|
assert states[2] == "locked"
|
|
|
|
|
|
def test_claim_marks_claimed_without_coin(client) -> None:
|
|
"""领第 1 档:暂不真发金币(产品定,后续删该功能),余额不变,但该档变 claimed。"""
|
|
token = _login(client, "13800003003")
|
|
_report_success(client, token, "s-1")
|
|
|
|
bal_before = client.get("/api/v1/wallet/account", headers=_auth(token)).json()["coin_balance"]
|
|
|
|
r = client.post("/api/v1/compare/milestones/1/claim", headers=_auth(token))
|
|
assert r.status_code == 200, r.text
|
|
res = r.json()
|
|
assert res["milestone"] == 1
|
|
assert res["coin_awarded"] == 0 # 不再发金币
|
|
assert res["coin_balance"] == bal_before # 余额不变
|
|
|
|
d = client.get("/api/v1/compare/milestones", headers=_auth(token)).json()
|
|
assert d["milestones"][0]["state"] == "claimed"
|
|
assert d["claimable_count"] == 0 # 第 1 档领掉了,成功数 1 没解锁第 2 档
|
|
|
|
|
|
def test_claim_idempotent_409(client) -> None:
|
|
"""同档重复领 → 409,且不重复发金币。"""
|
|
token = _login(client, "13800003004")
|
|
_report_success(client, token, "s-1")
|
|
assert client.post("/api/v1/compare/milestones/1/claim", headers=_auth(token)).status_code == 200
|
|
bal = client.get("/api/v1/wallet/account", headers=_auth(token)).json()["coin_balance"]
|
|
|
|
r = client.post("/api/v1/compare/milestones/1/claim", headers=_auth(token))
|
|
assert r.status_code == 409
|
|
bal2 = client.get("/api/v1/wallet/account", headers=_auth(token)).json()["coin_balance"]
|
|
assert bal2 == bal # 没重复发
|
|
|
|
|
|
def test_claim_locked_409(client) -> None:
|
|
"""领还没解锁的档(成功数不够)→ 409 locked。"""
|
|
token = _login(client, "13800003005")
|
|
_report_success(client, token, "s-1") # 只解锁第 1 档
|
|
r = client.post("/api/v1/compare/milestones/2/claim", headers=_auth(token))
|
|
assert r.status_code == 409
|
|
|
|
|
|
def test_claim_unknown_milestone_404(client) -> None:
|
|
"""档位越界 → 404。"""
|
|
token = _login(client, "13800003006")
|
|
assert client.post("/api/v1/compare/milestones/0/claim", headers=_auth(token)).status_code == 404
|
|
big = len(RECORD_MILESTONES) + 1
|
|
assert client.post(f"/api/v1/compare/milestones/{big}/claim", headers=_auth(token)).status_code == 404
|
|
|
|
|
|
def test_requires_auth(client) -> None:
|
|
"""不带 token → 401。"""
|
|
assert client.get("/api/v1/compare/milestones").status_code == 401
|
|
assert client.post("/api/v1/compare/milestones/1/claim").status_code == 401
|