fix: 修复 player 详情 completionRate 和 k8s 公开路由
同步 k8s Envoy 中已放行公开接口的实际路由,避免落到泛用 user API;同时规范 dev API 测试脚本的响应体解析,使新增负向断言通过静态检查。
This commit is contained in:
@@ -45,15 +45,20 @@ func (l *GetPlayerLogic) GetPlayer(req *types.GetPlayerReq) (resp *types.PlayerP
|
|||||||
if player == nil {
|
if player == nil {
|
||||||
return nil, errors.New("player not found")
|
return nil, errors.New("player not found")
|
||||||
}
|
}
|
||||||
|
completionRate := 0.0
|
||||||
|
if player.TotalOrders > 0 {
|
||||||
|
completionRate = float64(player.CompletedOrders) / float64(player.TotalOrders)
|
||||||
|
}
|
||||||
|
|
||||||
resp = &types.PlayerProfile{
|
resp = &types.PlayerProfile{
|
||||||
Id: player.Id,
|
Id: player.Id,
|
||||||
Rating: player.Rating,
|
Rating: player.Rating,
|
||||||
TotalOrders: player.TotalOrders,
|
TotalOrders: player.TotalOrders,
|
||||||
Status: player.Status,
|
CompletionRate: completionRate,
|
||||||
Gender: player.Gender,
|
Status: player.Status,
|
||||||
Services: []types.PlayerService{},
|
Gender: player.Gender,
|
||||||
Tags: append([]string{}, player.Tags...),
|
Services: []types.PlayerService{},
|
||||||
|
Tags: append([]string{}, player.Tags...),
|
||||||
}
|
}
|
||||||
|
|
||||||
games := make([]string, 0, len(player.Games))
|
games := make([]string, 0, len(player.Games))
|
||||||
|
|||||||
+209
-94
@@ -16,7 +16,12 @@ import urllib.parse
|
|||||||
import http.cookiejar
|
import http.cookiejar
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
from collections.abc import Callable
|
||||||
from decimal import Decimal, InvalidOperation
|
from decimal import Decimal, InvalidOperation
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
Body = dict[str, Any]
|
||||||
|
StatusExpectation = int | tuple[int, ...] | list[int] | set[int]
|
||||||
|
|
||||||
GATEWAY = "http://127.0.0.1:18080"
|
GATEWAY = "http://127.0.0.1:18080"
|
||||||
ADMIN_USERNAME = os.getenv("ADMIN_USERNAME", "admin")
|
ADMIN_USERNAME = os.getenv("ADMIN_USERNAME", "admin")
|
||||||
@@ -50,7 +55,19 @@ def same_id(left, right):
|
|||||||
return str(left) == str(right)
|
return str(left) == str(right)
|
||||||
|
|
||||||
|
|
||||||
def body_text(body):
|
def response_body(data: str) -> Body:
|
||||||
|
if not data:
|
||||||
|
return {}
|
||||||
|
try:
|
||||||
|
parsed = json.loads(data)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
return {"_raw": data}
|
||||||
|
if isinstance(parsed, dict):
|
||||||
|
return parsed
|
||||||
|
return {"_raw": parsed}
|
||||||
|
|
||||||
|
|
||||||
|
def body_text(body: object):
|
||||||
if not isinstance(body, dict):
|
if not isinstance(body, dict):
|
||||||
return str(body)
|
return str(body)
|
||||||
if "_raw" in body:
|
if "_raw" in body:
|
||||||
@@ -72,15 +89,17 @@ def report_rejected(name, status_code, body, expect_status=(400, 403, 500)):
|
|||||||
report_check(f"{name} returns error body", bool(body_text(body)), body)
|
report_check(f"{name} returns error body", bool(body_text(body)), body)
|
||||||
|
|
||||||
|
|
||||||
def pick_items(body):
|
def pick_items(body: object) -> list[Body]:
|
||||||
|
if not isinstance(body, dict):
|
||||||
|
return []
|
||||||
if isinstance(body.get("items"), list):
|
if isinstance(body.get("items"), list):
|
||||||
return body["items"]
|
return [item for item in body["items"] if isinstance(item, dict)]
|
||||||
if isinstance(body.get("list"), list):
|
if isinstance(body.get("list"), list):
|
||||||
return body["list"]
|
return [item for item in body["list"] if isinstance(item, dict)]
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
def find_item(items, predicate):
|
def find_item(items: list[Body], predicate: Callable[[Body], bool]) -> Body | None:
|
||||||
for item in items:
|
for item in items:
|
||||||
if predicate(item):
|
if predicate(item):
|
||||||
return item
|
return item
|
||||||
@@ -91,7 +110,7 @@ def find_item_by_id(items, item_id):
|
|||||||
return find_item(items, lambda item: same_id(item.get("id"), item_id))
|
return find_item(items, lambda item: same_id(item.get("id"), item_id))
|
||||||
|
|
||||||
|
|
||||||
def user_from(body):
|
def user_from(body: Body) -> Body:
|
||||||
user = body.get("user") if isinstance(body, dict) else None
|
user = body.get("user") if isinstance(body, dict) else None
|
||||||
return user if isinstance(user, dict) else {}
|
return user if isinstance(user, dict) else {}
|
||||||
|
|
||||||
@@ -186,7 +205,7 @@ class Session:
|
|||||||
headers=None,
|
headers=None,
|
||||||
form_data=None,
|
form_data=None,
|
||||||
raw_body=None,
|
raw_body=None,
|
||||||
):
|
) -> tuple[int, Body, dict[str, str]]:
|
||||||
hdrs = headers or {}
|
hdrs = headers or {}
|
||||||
body = None
|
body = None
|
||||||
if json_body is not None:
|
if json_body is not None:
|
||||||
@@ -202,35 +221,31 @@ class Session:
|
|||||||
try:
|
try:
|
||||||
resp = self.opener.open(req, timeout=15)
|
resp = self.opener.open(req, timeout=15)
|
||||||
data = resp.read().decode()
|
data = resp.read().decode()
|
||||||
try:
|
return resp.status, response_body(data), dict(resp.headers)
|
||||||
return resp.status, json.loads(data) if data else {}, dict(resp.headers)
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
return resp.status, {"_raw": data}, dict(resp.headers)
|
|
||||||
except urllib.error.HTTPError as e:
|
except urllib.error.HTTPError as e:
|
||||||
data = e.read().decode() if e.fp else ""
|
data = e.read().decode() if e.fp else ""
|
||||||
try:
|
return e.code, response_body(data), dict(e.headers)
|
||||||
return e.code, json.loads(data) if data else {}, dict(e.headers)
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
return e.code, {"_raw": data}, dict(e.headers)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return 0, {"_error": str(e)}, {}
|
return 0, {"_error": str(e)}, {}
|
||||||
|
|
||||||
def get(self, url, **kw):
|
def get(self, url, **kw) -> tuple[int, Body, dict[str, str]]:
|
||||||
return self.request("GET", url, **kw)
|
return self.request("GET", url, **kw)
|
||||||
|
|
||||||
def post(self, url, **kw):
|
def post(self, url, **kw) -> tuple[int, Body, dict[str, str]]:
|
||||||
return self.request("POST", url, **kw)
|
return self.request("POST", url, **kw)
|
||||||
|
|
||||||
def post_multipart(self, url, fields, files, headers=None):
|
def post_multipart(
|
||||||
|
self, url, fields, files, headers=None
|
||||||
|
) -> tuple[int, Body, dict[str, str]]:
|
||||||
hdrs = dict(headers or {})
|
hdrs = dict(headers or {})
|
||||||
content_type, body = build_multipart_form(fields, files)
|
content_type, body = build_multipart_form(fields, files)
|
||||||
hdrs["Content-Type"] = content_type
|
hdrs["Content-Type"] = content_type
|
||||||
return self.post(url, headers=hdrs, raw_body=body)
|
return self.post(url, headers=hdrs, raw_body=body)
|
||||||
|
|
||||||
def put(self, url, **kw):
|
def put(self, url, **kw) -> tuple[int, Body, dict[str, str]]:
|
||||||
return self.request("PUT", url, **kw)
|
return self.request("PUT", url, **kw)
|
||||||
|
|
||||||
def delete(self, url, **kw):
|
def delete(self, url, **kw) -> tuple[int, Body, dict[str, str]]:
|
||||||
return self.request("DELETE", url, **kw)
|
return self.request("DELETE", url, **kw)
|
||||||
|
|
||||||
def csrf_headers(self):
|
def csrf_headers(self):
|
||||||
@@ -238,7 +253,7 @@ class Session:
|
|||||||
return {"xsrf-token": token} if token else {}
|
return {"xsrf-token": token} if token else {}
|
||||||
|
|
||||||
|
|
||||||
def report(name, status_code, body, expect_status=200):
|
def report(name, status_code, body, expect_status: StatusExpectation = 200):
|
||||||
global passed, failed
|
global passed, failed
|
||||||
if isinstance(expect_status, (list, tuple, set)):
|
if isinstance(expect_status, (list, tuple, set)):
|
||||||
ok = status_code in expect_status
|
ok = status_code in expect_status
|
||||||
@@ -276,7 +291,7 @@ def skip(name, reason):
|
|||||||
print(f" [SKIP] {name}: {reason}")
|
print(f" [SKIP] {name}: {reason}")
|
||||||
|
|
||||||
|
|
||||||
def check_order_status(session, order_id, expected_status, label):
|
def check_order_status(session, order_id, expected_status, label) -> Body:
|
||||||
code, body, _ = session.get(f"{GATEWAY}/api/v1/orders/{order_id}")
|
code, body, _ = session.get(f"{GATEWAY}/api/v1/orders/{order_id}")
|
||||||
report(f"GET /orders/{order_id} ({label})", code, body)
|
report(f"GET /orders/{order_id} ({label})", code, body)
|
||||||
report_check(
|
report_check(
|
||||||
@@ -521,8 +536,9 @@ def phase3_admin_and_verification(
|
|||||||
all(
|
all(
|
||||||
find_item(
|
find_item(
|
||||||
pick_items(body),
|
pick_items(body),
|
||||||
lambda item, role=role: item.get("role") == role
|
lambda item, role=role: (
|
||||||
and item.get("status") == "pending",
|
item.get("role") == role and item.get("status") == "pending"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
for role in ("player", "owner")
|
for role in ("player", "owner")
|
||||||
),
|
),
|
||||||
@@ -539,8 +555,9 @@ def phase3_admin_and_verification(
|
|||||||
bool(
|
bool(
|
||||||
find_item(
|
find_item(
|
||||||
pick_items(body),
|
pick_items(body),
|
||||||
lambda item: item.get("role") == "owner"
|
lambda item: (
|
||||||
and item.get("status") == "pending",
|
item.get("role") == "owner" and item.get("status") == "pending"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
body,
|
body,
|
||||||
@@ -586,9 +603,11 @@ def phase3_admin_and_verification(
|
|||||||
bool(
|
bool(
|
||||||
find_item(
|
find_item(
|
||||||
pick_items(body),
|
pick_items(body),
|
||||||
lambda item: item.get("role") == "owner"
|
lambda item: (
|
||||||
and item.get("status") == "rejected"
|
item.get("role") == "owner"
|
||||||
and item.get("rejectReason") == "test reject flow",
|
and item.get("status") == "rejected"
|
||||||
|
and item.get("rejectReason") == "test reject flow"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
body,
|
body,
|
||||||
@@ -671,8 +690,9 @@ def phase3b_secondary_player(s_admin: Session, s_player: Session):
|
|||||||
bool(
|
bool(
|
||||||
find_item(
|
find_item(
|
||||||
pick_items(body),
|
pick_items(body),
|
||||||
lambda item: item.get("role") == "player"
|
lambda item: (
|
||||||
and item.get("status") == "pending",
|
item.get("role") == "player" and item.get("status") == "pending"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
body,
|
body,
|
||||||
@@ -698,7 +718,9 @@ def phase3b_secondary_player(s_admin: Session, s_player: Session):
|
|||||||
report("POST /users/me/switch-role (invited user player)", code, body)
|
report("POST /users/me/switch-role (invited user player)", code, body)
|
||||||
code, body, _ = s_player.get(f"{GATEWAY}/api/v1/users/me")
|
code, body, _ = s_player.get(f"{GATEWAY}/api/v1/users/me")
|
||||||
report("GET /users/me (invited user player role)", code, body)
|
report("GET /users/me (invited user player role)", code, body)
|
||||||
report_check("invited user current role is player", body.get("role") == "player", body)
|
report_check(
|
||||||
|
"invited user current role is player", body.get("role") == "player", body
|
||||||
|
)
|
||||||
|
|
||||||
code, body, _ = s_player.post(
|
code, body, _ = s_player.post(
|
||||||
f"{GATEWAY}/api/v1/players/me",
|
f"{GATEWAY}/api/v1/players/me",
|
||||||
@@ -739,7 +761,9 @@ def phase5_games(s: Session, s_admin: Session):
|
|||||||
|
|
||||||
code, body, _ = s.get(f"{GATEWAY}/api/v1/games")
|
code, body, _ = s.get(f"{GATEWAY}/api/v1/games")
|
||||||
report("GET /games", code, body)
|
report("GET /games", code, body)
|
||||||
report_check("GET /games returns list shape", isinstance(pick_items(body), list), body)
|
report_check(
|
||||||
|
"GET /games returns list shape", isinstance(pick_items(body), list), body
|
||||||
|
)
|
||||||
|
|
||||||
csrf_admin = s_admin.csrf_headers()
|
csrf_admin = s_admin.csrf_headers()
|
||||||
game_name = f"TestGame_{rand_str(4)}"
|
game_name = f"TestGame_{rand_str(4)}"
|
||||||
@@ -820,7 +844,9 @@ def phase6_player(s: Session, game_id):
|
|||||||
|
|
||||||
code, body, _ = s.get(f"{GATEWAY}/api/v1/players")
|
code, body, _ = s.get(f"{GATEWAY}/api/v1/players")
|
||||||
report("GET /players", code, body)
|
report("GET /players", code, body)
|
||||||
report_check("GET /players returns list shape", isinstance(pick_items(body), list), body)
|
report_check(
|
||||||
|
"GET /players returns list shape", isinstance(pick_items(body), list), body
|
||||||
|
)
|
||||||
|
|
||||||
if player_id:
|
if player_id:
|
||||||
code, body, _ = s.get(f"{GATEWAY}/api/v1/players/{player_id}")
|
code, body, _ = s.get(f"{GATEWAY}/api/v1/players/{player_id}")
|
||||||
@@ -866,7 +892,9 @@ def phase6_player(s: Session, game_id):
|
|||||||
|
|
||||||
code, body, _ = s.get(f"{GATEWAY}/api/v1/services")
|
code, body, _ = s.get(f"{GATEWAY}/api/v1/services")
|
||||||
report("GET /services", code, body)
|
report("GET /services", code, body)
|
||||||
report_check("GET /services returns list shape", isinstance(pick_items(body), list), body)
|
report_check(
|
||||||
|
"GET /services returns list shape", isinstance(pick_items(body), list), body
|
||||||
|
)
|
||||||
|
|
||||||
service_id = svc_body.get("id", 0) if svc_body else 0
|
service_id = svc_body.get("id", 0) if svc_body else 0
|
||||||
if service_id:
|
if service_id:
|
||||||
@@ -1058,7 +1086,8 @@ def phase7_shop(
|
|||||||
report(f"GET /shops/{shop_id} (after announcement delete)", code, body)
|
report(f"GET /shops/{shop_id} (after announcement delete)", code, body)
|
||||||
report_check(
|
report_check(
|
||||||
"deleted announcement is absent",
|
"deleted announcement is absent",
|
||||||
announcement not in [str(item) for item in body.get("announcements") or []],
|
announcement
|
||||||
|
not in [str(item) for item in body.get("announcements") or []],
|
||||||
body,
|
body,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1155,7 +1184,9 @@ def phase7_shop(
|
|||||||
code, body, _ = s_owner.get(
|
code, body, _ = s_owner.get(
|
||||||
f"{GATEWAY}/api/v1/shops/{shop_id}/invitations",
|
f"{GATEWAY}/api/v1/shops/{shop_id}/invitations",
|
||||||
)
|
)
|
||||||
report(f"GET /shops/{shop_id}/invitations (after wrong accept)", code, body)
|
report(
|
||||||
|
f"GET /shops/{shop_id}/invitations (after wrong accept)", code, body
|
||||||
|
)
|
||||||
pending_invitation = find_item_by_id(pick_items(body), invitation_id)
|
pending_invitation = find_item_by_id(pick_items(body), invitation_id)
|
||||||
report_check(
|
report_check(
|
||||||
"wrong invitation accept keeps status pending",
|
"wrong invitation accept keeps status pending",
|
||||||
@@ -1248,7 +1279,9 @@ def phase7_shop(
|
|||||||
code, body, _ = s_owner.get(
|
code, body, _ = s_owner.get(
|
||||||
f"{GATEWAY}/api/v1/shops/{shop_id}/invitations",
|
f"{GATEWAY}/api/v1/shops/{shop_id}/invitations",
|
||||||
)
|
)
|
||||||
report(f"GET /shops/{shop_id}/invitations (after reject)", code, body)
|
report(
|
||||||
|
f"GET /shops/{shop_id}/invitations (after reject)", code, body
|
||||||
|
)
|
||||||
rejected = find_item_by_id(pick_items(body), reinvite_id)
|
rejected = find_item_by_id(pick_items(body), reinvite_id)
|
||||||
report_check(
|
report_check(
|
||||||
"rejected invitation has rejected status",
|
"rejected invitation has rejected status",
|
||||||
@@ -1260,7 +1293,9 @@ def phase7_shop(
|
|||||||
|
|
||||||
code, body, _ = s_owner.get(f"{GATEWAY}/api/v1/shops/mine")
|
code, body, _ = s_owner.get(f"{GATEWAY}/api/v1/shops/mine")
|
||||||
report("GET /shops/mine", code, body)
|
report("GET /shops/mine", code, body)
|
||||||
report_check("GET /shops/mine returns owned shop", same_id(body.get("id"), shop_id), body)
|
report_check(
|
||||||
|
"GET /shops/mine returns owned shop", same_id(body.get("id"), shop_id), body
|
||||||
|
)
|
||||||
|
|
||||||
return shop_id
|
return shop_id
|
||||||
|
|
||||||
@@ -1331,7 +1366,9 @@ def phase8_order(s_consumer: Session, s_actor: Session, player_id, service_id, s
|
|||||||
)
|
)
|
||||||
|
|
||||||
if order_id:
|
if order_id:
|
||||||
body = check_order_status(s_consumer, order_id, "pending_payment", "after create")
|
body = check_order_status(
|
||||||
|
s_consumer, order_id, "pending_payment", "after create"
|
||||||
|
)
|
||||||
report_check(
|
report_check(
|
||||||
"created order detail matches participants",
|
"created order detail matches participants",
|
||||||
same_id(body.get("consumerId"), consumer_user_id)
|
same_id(body.get("consumerId"), consumer_user_id)
|
||||||
@@ -1348,15 +1385,21 @@ def phase8_order(s_consumer: Session, s_actor: Session, player_id, service_id, s
|
|||||||
headers=s_actor.csrf_headers(),
|
headers=s_actor.csrf_headers(),
|
||||||
)
|
)
|
||||||
report_rejected(f"POST /orders/{order_id}/accept (before pay)", code, body)
|
report_rejected(f"POST /orders/{order_id}/accept (before pay)", code, body)
|
||||||
check_order_status(s_consumer, order_id, "pending_payment", "after early accept")
|
check_order_status(
|
||||||
|
s_consumer, order_id, "pending_payment", "after early accept"
|
||||||
|
)
|
||||||
|
|
||||||
code, body, _ = s_consumer.post(
|
code, body, _ = s_consumer.post(
|
||||||
f"{GATEWAY}/api/v1/orders/{order_id}/confirm-close",
|
f"{GATEWAY}/api/v1/orders/{order_id}/confirm-close",
|
||||||
json_body={},
|
json_body={},
|
||||||
headers=csrf,
|
headers=csrf,
|
||||||
)
|
)
|
||||||
report_rejected(f"POST /orders/{order_id}/confirm-close (before close request)", code, body)
|
report_rejected(
|
||||||
check_order_status(s_consumer, order_id, "pending_payment", "after early confirm-close")
|
f"POST /orders/{order_id}/confirm-close (before close request)", code, body
|
||||||
|
)
|
||||||
|
check_order_status(
|
||||||
|
s_consumer, order_id, "pending_payment", "after early confirm-close"
|
||||||
|
)
|
||||||
|
|
||||||
code, body, _ = s_consumer.post(
|
code, body, _ = s_consumer.post(
|
||||||
f"{GATEWAY}/api/v1/orders/{order_id}/pay",
|
f"{GATEWAY}/api/v1/orders/{order_id}/pay",
|
||||||
@@ -1371,8 +1414,12 @@ def phase8_order(s_consumer: Session, s_actor: Session, player_id, service_id, s
|
|||||||
json_body={},
|
json_body={},
|
||||||
headers=s_actor.csrf_headers(),
|
headers=s_actor.csrf_headers(),
|
||||||
)
|
)
|
||||||
report_rejected(f"POST /orders/{order_id}/request-close (before accept)", code, body)
|
report_rejected(
|
||||||
check_order_status(s_consumer, order_id, "pending_accept", "after early request-close")
|
f"POST /orders/{order_id}/request-close (before accept)", code, body
|
||||||
|
)
|
||||||
|
check_order_status(
|
||||||
|
s_consumer, order_id, "pending_accept", "after early request-close"
|
||||||
|
)
|
||||||
|
|
||||||
code, body, _ = s_consumer.post(
|
code, body, _ = s_consumer.post(
|
||||||
f"{GATEWAY}/api/v1/orders/{order_id}/pay",
|
f"{GATEWAY}/api/v1/orders/{order_id}/pay",
|
||||||
@@ -1380,7 +1427,9 @@ def phase8_order(s_consumer: Session, s_actor: Session, player_id, service_id, s
|
|||||||
headers=csrf,
|
headers=csrf,
|
||||||
)
|
)
|
||||||
report_rejected(f"POST /orders/{order_id}/pay (second time)", code, body)
|
report_rejected(f"POST /orders/{order_id}/pay (second time)", code, body)
|
||||||
check_order_status(s_consumer, order_id, "pending_accept", "after duplicate pay")
|
check_order_status(
|
||||||
|
s_consumer, order_id, "pending_accept", "after duplicate pay"
|
||||||
|
)
|
||||||
|
|
||||||
code, body, _ = s_actor.post(
|
code, body, _ = s_actor.post(
|
||||||
f"{GATEWAY}/api/v1/orders/{order_id}/accept",
|
f"{GATEWAY}/api/v1/orders/{order_id}/accept",
|
||||||
@@ -1389,15 +1438,21 @@ def phase8_order(s_consumer: Session, s_actor: Session, player_id, service_id, s
|
|||||||
)
|
)
|
||||||
report(f"POST /orders/{order_id}/accept", code, body)
|
report(f"POST /orders/{order_id}/accept", code, body)
|
||||||
body = check_order_status(s_consumer, order_id, "in_progress", "after accept")
|
body = check_order_status(s_consumer, order_id, "in_progress", "after accept")
|
||||||
report_check("accepted order has acceptedAt", bool(body.get("acceptedAt")), body)
|
report_check(
|
||||||
|
"accepted order has acceptedAt", bool(body.get("acceptedAt")), body
|
||||||
|
)
|
||||||
|
|
||||||
code, body, _ = s_consumer.post(
|
code, body, _ = s_consumer.post(
|
||||||
f"{GATEWAY}/api/v1/orders/{order_id}/confirm-close",
|
f"{GATEWAY}/api/v1/orders/{order_id}/confirm-close",
|
||||||
json_body={},
|
json_body={},
|
||||||
headers=csrf,
|
headers=csrf,
|
||||||
)
|
)
|
||||||
report_rejected(f"POST /orders/{order_id}/confirm-close (before request-close)", code, body)
|
report_rejected(
|
||||||
check_order_status(s_consumer, order_id, "in_progress", "after early confirm-close")
|
f"POST /orders/{order_id}/confirm-close (before request-close)", code, body
|
||||||
|
)
|
||||||
|
check_order_status(
|
||||||
|
s_consumer, order_id, "in_progress", "after early confirm-close"
|
||||||
|
)
|
||||||
|
|
||||||
code, body, _ = s_actor.post(
|
code, body, _ = s_actor.post(
|
||||||
f"{GATEWAY}/api/v1/orders/{order_id}/request-close",
|
f"{GATEWAY}/api/v1/orders/{order_id}/request-close",
|
||||||
@@ -1413,7 +1468,9 @@ def phase8_order(s_consumer: Session, s_actor: Session, player_id, service_id, s
|
|||||||
headers=csrf,
|
headers=csrf,
|
||||||
)
|
)
|
||||||
report(f"POST /orders/{order_id}/confirm-close", code, body)
|
report(f"POST /orders/{order_id}/confirm-close", code, body)
|
||||||
check_order_status(s_consumer, order_id, "pending_review", "after confirm-close")
|
check_order_status(
|
||||||
|
s_consumer, order_id, "pending_review", "after confirm-close"
|
||||||
|
)
|
||||||
|
|
||||||
code, body, _ = s_consumer.post(
|
code, body, _ = s_consumer.post(
|
||||||
f"{GATEWAY}/api/v1/orders",
|
f"{GATEWAY}/api/v1/orders",
|
||||||
@@ -1438,8 +1495,12 @@ def phase8_order(s_consumer: Session, s_actor: Session, player_id, service_id, s
|
|||||||
json_body={"rating": 5, "content": "too early"},
|
json_body={"rating": 5, "content": "too early"},
|
||||||
headers=csrf,
|
headers=csrf,
|
||||||
)
|
)
|
||||||
report_rejected(f"POST /orders/{order2_id}/review (before completion)", code, body)
|
report_rejected(
|
||||||
check_order_status(s_consumer, order2_id, "pending_payment", "after early review")
|
f"POST /orders/{order2_id}/review (before completion)", code, body
|
||||||
|
)
|
||||||
|
check_order_status(
|
||||||
|
s_consumer, order2_id, "pending_payment", "after early review"
|
||||||
|
)
|
||||||
|
|
||||||
if order_id:
|
if order_id:
|
||||||
code, body, _ = s_consumer.post(
|
code, body, _ = s_consumer.post(
|
||||||
@@ -1465,7 +1526,9 @@ def phase8_order(s_consumer: Session, s_actor: Session, player_id, service_id, s
|
|||||||
headers=csrf,
|
headers=csrf,
|
||||||
)
|
)
|
||||||
report(f"POST /orders/{order2_id}/pay (before cancel)", code, body)
|
report(f"POST /orders/{order2_id}/pay (before cancel)", code, body)
|
||||||
check_order_status(s_consumer, order2_id, "pending_accept", "second order after pay")
|
check_order_status(
|
||||||
|
s_consumer, order2_id, "pending_accept", "second order after pay"
|
||||||
|
)
|
||||||
|
|
||||||
code, body, _ = s_consumer.post(
|
code, body, _ = s_consumer.post(
|
||||||
f"{GATEWAY}/api/v1/orders/{order2_id}/cancel",
|
f"{GATEWAY}/api/v1/orders/{order2_id}/cancel",
|
||||||
@@ -1473,7 +1536,9 @@ def phase8_order(s_consumer: Session, s_actor: Session, player_id, service_id, s
|
|||||||
headers=csrf,
|
headers=csrf,
|
||||||
)
|
)
|
||||||
report(f"POST /orders/{order2_id}/cancel", code, body)
|
report(f"POST /orders/{order2_id}/cancel", code, body)
|
||||||
check_order_status(s_consumer, order2_id, "cancelled", "second order after cancel")
|
check_order_status(
|
||||||
|
s_consumer, order2_id, "cancelled", "second order after cancel"
|
||||||
|
)
|
||||||
|
|
||||||
code, body, _ = s_consumer.post(
|
code, body, _ = s_consumer.post(
|
||||||
f"{GATEWAY}/api/v1/orders/{order2_id}/pay",
|
f"{GATEWAY}/api/v1/orders/{order2_id}/pay",
|
||||||
@@ -1547,8 +1612,14 @@ def phase8b_review(
|
|||||||
)
|
)
|
||||||
report(f"POST /orders/{order_id}/review (counterparty)", code, body)
|
report(f"POST /orders/{order_id}/review (counterparty)", code, body)
|
||||||
|
|
||||||
order_body = check_order_status(s_consumer, order_id, "completed", "after two reviews")
|
order_body = check_order_status(
|
||||||
report_check("completed order has completedAt", bool(order_body.get("completedAt")), order_body)
|
s_consumer, order_id, "completed", "after two reviews"
|
||||||
|
)
|
||||||
|
report_check(
|
||||||
|
"completed order has completedAt",
|
||||||
|
bool(order_body.get("completedAt")),
|
||||||
|
order_body,
|
||||||
|
)
|
||||||
|
|
||||||
code, body, _ = s_consumer.get(f"{GATEWAY}/api/v1/orders/{order_id}/reviews")
|
code, body, _ = s_consumer.get(f"{GATEWAY}/api/v1/orders/{order_id}/reviews")
|
||||||
report(f"GET /orders/{order_id}/reviews (after two reviews)", code, body)
|
report(f"GET /orders/{order_id}/reviews (after two reviews)", code, body)
|
||||||
@@ -1558,8 +1629,12 @@ def phase8b_review(
|
|||||||
len(reviews) == 2
|
len(reviews) == 2
|
||||||
and all(same_id(item.get("orderId"), order_id) for item in reviews)
|
and all(same_id(item.get("orderId"), order_id) for item in reviews)
|
||||||
and all(item.get("sealed") is False for item in reviews)
|
and all(item.get("sealed") is False for item in reviews)
|
||||||
and bool(find_item(reviews, lambda item: item.get("content") == "great service"))
|
and bool(
|
||||||
and bool(find_item(reviews, lambda item: item.get("content") == "smooth buyer")),
|
find_item(reviews, lambda item: item.get("content") == "great service")
|
||||||
|
)
|
||||||
|
and bool(
|
||||||
|
find_item(reviews, lambda item: item.get("content") == "smooth buyer")
|
||||||
|
),
|
||||||
body,
|
body,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1570,8 +1645,10 @@ def phase8b_review(
|
|||||||
bool(
|
bool(
|
||||||
find_item(
|
find_item(
|
||||||
pick_items(body),
|
pick_items(body),
|
||||||
lambda item: same_id(item.get("orderId"), order_id)
|
lambda item: (
|
||||||
and item.get("sealed") is False,
|
same_id(item.get("orderId"), order_id)
|
||||||
|
and item.get("sealed") is False
|
||||||
|
),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
body,
|
body,
|
||||||
@@ -1587,16 +1664,20 @@ def phase8b_review(
|
|||||||
bool(
|
bool(
|
||||||
find_item(
|
find_item(
|
||||||
pick_items(body),
|
pick_items(body),
|
||||||
lambda item: same_id(item.get("orderId"), order_id)
|
lambda item: (
|
||||||
and same_id(item.get("fromUserId"), consumer_user_id)
|
same_id(item.get("orderId"), order_id)
|
||||||
and item.get("content") == "great service",
|
and same_id(item.get("fromUserId"), consumer_user_id)
|
||||||
|
and item.get("content") == "great service"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
body,
|
body,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def phase8c_dispute(s_consumer: Session, s_actor: Session, player_id, service_id, shop_id):
|
def phase8c_dispute(
|
||||||
|
s_consumer: Session, s_actor: Session, player_id, service_id, shop_id
|
||||||
|
):
|
||||||
print("\n=== Phase 8c: Disputes ===")
|
print("\n=== Phase 8c: Disputes ===")
|
||||||
if not player_id or not service_id:
|
if not player_id or not service_id:
|
||||||
skip("Dispute flow", "Missing player or service id")
|
skip("Dispute flow", "Missing player or service id")
|
||||||
@@ -1643,7 +1724,9 @@ def phase8c_dispute(s_consumer: Session, s_actor: Session, player_id, service_id
|
|||||||
headers=csrf,
|
headers=csrf,
|
||||||
)
|
)
|
||||||
report(f"POST /orders/{order_id}/pay (dispute flow)", code, body)
|
report(f"POST /orders/{order_id}/pay (dispute flow)", code, body)
|
||||||
check_order_status(s_consumer, order_id, "pending_accept", "dispute order after pay")
|
check_order_status(
|
||||||
|
s_consumer, order_id, "pending_accept", "dispute order after pay"
|
||||||
|
)
|
||||||
|
|
||||||
code, body, _ = s_actor.post(
|
code, body, _ = s_actor.post(
|
||||||
f"{GATEWAY}/api/v1/orders/{order_id}/accept",
|
f"{GATEWAY}/api/v1/orders/{order_id}/accept",
|
||||||
@@ -1651,7 +1734,9 @@ def phase8c_dispute(s_consumer: Session, s_actor: Session, player_id, service_id
|
|||||||
headers=s_actor.csrf_headers(),
|
headers=s_actor.csrf_headers(),
|
||||||
)
|
)
|
||||||
report(f"POST /orders/{order_id}/accept (dispute flow)", code, body)
|
report(f"POST /orders/{order_id}/accept (dispute flow)", code, body)
|
||||||
check_order_status(s_consumer, order_id, "in_progress", "dispute order after accept")
|
check_order_status(
|
||||||
|
s_consumer, order_id, "in_progress", "dispute order after accept"
|
||||||
|
)
|
||||||
|
|
||||||
code, body, _ = s_consumer.post(
|
code, body, _ = s_consumer.post(
|
||||||
f"{GATEWAY}/api/v1/orders/{order_id}/dispute",
|
f"{GATEWAY}/api/v1/orders/{order_id}/dispute",
|
||||||
@@ -1694,8 +1779,9 @@ def phase8c_dispute(s_consumer: Session, s_actor: Session, player_id, service_id
|
|||||||
bool(
|
bool(
|
||||||
find_item(
|
find_item(
|
||||||
pick_items(body),
|
pick_items(body),
|
||||||
lambda item: same_id(item.get("id"), dispute_id)
|
lambda item: (
|
||||||
and item.get("status") == "open",
|
same_id(item.get("id"), dispute_id) and item.get("status") == "open"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
body,
|
body,
|
||||||
@@ -1746,7 +1832,9 @@ def phase8d_notifications(s: Session):
|
|||||||
report("GET /notifications", code, body)
|
report("GET /notifications", code, body)
|
||||||
report_check(
|
report_check(
|
||||||
"GET /notifications returns list shape",
|
"GET /notifications returns list shape",
|
||||||
code == 200 and isinstance(pick_items(body), list) and isinstance(body.get("meta"), dict),
|
code == 200
|
||||||
|
and isinstance(pick_items(body), list)
|
||||||
|
and isinstance(body.get("meta"), dict),
|
||||||
body,
|
body,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1812,7 +1900,9 @@ def phase8e_search_and_favorites(s: Session, user_id, player_id, shop_id):
|
|||||||
report("GET /favorites", code, body)
|
report("GET /favorites", code, body)
|
||||||
report_check(
|
report_check(
|
||||||
"GET /favorites returns list shape",
|
"GET /favorites returns list shape",
|
||||||
code == 200 and isinstance(pick_items(body), list) and isinstance(body.get("meta"), dict),
|
code == 200
|
||||||
|
and isinstance(pick_items(body), list)
|
||||||
|
and isinstance(body.get("meta"), dict),
|
||||||
body,
|
body,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1833,8 +1923,10 @@ def phase8e_search_and_favorites(s: Session, user_id, player_id, shop_id):
|
|||||||
not bool(
|
not bool(
|
||||||
find_item(
|
find_item(
|
||||||
pick_items(body),
|
pick_items(body),
|
||||||
lambda item: item.get("targetType") == "player"
|
lambda item: (
|
||||||
and same_id(item.get("targetId"), "not-a-snowflake"),
|
item.get("targetType") == "player"
|
||||||
|
and same_id(item.get("targetId"), "not-a-snowflake")
|
||||||
|
),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
body,
|
body,
|
||||||
@@ -1871,9 +1963,11 @@ def phase8e_search_and_favorites(s: Session, user_id, player_id, shop_id):
|
|||||||
bool(
|
bool(
|
||||||
find_item(
|
find_item(
|
||||||
favorite_items,
|
favorite_items,
|
||||||
lambda item: item.get("targetType") == "player"
|
lambda item: (
|
||||||
and same_id(item.get("targetId"), player_id)
|
item.get("targetType") == "player"
|
||||||
and same_id(item.get("userId"), user_id),
|
and same_id(item.get("targetId"), player_id)
|
||||||
|
and same_id(item.get("userId"), user_id)
|
||||||
|
),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
body,
|
body,
|
||||||
@@ -1884,18 +1978,19 @@ def phase8e_search_and_favorites(s: Session, user_id, player_id, shop_id):
|
|||||||
bool(
|
bool(
|
||||||
find_item(
|
find_item(
|
||||||
favorite_items,
|
favorite_items,
|
||||||
lambda item: item.get("targetType") == "shop"
|
lambda item: (
|
||||||
and same_id(item.get("targetId"), shop_id)
|
item.get("targetType") == "shop"
|
||||||
and same_id(item.get("userId"), user_id),
|
and same_id(item.get("targetId"), shop_id)
|
||||||
|
and same_id(item.get("userId"), user_id)
|
||||||
|
),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
body,
|
body,
|
||||||
)
|
)
|
||||||
favorite_id = 0
|
favorite_id = 0
|
||||||
for item in favorite_items:
|
for item in favorite_items:
|
||||||
if (
|
if item.get("targetType") == "player" and str(item.get("targetId")) == str(
|
||||||
item.get("targetType") == "player"
|
player_id
|
||||||
and str(item.get("targetId")) == str(player_id)
|
|
||||||
):
|
):
|
||||||
favorite_id = as_int(item.get("id"))
|
favorite_id = as_int(item.get("id"))
|
||||||
break
|
break
|
||||||
@@ -1914,7 +2009,9 @@ def phase8e_search_and_favorites(s: Session, user_id, player_id, shop_id):
|
|||||||
)
|
)
|
||||||
report(f"GET /users/{user_id}/favorites/check (after delete)", code, body)
|
report(f"GET /users/{user_id}/favorites/check (after delete)", code, body)
|
||||||
if code == 200:
|
if code == 200:
|
||||||
report_check("favorite check after delete", body.get("favorited") is False, body)
|
report_check(
|
||||||
|
"favorite check after delete", body.get("favorited") is False, body
|
||||||
|
)
|
||||||
code, body, _ = s.get(f"{GATEWAY}/api/v1/favorites")
|
code, body, _ = s.get(f"{GATEWAY}/api/v1/favorites")
|
||||||
report("GET /favorites (after delete)", code, body)
|
report("GET /favorites (after delete)", code, body)
|
||||||
report_check(
|
report_check(
|
||||||
@@ -1922,8 +2019,10 @@ def phase8e_search_and_favorites(s: Session, user_id, player_id, shop_id):
|
|||||||
not bool(
|
not bool(
|
||||||
find_item(
|
find_item(
|
||||||
pick_items(body),
|
pick_items(body),
|
||||||
lambda item: item.get("targetType") == "player"
|
lambda item: (
|
||||||
and same_id(item.get("targetId"), player_id),
|
item.get("targetType") == "player"
|
||||||
|
and same_id(item.get("targetId"), player_id)
|
||||||
|
),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
body,
|
body,
|
||||||
@@ -2011,17 +2110,21 @@ def phase9_wallet(s: Session):
|
|||||||
bool(
|
bool(
|
||||||
find_item(
|
find_item(
|
||||||
transactions,
|
transactions,
|
||||||
lambda item: item.get("type") == "topup"
|
lambda item: (
|
||||||
and as_decimal(item.get("amount")) == Decimal("100")
|
item.get("type") == "topup"
|
||||||
and item.get("description") == "topup via alipay",
|
and as_decimal(item.get("amount")) == Decimal("100")
|
||||||
|
and item.get("description") == "topup via alipay"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
and bool(
|
and bool(
|
||||||
find_item(
|
find_item(
|
||||||
transactions,
|
transactions,
|
||||||
lambda item: item.get("type") == "withdrawal"
|
lambda item: (
|
||||||
and as_decimal(item.get("amount")) == Decimal("10")
|
item.get("type") == "withdrawal"
|
||||||
and item.get("description") == "withdraw via alipay",
|
and as_decimal(item.get("amount")) == Decimal("10")
|
||||||
|
and item.get("description") == "withdraw via alipay"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
body,
|
body,
|
||||||
@@ -2060,7 +2163,11 @@ def phase10_community(s: Session, user_id):
|
|||||||
|
|
||||||
code, body, _ = s.get(f"{GATEWAY}/api/v1/posts")
|
code, body, _ = s.get(f"{GATEWAY}/api/v1/posts")
|
||||||
report("GET /posts", code, body)
|
report("GET /posts", code, body)
|
||||||
report_check("created post appears in list", bool(find_item_by_id(pick_items(body), post_id)), body)
|
report_check(
|
||||||
|
"created post appears in list",
|
||||||
|
bool(find_item_by_id(pick_items(body), post_id)),
|
||||||
|
body,
|
||||||
|
)
|
||||||
|
|
||||||
if post_id:
|
if post_id:
|
||||||
code, body, _ = s.get(f"{GATEWAY}/api/v1/posts/{post_id}")
|
code, body, _ = s.get(f"{GATEWAY}/api/v1/posts/{post_id}")
|
||||||
@@ -2181,7 +2288,11 @@ def phase10_community(s: Session, user_id):
|
|||||||
|
|
||||||
code, body, _ = s.get(f"{GATEWAY}/api/v1/users/{user_id}/posts")
|
code, body, _ = s.get(f"{GATEWAY}/api/v1/users/{user_id}/posts")
|
||||||
report(f"GET /users/{user_id}/posts", code, body)
|
report(f"GET /users/{user_id}/posts", code, body)
|
||||||
report_check("user posts contain created post", bool(find_item_by_id(pick_items(body), post_id)), body)
|
report_check(
|
||||||
|
"user posts contain created post",
|
||||||
|
bool(find_item_by_id(pick_items(body), post_id)),
|
||||||
|
body,
|
||||||
|
)
|
||||||
|
|
||||||
return post_id
|
return post_id
|
||||||
|
|
||||||
@@ -2241,7 +2352,9 @@ def phase12_email(s: Session):
|
|||||||
report("POST /email/verification-code/send (gateway)", code, body)
|
report("POST /email/verification-code/send (gateway)", code, body)
|
||||||
report_check(
|
report_check(
|
||||||
"email verification send returns request id",
|
"email verification send returns request id",
|
||||||
code == 200 and bool(body.get("requestId")) and as_int(body.get("expireInSec")) > 0,
|
code == 200
|
||||||
|
and bool(body.get("requestId"))
|
||||||
|
and as_int(body.get("expireInSec")) > 0,
|
||||||
body,
|
body,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -2253,7 +2366,9 @@ def phase12_email(s: Session):
|
|||||||
report("POST /auth/forgot-password/send (gateway)", code, body)
|
report("POST /auth/forgot-password/send (gateway)", code, body)
|
||||||
report_check(
|
report_check(
|
||||||
"forgot password send returns request id",
|
"forgot password send returns request id",
|
||||||
code == 200 and bool(body.get("requestId")) and as_int(body.get("expireInSec")) > 0,
|
code == 200
|
||||||
|
and bool(body.get("requestId"))
|
||||||
|
and as_int(body.get("expireInSec")) > 0,
|
||||||
body,
|
body,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -141,6 +141,98 @@ data:
|
|||||||
route:
|
route:
|
||||||
cluster: player_api_cluster
|
cluster: player_api_cluster
|
||||||
timeout: 30s
|
timeout: 30s
|
||||||
|
- match:
|
||||||
|
prefix: /api/v1/services
|
||||||
|
headers:
|
||||||
|
- name: ":method"
|
||||||
|
exact_match: "GET"
|
||||||
|
route:
|
||||||
|
cluster: player_api_cluster
|
||||||
|
timeout: 30s
|
||||||
|
typed_per_filter_config:
|
||||||
|
envoy.filters.http.ext_authz:
|
||||||
|
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
|
||||||
|
disabled: true
|
||||||
|
- match:
|
||||||
|
path: /api/v1/shops
|
||||||
|
headers:
|
||||||
|
- name: ":method"
|
||||||
|
exact_match: "GET"
|
||||||
|
route:
|
||||||
|
cluster: shop_api_cluster
|
||||||
|
timeout: 30s
|
||||||
|
typed_per_filter_config:
|
||||||
|
envoy.filters.http.ext_authz:
|
||||||
|
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
|
||||||
|
disabled: true
|
||||||
|
- match:
|
||||||
|
safe_regex:
|
||||||
|
google_re2: {}
|
||||||
|
regex: "^/api/v1/shops/[^/]+$"
|
||||||
|
headers:
|
||||||
|
- name: ":method"
|
||||||
|
exact_match: "GET"
|
||||||
|
route:
|
||||||
|
cluster: shop_api_cluster
|
||||||
|
timeout: 30s
|
||||||
|
typed_per_filter_config:
|
||||||
|
envoy.filters.http.ext_authz:
|
||||||
|
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
|
||||||
|
disabled: true
|
||||||
|
- match:
|
||||||
|
safe_regex:
|
||||||
|
google_re2: {}
|
||||||
|
regex: "^/api/v1/shops/[^/]+/players$"
|
||||||
|
headers:
|
||||||
|
- name: ":method"
|
||||||
|
exact_match: "GET"
|
||||||
|
route:
|
||||||
|
cluster: shop_api_cluster
|
||||||
|
timeout: 30s
|
||||||
|
typed_per_filter_config:
|
||||||
|
envoy.filters.http.ext_authz:
|
||||||
|
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
|
||||||
|
disabled: true
|
||||||
|
- match:
|
||||||
|
safe_regex:
|
||||||
|
google_re2: {}
|
||||||
|
regex: "^/api/v1/users/[^/]+/posts$"
|
||||||
|
headers:
|
||||||
|
- name: ":method"
|
||||||
|
exact_match: "GET"
|
||||||
|
route:
|
||||||
|
cluster: community_api_cluster
|
||||||
|
timeout: 30s
|
||||||
|
typed_per_filter_config:
|
||||||
|
envoy.filters.http.ext_authz:
|
||||||
|
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
|
||||||
|
disabled: true
|
||||||
|
- match:
|
||||||
|
safe_regex:
|
||||||
|
google_re2: {}
|
||||||
|
regex: "^/api/v1/users/[^/]+/shop$"
|
||||||
|
headers:
|
||||||
|
- name: ":method"
|
||||||
|
exact_match: "GET"
|
||||||
|
route:
|
||||||
|
cluster: shop_api_cluster
|
||||||
|
timeout: 30s
|
||||||
|
typed_per_filter_config:
|
||||||
|
envoy.filters.http.ext_authz:
|
||||||
|
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
|
||||||
|
disabled: true
|
||||||
|
- match:
|
||||||
|
prefix: /api/v1/posts
|
||||||
|
headers:
|
||||||
|
- name: ":method"
|
||||||
|
exact_match: "GET"
|
||||||
|
route:
|
||||||
|
cluster: community_api_cluster
|
||||||
|
timeout: 30s
|
||||||
|
typed_per_filter_config:
|
||||||
|
envoy.filters.http.ext_authz:
|
||||||
|
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute
|
||||||
|
disabled: true
|
||||||
# - match:
|
# - match:
|
||||||
# prefix: /api/v1/shop
|
# prefix: /api/v1/shop
|
||||||
# route:
|
# route:
|
||||||
|
|||||||
Reference in New Issue
Block a user