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) case platform.Managed: assertRouteMethods(t, routes, path, http.MethodGet, http.MethodPost) assertRouteMethods(t, routes, path+"/:identity", http.MethodGet, http.MethodPut) assertNoRouteMethods(t, routes, path, http.MethodDelete) assertNoRouteMethods(t, routes, path+"/:identity", http.MethodPatch, 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_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_basic", "/gas_account", "/delivery_basic", "/delivery_account", "/staff_account", "/staff_credential", "/user_account", "/user_address", "/user_service_relation", "/platfrom_account", "/platform_role", "/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_role/:identity/menu", http.MethodGet, http.MethodPut) assertRouteMethods(t, routes, "/heqi/platform/v1/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_category", "/ec_product", "/ec_product_attribute", "/ec_product_image", "/ec_cart", "/ec_order", "/ec_order_item", "/ec_review", } { 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{"/gasorder_item", "/gasorder_assign", "/gasorder_status", "/gasorder_track", "/gasorder_track_point", "/gasorder_confirm", "/gasorder_payment", "/gasorder_contract_revision"} { path := "/heqi/platform/v1" + resource 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) } assertRouteMethods(t, routes, "/heqi/platform/v1/gasorder_contract", http.MethodGet, http.MethodPost) assertRouteMethods(t, routes, "/heqi/platform/v1/gasorder_contract/:identity", http.MethodGet, http.MethodPut) assertRouteMethods(t, routes, "/heqi/platform/v1/gasorder_basic", http.MethodGet, http.MethodPost) assertRouteMethods(t, routes, "/heqi/platform/v1/gasorder_basic/:identity", http.MethodGet) for _, action := range []string{"assign", "filling", "ready", "exception", "recover", "cancel"} { assertRouteMethods(t, routes, "/heqi/platform/v1/gasorder_basic/:identity/"+action, http.MethodPost) } for _, old := range []string{"/delivery/delivery_task", "/delivery/delivery_track", "/delivery/delivery_track_point"} { assertNoRouteMethods(t, routes, "/heqi/platform/v1"+old, http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete) } 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{ "/fin_payment", "/fin_settlement", "/fin_reconciliation", "/cms_content", "/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) } } }