refactor(platform): remove safety management module

This commit is contained in:
2026-07-27 15:49:51 +08:00
parent 95fb27f596
commit 8739cfd4d6
25 changed files with 27 additions and 391 deletions

View File

@@ -38,7 +38,6 @@ func InitPlatformAccess(database *gorm.DB) error {
{Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1}, MenuCode: "staff", Name: "服务人员", Icon: "icon-user", Path: "/staff/list", SortNo: 40},
{Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1}, MenuCode: "user", Name: "业主客户", Icon: "icon-user-group", Path: "/user/list", SortNo: 50},
{Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1}, MenuCode: "device", Name: "设备管理", Icon: "icon-storage", Path: "/device", SortNo: 60},
{Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1}, MenuCode: "safety", Name: "安全治理", Icon: "icon-safe", Path: "/safety", SortNo: 70},
{Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1}, MenuCode: "ec", Name: "电商管理", Icon: "icon-shopping", Path: "/ec/product", SortNo: 80},
{Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1}, MenuCode: "finance", Name: "财务管理", Icon: "icon-safe", Path: "/finance/payment", SortNo: 90},
{Entity: models.Entity{Identity: models.NewIdentity(), Status: "enabled", Version: 1}, MenuCode: "wallet", Name: "钱包中心", Icon: "icon-wallet", Path: "/wallet/list", SortNo: 100},

View File

@@ -26,7 +26,7 @@ func TestInitPlatformAccessSeedsEveryProtectedFrontendDomain(t *testing.T) {
AddRow(uint64(1), "root-role", "enabled", 1, "root", "Root", "global", true))
domains := []string{
"dashboard", "gas", "delivery", "staff", "user", "device", "safety",
"dashboard", "gas", "delivery", "staff", "user", "device",
"ec", "finance", "wallet", "content", "customer_service", "platform",
}
for index, domain := range domains {

View File

@@ -15,7 +15,6 @@ func TestDashboardOverviewReturnsZeroValuesForAnEmptyDatabase(t *testing.T) {
`SELECT count\(\*\) FROM "delivery_basic" WHERE status = \$1`,
`SELECT count\(\*\) FROM "staff_account" WHERE work_status = \$1`,
`SELECT count\(\*\) FROM "user_account" WHERE status = \$1`,
`SELECT count\(\*\) FROM "safe_event" WHERE status = \$1`,
} {
mock.ExpectQuery(regexp.MustCompile(query).String()).WithArgs(sqlmock.AnyArg()).WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(0))
}

View File

