Files
platforms/backend/api/internal/routers/platform_test.go
2026-07-28 09:25:49 +08:00

223 lines
9.6 KiB
Go

package routers
import (
"net/http"
"testing"
"git.apinb.com/heqiapp/platforms/backend/api/internal/logic/platform"
"github.com/gin-gonic/gin"
)
func TestEveryContractHasRegisteredRoute(t *testing.T) {
engine := gin.New()
RegisterPlatform("heqi", engine)
routes := make(map[string]map[string]bool)
for _, route := range engine.Routes() {
if routes[route.Path] == nil {
routes[route.Path] = make(map[string]bool)
}
routes[route.Path][route.Method] = true
}
for _, contract := range platform.ExpectedResources() {
path := "/heqi/platform/v1" + contract.Path
switch contract.Mode {
case platform.ReadOnly:
assertRouteMethods(t, routes, path, http.MethodGet)
assertRouteMethods(t, routes, path+"/:identity", http.MethodGet)
assertNoRouteMethods(t, routes, path, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete)
assertNoRouteMethods(t, routes, path+"/:identity", http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete)
case platform.AppendOnly:
assertRouteMethods(t, routes, path, http.MethodGet, http.MethodPost)
assertNoRouteMethods(t, routes, path, http.MethodPut, http.MethodPatch, http.MethodDelete)
case platform.Editable:
assertRouteMethods(t, routes, path, http.MethodGet, http.MethodPost)
assertRouteMethods(t, routes, path+"/:identity", http.MethodGet, http.MethodPut)
assertRouteMethods(t, routes, path+"/:identity/status", http.MethodPatch)
assertNoRouteMethods(t, routes, path, http.MethodDelete)
assertNoRouteMethods(t, routes, path+"/:identity", http.MethodDelete)
default:
assertRouteMethods(t, routes, path, http.MethodGet, http.MethodPost)
assertRouteMethods(t, routes, path+"/:identity", http.MethodGet, http.MethodPut, http.MethodDelete)
assertRouteMethods(t, routes, path+"/:identity/status", http.MethodPatch)
}
}
}
func TestPlatformGasRouteUsesGasBasic(t *testing.T) {
engine := gin.New()
RegisterPlatform("heqi", engine)
for _, route := range engine.Routes() {
if route.Path == "/heqi/platform/v1/gas/gas_station" {
t.Fatal("gas station route must use gas_basic as its resource name")
}
if route.Method == "GET" && route.Path == "/heqi/platform/v1/gas/gas_basic" {
return
}
}
t.Fatal("gas_basic list route is not registered")
}
func TestPlatformOrganizationAndAccountRoutesExposeResourceCRUD(t *testing.T) {
engine := gin.New()
RegisterPlatform("heqi", engine)
routes := make(map[string]map[string]bool)
for _, route := range engine.Routes() {
if routes[route.Path] == nil {
routes[route.Path] = make(map[string]bool)
}
routes[route.Path][route.Method] = true
}
for _, resource := range []string{
"/gas/gas_basic",
"/gas/gas_account",
"/delivery/delivery_basic",
"/delivery/delivery_account",
"/staff/account",
"/staff/credential",
"/user/account",
"/user/address",
"/user/service_relation",
"/platform/platfrom_account",
"/platform/platform_role",
"/platform/platform_menu",
} {
assertRouteMethods(t, routes, "/heqi/platform/v1"+resource, http.MethodGet, http.MethodPost)
assertRouteMethods(t, routes, "/heqi/platform/v1"+resource+"/:identity", http.MethodGet, http.MethodPut, http.MethodDelete)
assertRouteMethods(t, routes, "/heqi/platform/v1"+resource+"/:identity/status", http.MethodPatch)
}
assertRouteMethods(t, routes, "/heqi/platform/v1/platform/platform_role/:identity/menu", http.MethodGet, http.MethodPut)
assertRouteMethods(t, routes, "/heqi/platform/v1/platform/platform_role/:identity/menus", http.MethodPut)
}
func TestPlatformProductCommerceAndDeliveryRoutesFollowTheirContracts(t *testing.T) {
engine := gin.New()
RegisterPlatform("heqi", engine)
routes := make(map[string]map[string]bool)
for _, route := range engine.Routes() {
if routes[route.Path] == nil {
routes[route.Path] = make(map[string]bool)
}
routes[route.Path][route.Method] = true
}
for _, resource := range []string{
"/ec/ec_category", "/ec/ec_product", "/ec/ec_product_attribute", "/ec/ec_product_image", "/ec/ec_cart", "/ec/ec_order", "/ec/ec_order_item", "/ec/ec_review",
"/delivery/delivery_task", "/delivery/delivery_track",
} {
assertRouteMethods(t, routes, "/heqi/platform/v1"+resource, http.MethodGet, http.MethodPost)
assertRouteMethods(t, routes, "/heqi/platform/v1"+resource+"/:identity", http.MethodGet, http.MethodPut, http.MethodDelete)
assertRouteMethods(t, routes, "/heqi/platform/v1"+resource+"/:identity/status", http.MethodPatch)
}
trackPoint := "/heqi/platform/v1/delivery/delivery_track_point"
assertRouteMethods(t, routes, trackPoint, http.MethodGet)
assertRouteMethods(t, routes, trackPoint+"/:identity", http.MethodGet)
assertNoRouteMethods(t, routes, trackPoint, http.MethodPost)
assertNoRouteMethods(t, routes, trackPoint+"/:identity", http.MethodPut, http.MethodDelete)
assertNoRouteMethods(t, routes, trackPoint+"/:identity/status", http.MethodPatch)
for _, resource := range []string{"/product_type", "/product_warehouse", "/product_info", "/product_repair"} {
path := "/heqi/platform/v1" + resource
assertRouteMethods(t, routes, path, http.MethodGet, http.MethodPost)
assertRouteMethods(t, routes, path+"/:identity", http.MethodGet, http.MethodPut)
assertRouteMethods(t, routes, path+"/:identity/status", http.MethodPatch)
assertNoRouteMethods(t, routes, path+"/:identity", http.MethodDelete)
}
owner := "/heqi/platform/v1/product_owner"
assertRouteMethods(t, routes, owner, http.MethodGet, http.MethodPost)
assertRouteMethods(t, routes, owner+"/:identity", http.MethodGet)
assertNoRouteMethods(t, routes, owner+"/:identity", http.MethodPut, http.MethodPatch, http.MethodDelete)
for _, resource := range []string{
"/safety/safe_rule", "/safety/safe_event", "/safety/safe_inspection",
"/safety/safe_event/:identity/disposals",
} {
path := "/heqi/platform/v1" + resource
assertNoRouteMethods(t, routes, path, http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete)
assertNoRouteMethods(t, routes, path+"/:identity", http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete)
assertNoRouteMethods(t, routes, path+"/:identity/status", http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete)
}
}
func TestPlatformFinanceContentRoutesFollowTheirContracts(t *testing.T) {
engine := gin.New()
RegisterPlatform("heqi", engine)
routes := make(map[string]map[string]bool)
for _, route := range engine.Routes() {
if routes[route.Path] == nil {
routes[route.Path] = make(map[string]bool)
}
routes[route.Path][route.Method] = true
}
for _, resource := range []string{
"/finance/fin_payment", "/finance/fin_settlement", "/finance/fin_reconciliation",
"/content/cms_content", "/customer_service/cs_ticket",
} {
assertRouteMethods(t, routes, "/heqi/platform/v1"+resource, http.MethodGet, http.MethodPost)
assertRouteMethods(t, routes, "/heqi/platform/v1"+resource+"/:identity", http.MethodGet, http.MethodPut, http.MethodDelete)
assertRouteMethods(t, routes, "/heqi/platform/v1"+resource+"/:identity/status", http.MethodPatch)
}
for _, resource := range []string{
"/wallet_basic", "/wallet_bank", "/wallet_payment", "/wallet_record", "/wallet_refund", "/wallet_apply_cash",
} {
path := "/heqi/platform/v1" + resource
assertRouteMethods(t, routes, path, http.MethodGet)
assertRouteMethods(t, routes, path+"/:identity", http.MethodGet)
for _, method := range []string{http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete} {
if routes[path][method] || routes[path+"/:identity"][method] {
t.Errorf("read-only resource %s unexpectedly permits %s", resource, method)
}
}
}
assertRouteMethods(t, routes, "/heqi/platform/v1/wallet_basic/:identity/status", http.MethodPatch)
assertRouteMethods(t, routes, "/heqi/platform/v1/wallet_basic/:identity/recharge", http.MethodPost)
assertRouteMethods(t, routes, "/heqi/platform/v1/wallet_basic/owner/:owner_type/:owner_identity", http.MethodGet)
assertRouteMethods(t, routes, "/heqi/platform/v1/wallet_apply_cash/:identity/approve", http.MethodPost)
assertRouteMethods(t, routes, "/heqi/platform/v1/wallet_apply_cash/:identity/reject", http.MethodPost)
for _, oldPath := range []string{
"/heqi/platform/v1/wallet/wallet",
"/heqi/platform/v1/wallet/wallet_ledger",
"/heqi/platform/v1/wallet/wallet_recharge",
"/heqi/platform/v1/wallet/wallet_withdrawal",
} {
assertNoRouteMethods(t, routes, oldPath, http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete)
}
for _, resource := range []string{
"/content/cnt_content", "/notification/ntf_template",
"/report/report", "/report/report_item", "/report/report_metric_snapshot",
"/audit/audit_operation_log", "/audit/audit_export_log", "/audit/audit_approval",
} {
path := "/heqi/platform/v1" + resource
assertNoRouteMethods(t, routes, path, http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete)
assertNoRouteMethods(t, routes, path+"/:identity", http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete)
}
assertNoRouteMethods(t, routes, "/heqi/platform/v1/audit/audit_approval/:identity/approve", http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete)
}
func assertRouteMethods(t *testing.T, routes map[string]map[string]bool, path string, methods ...string) {
t.Helper()
for _, method := range methods {
if !routes[path][method] {
t.Errorf("route %s %s is not registered", method, path)
}
}
}
func assertNoRouteMethods(t *testing.T, routes map[string]map[string]bool, path string, methods ...string) {
t.Helper()
for _, method := range methods {
if routes[path][method] {
t.Errorf("route %s %s must not be registered", method, path)
}
}
}