Merge branch 'main-merge-base-a'

# Conflicts:
#	deploy/dev/docker-compose.yml
#	deploy/dev/envoy.yaml
#	desc/api/dispute.api
#	desc/api/review.api
#	desc/api/search.api
This commit is contained in:
zetaloop
2026-04-25 05:42:42 +08:00
231 changed files with 34629 additions and 44 deletions
+243 -1
View File
@@ -926,6 +926,13 @@ def phase8_order(s_consumer: Session, s_actor: Session, player_id, service_id, s
report(f"POST /orders/{order_id}/reorder", code, body)
if order2_id:
code, body, _ = s_consumer.post(
f"{GATEWAY}/api/v1/orders/{order2_id}/pay",
json_body={},
headers=csrf,
)
report(f"POST /orders/{order2_id}/pay (before cancel)", code, body)
code, body, _ = s_consumer.post(
f"{GATEWAY}/api/v1/orders/{order2_id}/cancel",
json_body={},
@@ -947,6 +954,237 @@ def phase8_order(s_consumer: Session, s_actor: Session, player_id, service_id, s
return order_id
def phase8b_review(s_consumer: Session, order_id, player_id):
print("\n=== Phase 8b: Reviews ===")
if not order_id:
skip("Review flow", "No pending_review order id")
return
csrf = s_consumer.csrf_headers()
code, body, _ = s_consumer.post(
f"{GATEWAY}/api/v1/orders/{order_id}/review",
json_body={"rating": 5, "content": "great service"},
headers=csrf,
)
report(f"POST /orders/{order_id}/review", code, body)
code, body, _ = s_consumer.get(f"{GATEWAY}/api/v1/orders/{order_id}/reviews")
report(f"GET /orders/{order_id}/reviews", code, body)
if code == 200:
report_check(
f"GET /orders/{order_id}/reviews shape",
isinstance(pick_items(body), list) and isinstance(body.get("meta"), dict),
body,
)
code, body, _ = s_consumer.get(f"{GATEWAY}/api/v1/reviews?limit=20")
report("GET /reviews?limit=20", code, body)
if player_id:
code, body, _ = s_consumer.get(
f"{GATEWAY}/api/v1/users/{player_id}/reviews?limit=20",
)
report(f"GET /users/{player_id}/reviews?limit=20", code, body)
def phase8c_dispute(s_consumer: Session, s_actor: Session, player_id, service_id, shop_id):
print("\n=== Phase 8c: Disputes ===")
if not player_id or not service_id:
skip("Dispute flow", "Missing player or service id")
return 0
csrf = s_consumer.csrf_headers()
payload = {
"playerId": player_id,
"serviceId": service_id,
"quantity": 1,
"note": "test dispute order",
}
if shop_id:
payload["shopId"] = shop_id
code, body, _ = s_consumer.post(
f"{GATEWAY}/api/v1/orders",
json_body=payload,
headers=csrf,
)
report("POST /orders (create for dispute)", code, body)
order_obj = body.get("order", {}) if isinstance(body, dict) else {}
order_id = order_obj.get("id", 0) if isinstance(order_obj, dict) else 0
if not order_id:
skip("Dispute flow", "No order id returned")
return 0
code, body, _ = s_consumer.post(
f"{GATEWAY}/api/v1/orders/{order_id}/pay",
json_body={},
headers=csrf,
)
report(f"POST /orders/{order_id}/pay (dispute flow)", code, body)
code, body, _ = s_actor.post(
f"{GATEWAY}/api/v1/orders/{order_id}/accept",
json_body={},
headers=s_actor.csrf_headers(),
)
report(f"POST /orders/{order_id}/accept (dispute flow)", code, body)
code, body, _ = s_consumer.post(
f"{GATEWAY}/api/v1/orders/{order_id}/dispute",
json_body={
"reason": "test dispute reason",
"evidence": ["http://example.com/evidence.jpg"],
},
headers=csrf,
)
report(f"POST /orders/{order_id}/dispute", code, body)
code, body, _ = s_consumer.get(f"{GATEWAY}/api/v1/orders/{order_id}/dispute")
report(f"GET /orders/{order_id}/dispute", code, body)
dispute_id = as_int(body.get("id")) if isinstance(body, dict) else 0
code, body, _ = s_consumer.get(f"{GATEWAY}/api/v1/disputes")
report("GET /disputes", code, body)
code, body, _ = s_consumer.get(f"{GATEWAY}/api/v1/disputes?status=open")
report("GET /disputes?status=open", code, body)
if dispute_id:
code, body, _ = s_actor.post(
f"{GATEWAY}/api/v1/disputes/{dispute_id}/response",
json_body={
"reason": "test respondent guard",
"evidence": ["http://example.com/response.jpg"],
},
headers=s_actor.csrf_headers(),
)
report(
f"POST /disputes/{dispute_id}/response (expect participant check)",
code,
body,
expect_status=(400, 403, 500),
)
code, body, _ = s_consumer.post(
f"{GATEWAY}/api/v1/disputes/{dispute_id}/appeal",
json_body={"reason": "test appeal guard"},
headers=csrf,
)
report(
f"POST /disputes/{dispute_id}/appeal (expect status check)",
code,
body,
expect_status=(400, 403, 500),
)
return dispute_id
def phase8d_notifications(s: Session):
print("\n=== Phase 8d: Notifications ===")
code, body, _ = s.get(f"{GATEWAY}/api/v1/notifications")
report("GET /notifications", code, body)
items = pick_items(body) if code == 200 and isinstance(body, dict) else []
if items:
notification_id = as_int(items[0].get("id"))
if notification_id:
code, body, _ = s.put(
f"{GATEWAY}/api/v1/notifications/{notification_id}/read",
json_body={},
headers=s.csrf_headers(),
)
report(f"PUT /notifications/{notification_id}/read", code, body)
else:
skip("PUT /notifications/:id/read", "No notification item returned")
code, body, _ = s.put(
f"{GATEWAY}/api/v1/notifications/read-all",
json_body={},
headers=s.csrf_headers(),
)
report("PUT /notifications/read-all", code, body)
def phase8e_search_and_favorites(s: Session, user_id, player_id, shop_id):
print("\n=== Phase 8e: Search & Favorites ===")
code, body, _ = s.get(f"{GATEWAY}/api/v1/search?q=LOL&limit=10")
report("GET /search?q=LOL&limit=10", code, body)
if code == 200:
report_check(
"GET /search response shape",
isinstance(pick_items(body), list) and isinstance(body.get("meta"), dict),
body,
)
code, body, _ = s.get(f"{GATEWAY}/api/v1/recommendations/home?limit=10")
report("GET /recommendations/home?limit=10", code, body)
if code == 200:
report_check(
"GET /recommendations/home response shape",
isinstance(pick_items(body), list) and isinstance(body.get("meta"), dict),
body,
)
code, body, _ = s.get(f"{GATEWAY}/api/v1/favorites")
report("GET /favorites", code, body)
if not player_id or not user_id:
skip("Favorites mutation flow", "Missing user or player id")
return
code, body, _ = s.post(
f"{GATEWAY}/api/v1/favorites",
json_body={"targetType": "player", "targetId": str(player_id)},
headers=s.csrf_headers(),
)
report("POST /favorites (player)", code, body)
code, body, _ = s.get(
f"{GATEWAY}/api/v1/users/{user_id}/favorites/check"
f"?targetType=player&targetId={player_id}",
)
report(f"GET /users/{user_id}/favorites/check (player)", code, body)
if code == 200:
report_check("favorite check after add", body.get("favorited") is True, body)
if shop_id:
code, body, _ = s.post(
f"{GATEWAY}/api/v1/favorites",
json_body={"targetType": "shop", "targetId": str(shop_id)},
headers=s.csrf_headers(),
)
report("POST /favorites (shop)", code, body)
code, body, _ = s.get(f"{GATEWAY}/api/v1/favorites")
report("GET /favorites (after add)", code, body)
favorite_id = 0
for item in pick_items(body):
if (
item.get("targetType") == "player"
and str(item.get("targetId")) == str(player_id)
):
favorite_id = as_int(item.get("id"))
break
report_check("locate favorite id", bool(favorite_id), {"id": favorite_id})
if favorite_id:
code, body, _ = s.delete(
f"{GATEWAY}/api/v1/favorites/{favorite_id}",
headers=s.csrf_headers(),
)
report(f"DELETE /favorites/{favorite_id}", code, body)
code, body, _ = s.get(
f"{GATEWAY}/api/v1/users/{user_id}/favorites/check"
f"?targetType=player&targetId={player_id}",
)
report(f"GET /users/{user_id}/favorites/check (after delete)", code, body)
if code == 200:
report_check("favorite check after delete", body.get("favorited") is False, body)
def phase9_wallet(s: Session):
print("\n=== Phase 9: Wallet ===")
csrf = s.csrf_headers()
@@ -1242,7 +1480,11 @@ def main():
player_id, service_id = phase6_player(s_user, game_id)
shop_id = phase7_shop(s_user, s_consumer, user_id, invited_player_id)
phase8_order(s_consumer, s_user, player_id, service_id, shop_id)
order_id = phase8_order(s_consumer, s_user, player_id, service_id, shop_id)
phase8b_review(s_consumer, order_id, player_id)
phase8c_dispute(s_consumer, s_user, player_id, service_id, shop_id)
phase8d_notifications(s_consumer)
phase8e_search_and_favorites(s_consumer, consumer_user_id, player_id, shop_id)
phase9_wallet(s_user)
phase10_community(s_user, user_id)
phase11_objectstory(s_user)