@@ -75,7 +75,6 @@ func ExpectedResources() []ResourceContract {
resourceContract("staff", "staff_account", Writable, "list"), resourceContract("staff", "staff_credential", Writable, "list"),
resourceContract("user", "user_account", Writable, "list"), resourceContract("user", "user_address", Writable, "list"), resourceContract("user", "user_service_relation", Writable, "list"),
resourceContract("device", "dev_smart_cylinder_valve", Writable, "list"), resourceContract("device", "dev_device_binding", Writable, "list"), resourceContract("device", "dev_telemetry", ReadOnly, "list"),
resourceContract("safety", "safe_rule", Writable, "list"), resourceContract("safety", "safe_event", Writable, "list"), resourceContract("safety", "safe_inspection", Writable, "list"), resourceContract("safety", "safe_event_disposal", AppendOnly, "list"),
resourceContract("ec", "ec_category", Writable, "list"), resourceContract("ec", "ec_product", Writable, "list"), resourceContract("ec", "ec_product_attribute", Writable, "list"), resourceContract("ec", "ec_product_image", Writable, "list"), resourceContract("ec", "ec_cart", Writable, "list"), resourceContract("ec", "ec_order", Writable, "list"), resourceContract("ec", "ec_order_item", Writable, "list"), resourceContract("ec", "ec_review", Writable, "list"),
resourceContract("delivery", "delivery_task", Writable, "list"), resourceContract("delivery", "delivery_track", Writable, "list"), resourceContract("delivery", "delivery_track_point", ReadOnly, "list"),
resourceContract("finance", "fin_payment", Writable, "list"), resourceContract("finance", "fin_settlement", Writable, "list"), resourceContract("finance", "fin_reconciliation", Writable, "list"),
@@ -101,8 +100,6 @@ func resourcePath(domain, name string) string {
return "/user/address"
case "user_service_relation":
return "/user/service_relation"
case "safe_event_disposal":
return "/safety/safe_event/:identity/disposals"
default:
return "/" + domain + "/" + name
}

View File

@@ -42,16 +42,13 @@ func TestContentUsesCMSResourceAndRemovedDomainsAreAbsent(t *testing.T) {
}
}
func TestSafeResourceContracts(t *testing.T) {
legacySafetyPrefix := "sa" + "f_"
assertContract(t, ExpectedResources(), "safety", "safe_rule", Writable, "list")
assertContract(t, ExpectedResources(), "safety", "safe_event", Writable, "list")
assertContract(t, ExpectedResources(), "safety", "safe_inspection", Writable, "list")
assertContract(t, ExpectedResources(), "safety", "safe_event_disposal", AppendOnly, "list")
func TestSafetyResourcesAreAbsent(t *testing.T) {
removed := map[string]struct{}{
"safe_rule": {}, "safe_event": {}, "safe_inspection": {}, "safe_event_disposal": {},
}
for _, contract := range ExpectedResources() {
if contract.Domain == "safety" && strings.HasPrefix(contract.Name, legacySafetyPrefix) {
t.Fatalf("legacy resource contract %s/%s must not be registered", contract.Domain, contract.Name)
if _, exists := removed[contract.Name]; exists || contract.Domain == "safety" {
t.Fatalf("removed safety resource %s/%s remains registered", contract.Domain, contract.Name)
}
}
}
@@ -258,17 +255,6 @@ func TestPrepareResourceValuesResolvesRequiredIdentityRelationsAndRejectsInvalid
}
func TestPrepareResourceValuesAcceptsArbitraryTextFields(t *testing.T) {
t.Run("safety rule", func(t *testing.T) {
ctx, _ := updateContext(http.MethodPost, "/safety/safe_rule", "", []byte(`{"rule_code":"pressure-limit","threshold":"{invalid}","action":"close-valve","gray_scope":"north region"}`))
values, err := prepareResourceValues(ctx, &models.SafeRule{}, []string{"rule_code", "threshold", "action", "gray_scope"}, nil)
if err != nil {
t.Fatal(err)
}
if values["threshold"] != `{invalid}` || values["gray_scope"] != `north region` {
t.Fatalf("text values were not preserved: %#v", values)
}
})
t.Run("order item", func(t *testing.T) {
_, mock := setupPlatformRoleDatabase(t)
mock.ExpectQuery(regexp.QuoteMeta(`SELECT "id" FROM "ec_order" WHERE identity = $1 ORDER BY "ec_order"."id" LIMIT $2`)).
@@ -292,12 +278,6 @@ func TestPrepareResourceValuesAcceptsArbitraryTextFields(t *testing.T) {
assertMockExpectations(t, mock)
})
t.Run("arbitrary text", func(t *testing.T) {
ctx, _ := updateContext(http.MethodPost, "/safety/safe_rule", "", []byte(`{"rule_code":"pressure-limit","threshold":"{invalid}","action":"close-valve"}`))
if _, err := prepareResourceValues(ctx, &models.SafeRule{}, []string{"rule_code", "threshold", "action"}, nil); err != nil {
t.Fatalf("arbitrary text was rejected: %v", err)
}
})
}
func TestCreateGasAccountResolvesGasBasicIdentityBeforePersisting(t *testing.T) {
@@ -350,7 +330,6 @@ func TestKeywordColumnsUseSafeTextAllowlist(t *testing.T) {
model any
want []string
}{
{"safety rule excludes arbitrary text fields", &models.SafeRule{}, []string{"rule_code", "action"}},
{"gas basic excludes sensitive fields", &models.GasBasic{}, []string{"code", "name"}},
{"user address has no searchable safe text", &models.UserAddress{}, []string{}},
}
@@ -655,26 +634,6 @@ func TestNonRootCannotAssignPlatformAccountRole(t *testing.T) {
}
}
func TestListSafetyEventDisposalsReturnsOnlyTheRequestedEventHistory(t *testing.T) {
_, mock := setupPlatformRoleDatabase(t)
mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(*) FROM "safe_event_disposal" WHERE safe_event_identity = $1`)).
WithArgs("event-a").
WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1))
mock.ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "safe_event_disposal" WHERE safe_event_identity = $1 ORDER BY created_at asc LIMIT $2`)).
WithArgs("event-a", 20).
WillReturnRows(sqlmock.NewRows([]string{"id", "identity", "created_at", "updated_at", "status", "version", "safe_event_identity", "action", "reason", "operator_identity"}).
AddRow(uint64(9), "disposal-a", nil, nil, "enabled", 1, "event-a", "close", "resolved", "operator-a"))
ctx, recorder := updateContext(http.MethodGet, "/safety/safe_event/event-a/disposals", "event-a", nil)
ListSafetyEventDisposals(ctx)
assertResponseCode(t, recorder, 0)
if !strings.Contains(recorder.Body.String(), `"safe_event_identity":"event-a"`) || strings.Contains(recorder.Body.String(), `"id":`) {
t.Fatalf("disposal history did not keep the event identity-only shape: %s", recorder.Body.String())
}
assertMockExpectations(t, mock)
}
func TestListGasAccountProjectsGasBasicIdentityAndNeverReturnsRelationID(t *testing.T) {
_, mock := setupPlatformRoleDatabase(t)
mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(*) FROM "gas_account"`)).
@@ -820,33 +779,6 @@ func TestGetDeliveryTrackPointReturnsCoordinatesWithPreciseLocationScope(t *test
assertMockExpectations(t, mock)
}
func TestDisposeSafetyEventUpdatesEventAndAppendsOperatorActionTransactionally(t *testing.T) {
_, mock := setupPlatformRoleDatabase(t)
now := time.Now().UTC()
mock.ExpectBegin()
mock.ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "safe_event" WHERE identity = $1 ORDER BY "safe_event"."id" LIMIT $2`)).
WithArgs("event-a", 1).
WillReturnRows(sqlmock.NewRows([]string{"id", "identity", "created_at", "updated_at", "status", "version", "event_code", "level", "title", "smart_cylinder_valve_identity", "sla_at"}).
AddRow(uint64(3), "event-a", now, now, "open", 1, "E-1", 2, "alarm", "valve-a", nil))
mock.ExpectExec(regexp.QuoteMeta(`UPDATE "safe_event" SET "status"=$1,"updated_at"=$2 WHERE identity = $3`)).
WithArgs("disposed", sqlmock.AnyArg(), "event-a").
WillReturnResult(sqlmock.NewResult(0, 1))
mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "safe_event_disposal" ("identity","created_at","updated_at","status","version","safe_event_identity","action","reason","operator_identity") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9) RETURNING "id"`)).
WithArgs(sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), "enabled", 1, "event-a", "close", "resolved", "operator-a").
WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(uint64(1)))
mock.ExpectCommit()
ctx, recorder := updateContext(http.MethodPost, "/safety/safe_event/event-a/disposals", "event-a", []byte(`{"action":"close","reason":"resolved"}`))
ctx.Set("Auth", &types.JwtClaims{Identity: "operator-a"})
DisposeSafetyEvent(ctx)
assertResponseCode(t, recorder, 0)
if !strings.Contains(recorder.Body.String(), `"operator_identity":"operator-a"`) {
t.Fatalf("disposal omitted its operator: %s", recorder.Body.String())
}
assertMockExpectations(t, mock)
}
func TestReplacePlatformRoleMenusAllowsAnEmptySetToClearAssignmentsTransactionally(t *testing.T) {
_, mock := setupPlatformRoleDatabase(t)
mock.ExpectBegin()

View File

@@ -15,7 +15,6 @@ import (
"git.apinb.com/heqiapp/platforms/backend/api/internal/impl"
"git.apinb.com/heqiapp/platforms/backend/api/internal/models"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
// ResourceRelation accepts a stable external identity while retaining the
@@ -530,73 +529,6 @@ func stripInternalIDs(value any) any {
return value
}
// DisposeSafetyEvent atomically updates an event and appends its operator-owned
// action record. Disposal records deliberately have no update or delete route.
func ListSafetyEventDisposals(ctx *gin.Context) {
page, size := pageSize(ctx)
var list []models.SafeEventDisposal
query := impl.DBService.Model(&models.SafeEventDisposal{}).Where("safe_event_identity = ?", ctx.Param("identity"))
var total int64
if err := query.Count(&total).Error; err != nil {
infra.Response.Error(ctx, err)
return
}
if err := query.Order("created_at asc").Offset((page - 1) * size).Limit(size).Find(&list).Error; err != nil {
infra.Response.Error(ctx, err)
return
}
infra.Response.Success(ctx, gin.H{"total": total, "list": resourceResponse(list)})
}
func DisposeSafetyEvent(ctx *gin.Context) {
claims, err := middleware.ParseAuth(ctx)
if err != nil {
infra.Response.Error(ctx, err)
return
}
var request struct {
Action string `json:"action" binding:"required,max=64"`
Reason string `json:"reason" binding:"max=2000"`
Status string `json:"status" binding:"max=32"`
}
if err := ctx.ShouldBindJSON(&request); err != nil {
infra.Response.Error(ctx, errcode.ErrInvalidArgument)
return
}
if request.Status == "" {
request.Status = "disposed"
}
var disposal models.SafeEventDisposal
err = impl.DBService.Transaction(func(transaction *gorm.DB) error {
var event models.SafeEvent
if err := transaction.Where("identity = ?", ctx.Param("identity")).First(&event).Error; err != nil {
return err
}
if result := transaction.Model(&models.SafeEvent{}).Where("identity = ?", event.Identity).Update("status", request.Status); result.Error != nil {
return result.Error
} else if result.RowsAffected == 0 {
return gorm.ErrRecordNotFound
}
disposal = models.SafeEventDisposal{
Entity: newEntity("enabled"),
SafeEventIdentity: event.Identity,
Action: request.Action,
Reason: request.Reason,
OperatorIdentity: claims.Identity,
}
return transaction.Create(&disposal).Error
})
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
infra.Response.Error(ctx, errcode.ErrRecordNotFound)
return
}
infra.Response.Error(ctx, err)
return
}
infra.Response.Success(ctx, resourceResponse(disposal))
}
// GetEcOrder returns the order together with its immutable item snapshots.
func GetEcOrder(ctx *gin.Context) {
var order models.EcOrder

View File

@@ -8,7 +8,6 @@ type DashboardOverview struct {
DeliveryBasicCount int64 `json:"delivery_basic_count"` // 启用配送点数量
StaffCount int64 `json:"staff_count"` // 在岗服务人员数量
UserCount int64 `json:"user_count"` // 启用业主客户数量
PendingSafetyCount int64 `json:"pending_safety_count"` // 待处理安全事件数量
}
// GetDashboardOverview 通过独立查询返回首页概览指标。
@@ -26,9 +25,6 @@ func GetDashboardOverview() (DashboardOverview, error) {
if err := impl.DBService.Model(&UserAccount{}).Where("status = ?", "enabled").Count(&overview.UserCount).Error; err != nil {
return DashboardOverview{}, err
}
if err := impl.DBService.Model(&SafeEvent{}).Where("status = ?", "pending").Count(&overview.PendingSafetyCount).Error; err != nil {
return DashboardOverview{}, err
}
return overview, nil
}

View File

@@ -1,19 +0,0 @@
package models
import (
"git.apinb.com/bsm-sdk/core/database"
"time"
)
// SafeEvent 对应 safe_event保存安全事件统一入口。
type SafeEvent struct {
Entity // 公共实体字段
EventCode string `gorm:"column:event_code;type:varchar(64);not null;uniqueIndex" json:"event_code"` // event_code 业务字段
Level int `gorm:"column:level;not null;default:3" json:"level"` // level 业务字段
Title string `gorm:"column:title;type:varchar(256);not null;default:''" json:"title"` // title 业务字段
SmartCylinderValveIdentity string `gorm:"column:smart_cylinder_valve_identity;type:varchar(36);not null;default:'';index" json:"smart_cylinder_valve_identity"` // smart_cylinder_valve_identity 业务字段
SLAAt *time.Time `gorm:"column:sla_at;type:timestamptz" json:"sla_at"` // sla_at 业务字段
}
func init() { database.AppendMigrate(&SafeEvent{}) }
func (table *SafeEvent) TableName() string { return "safe_event" }

View File

@@ -1,15 +0,0 @@
package models
import "git.apinb.com/bsm-sdk/core/database"
// SafeEventDisposal 对应 safe_event_disposal保存安全处置记录。
type SafeEventDisposal struct {
Entity // 公共实体字段
SafeEventIdentity string `gorm:"column:safe_event_identity;type:varchar(36);not null;index" json:"safe_event_identity"` // safe_event_identity 业务字段
Action string `gorm:"column:action;type:varchar(64);not null" json:"action"` // action 业务字段
Reason string `gorm:"column:reason;type:text;not null;default:''" json:"reason"` // reason 业务字段
OperatorIdentity string `gorm:"column:operator_identity;type:varchar(36);not null;default:''" json:"operator_identity"` // operator_identity 业务字段
}
func init() { database.AppendMigrate(&SafeEventDisposal{}) }
func (table *SafeEventDisposal) TableName() string { return "safe_event_disposal" }

View File

@@ -1,15 +0,0 @@
package models
import "git.apinb.com/bsm-sdk/core/database"
// SafeInspection 对应 safe_inspection保存安检与复检记录。
type SafeInspection struct {
Entity // 公共实体字段
UserAccountID uint64 `gorm:"column:user_account_id;not null;index" json:"user_account_id"` // user_account_id 业务字段
StaffAccountID uint64 `gorm:"column:staff_account_id;not null;index" json:"staff_account_id"` // staff_account_id 业务字段
Result string `gorm:"column:result;type:varchar(32);not null" json:"result"` // result 业务字段
EvidenceURI string `gorm:"column:evidence_uri;type:varchar(512);not null;default:''" json:"evidence_uri"` // evidence_uri 业务字段
}
func init() { database.AppendMigrate(&SafeInspection{}) }
func (table *SafeInspection) TableName() string { return "safe_inspection" }

View File

@@ -1,16 +0,0 @@
package models
import "git.apinb.com/bsm-sdk/core/database"
// SafeRule 对应 safe_rule保存安全规则。
type SafeRule struct {
Entity // 公共实体字段
RuleCode string `gorm:"column:rule_code;type:varchar(64);not null;uniqueIndex" json:"rule_code"` // rule_code 业务字段
VersionNo int `gorm:"column:version_no;not null;default:1" json:"version_no"` // version_no 业务字段
Threshold string `gorm:"column:threshold;type:text;not null;default:''" json:"threshold"` // threshold 业务字段
Action string `gorm:"column:action;type:varchar(64);not null" json:"action"` // action 业务字段
GrayScope string `gorm:"column:gray_scope;type:text;not null;default:''" json:"gray_scope"` // gray_scope 业务字段
}
func init() { database.AppendMigrate(&SafeRule{}) }
func (table *SafeRule) TableName() string { return "safe_rule" }

View File

@@ -28,7 +28,6 @@ func RegisterPlatform(serviceKey string, engine *gin.Engine) {
registerStaffRoute(protected)
registerUserRoute(protected)
registerDeviceRoute(protected)
registerSafetyRoute(protected)
registerCommerceRoute(protected)
registerFinanceRoute(protected)
registerContentRoute(protected)
@@ -60,14 +59,6 @@ func registerDeviceRoute(group *gin.RouterGroup) {
telemetry.GET("/:identity", get)
}
func registerSafetyRoute(group *gin.RouterGroup) {
registerRestrictedWritableResource(group, "/safety/safe_rule", &models.SafeRule{}, []string{"rule_code", "version_no", "threshold", "action", "gray_scope"})
registerRestrictedWritableResource(group, "/safety/safe_event", &models.SafeEvent{}, []string{"event_code", "level", "title", "smart_cylinder_valve_identity", "sla_at"})
registerRestrictedWritableResource(group, "/safety/safe_inspection", &models.SafeInspection{}, []string{"result", "evidence_uri"}, requiredRelation("user_account_identity", "user_account_id", &models.UserAccount{}), requiredRelation("staff_account_identity", "staff_account_id", &models.StaffAccount{}))
group.GET("/safety/safe_event/:identity/disposals", platform.ListSafetyEventDisposals)
group.POST("/safety/safe_event/:identity/disposals", platform.DisposeSafetyEvent)
}
func registerCommerceRoute(group *gin.RouterGroup) {
categoryRelations := []platform.ResourceRelation{optionalRelation("parent_identity", "parent_id", &models.EcCategory{})}
_, categoryCreate, _, categoryUpdate := platform.ResourceHandlers(&models.EcCategory{}, []string{"name", "sort_no"}, []string{"name", "sort_no"}, categoryRelations...)

View File

@@ -87,7 +87,7 @@ func TestPlatformOrganizationAndAccountRoutesExposeResourceCRUD(t *testing.T) {
assertRouteMethods(t, routes, "/heqi/platform/v1/platform/platform_role/:identity/menus", http.MethodPut)
}
func TestPlatformDeviceSafetyCommerceAndDeliveryRoutesFollowTheirContracts(t *testing.T) {
func TestPlatformDeviceCommerceAndDeliveryRoutesFollowTheirContracts(t *testing.T) {
engine := gin.New()
RegisterPlatform("heqi", engine)
@@ -101,7 +101,6 @@ func TestPlatformDeviceSafetyCommerceAndDeliveryRoutesFollowTheirContracts(t *te
for _, resource := range []string{
"/device/dev_smart_cylinder_valve", "/device/dev_device_binding",
"/safety/safe_rule", "/safety/safe_event", "/safety/safe_inspection",
"/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",
} {
@@ -126,20 +125,15 @@ func TestPlatformDeviceSafetyCommerceAndDeliveryRoutesFollowTheirContracts(t *te
}
}
disposal := "/heqi/platform/v1/safety/safe_event/:identity/disposals"
assertRouteMethods(t, routes, disposal, http.MethodGet, http.MethodPost)
if routes[disposal][http.MethodDelete] {
t.Fatal("safety event disposals must be append-only")
}
legacySafetyPrefix := "/safety/" + "sa" + "f_"
for _, resource := range []string{legacySafetyPrefix + "rule", legacySafetyPrefix + "event", legacySafetyPrefix + "inspection"} {
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)
}
assertNoRouteMethods(t, routes, "/heqi/platform/v1"+legacySafetyPrefix+"event/:identity/disposals", http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete)
}
func TestPlatformFinanceContentRoutesFollowTheirContracts(t *testing.T) {