2bec257289
iotlcm-worker-svr:异步执行中枢(RabbitMQ 消费者 + 全量同步编排)。 - Go module:iotlcm-worker-svr → git.5iot.com/iotlcm-public/iotlcm-worker-svr(214 文件) - 凭据与内部标识脱敏:MySQL/Redis 凭据、私网与生产 IP、内网域名、 库名 xiujie_admin → iotlcm、哨兵名占位 - 159 处真实手机号 → 合法 11 位编造号(保留号段与后 4 位,维持互异, 不破坏「校验 MSISDN 格式」等测试断言) - 移除内部资产:CI 触发器、Jenkins 触发测试文档、预演门禁与镜像 digest 记录 - Dockerfile 改用公共基础镜像(golang:1.25-alpine → alpine:3.23), 移除写死的 git 凭据 - README 重写(架构/全量同步模型/配置/已知失败),补 Apache-2.0 LICENSE,LF 行尾 + .gitattributes 已知:3 个测试包在源仓同一提交上同样失败(client/upstream、 service/allocate、service/inbound),属既有缺陷,本仓未引入亦未修复。
219 lines
9.3 KiB
Go
219 lines
9.3 KiB
Go
package renewchange
|
|
|
|
import (
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gogf/gf/v2/os/gtime"
|
|
)
|
|
|
|
func TestOrderDOLocalSchemaMatchesProductionContract(t *testing.T) {
|
|
want := []string{
|
|
"Id", "OrderSn", "ParentOrderId", "ParentOrderSn", "CustomerType",
|
|
"CustomerAgentId", "EndUserId", "AgentId", "OrderType", "OrderStatus",
|
|
"ShippingStatus", "ReturnStatus", "Consignee", "Mobile", "Email", "Address",
|
|
"AreaCode", "BuyerNote", "AdminNote", "Remark", "ShippingMethod", "LogisticsId",
|
|
"LogisticsName", "ShippingTypeId", "ShippingTypeName", "TrackingNo", "ShippingTime",
|
|
"ReceivedTime", "PayType", "PayStatus", "PayOrderSn", "PayTime", "TotalAmount",
|
|
"ProductAmount", "ShippingFee", "ServiceFee", "InvoiceFee", "CouponAmount",
|
|
"DiscountAmount", "Balance", "PaidAmount", "OnlinePaidAmount", "OfflinePaidAmount",
|
|
"UnpaidAmount", "UnrefundAmount", "IsNeedCommission", "DistributionStatus", "TenantId",
|
|
"CreatedDept", "CreatedBy", "CreatedAt", "UpdatedBy", "UpdatedAt",
|
|
}
|
|
assertDOFields(t, reflect.TypeOf(OrderDO{}), want)
|
|
}
|
|
|
|
func TestOrderItemDOLocalSchemaMatchesProductionContract(t *testing.T) {
|
|
want := []string{
|
|
"ItemId", "OrderId", "OrderSn", "CustomerType", "CustomerAgentId", "EndUserId",
|
|
"Price", "Quantity", "ProductId", "ProductName", "ProductSn", "PicThumb", "SkuId",
|
|
"SkuData", "DeliveryQuantity", "ProductType", "IsGift", "AgentId", "PrepayPrice",
|
|
"Commission", "OriginPrice", "PromotionData", "ExtraSkuData", "PayMode",
|
|
"ServiceBeginTime", "ServiceEndTime", "TenantId", "CreatedDept", "CreatedBy",
|
|
"CreatedAt", "UpdatedBy", "UpdatedAt",
|
|
}
|
|
assertDOFields(t, reflect.TypeOf(OrderItemDO{}), want)
|
|
}
|
|
|
|
func TestOrderDOsHaveExplicitORMColumnMappings(t *testing.T) {
|
|
for _, testCase := range []struct {
|
|
name string
|
|
typ reflect.Type
|
|
}{
|
|
{name: "order", typ: reflect.TypeOf(OrderDO{})},
|
|
{name: "order item", typ: reflect.TypeOf(OrderItemDO{})},
|
|
{name: "change history", typ: reflect.TypeOf(ChangeBindHistoryDO{})},
|
|
{name: "change order update", typ: reflect.TypeOf(changeOrderUpdateDO{})},
|
|
{name: "change order item update", typ: reflect.TypeOf(changeOrderItemUpdateDO{})},
|
|
{name: "change card update", typ: reflect.TypeOf(changeCardUpdateDO{})},
|
|
} {
|
|
t.Run(testCase.name, func(t *testing.T) {
|
|
for i := 0; i < testCase.typ.NumField(); i++ {
|
|
field := testCase.typ.Field(i)
|
|
if field.Name == "Meta" {
|
|
continue
|
|
}
|
|
if got := field.Tag.Get("orm"); got == "" {
|
|
t.Errorf("%s has no explicit orm column mapping", field.Name)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestOrderDOTagsMatchProductionColumns(t *testing.T) {
|
|
assertDOColumnTags(t, reflect.TypeOf(OrderDO{}), map[string]string{
|
|
"OrderSn": "order_sn", "CustomerAgentId": "customer_agent_id", "EndUserId": "end_user_id", "AgentId": "agent_id",
|
|
"OrderType": "order_type", "OrderStatus": "order_status", "ShippingStatus": "shipping_status", "ReturnStatus": "return_status",
|
|
"BuyerNote": "buyer_note", "AdminNote": "admin_note", "Remark": "remark", "PayType": "pay_type", "PayStatus": "pay_status",
|
|
"PayTime": "pay_time", "TotalAmount": "total_amount", "ProductAmount": "product_amount", "PaidAmount": "paid_amount",
|
|
"OnlinePaidAmount": "online_paid_amount", "OfflinePaidAmount": "offline_paid_amount", "TenantId": "tenant_id",
|
|
"CreatedDept": "created_dept", "CreatedBy": "created_by", "CreatedAt": "created_at", "UpdatedBy": "updated_by", "UpdatedAt": "updated_at",
|
|
})
|
|
assertDOColumnTags(t, reflect.TypeOf(OrderItemDO{}), map[string]string{
|
|
"ItemId": "item_id", "OrderId": "order_id", "OrderSn": "order_sn", "CustomerAgentId": "customer_agent_id", "EndUserId": "end_user_id",
|
|
"Price": "price", "Quantity": "quantity", "ProductId": "product_id", "ProductName": "product_name", "ProductSn": "product_sn",
|
|
"SkuData": "sku_data", "ProductType": "product_type", "IsGift": "is_gift", "AgentId": "agent_id", "OriginPrice": "origin_price",
|
|
"ExtraSkuData": "extra_sku_data", "PayMode": "pay_mode", "ServiceBeginTime": "service_begin_time", "ServiceEndTime": "service_end_time",
|
|
"TenantId": "tenant_id", "CreatedDept": "created_dept", "CreatedBy": "created_by", "CreatedAt": "created_at", "UpdatedBy": "updated_by", "UpdatedAt": "updated_at",
|
|
})
|
|
}
|
|
|
|
func TestNextOrderSNIsGeneratedBeforeInsert(t *testing.T) {
|
|
got, err := NextOrderSN(time.Date(2026, 8, 3, 10, 2, 50, 0, time.Local))
|
|
if err != nil {
|
|
t.Fatalf("NextOrderSN returned error: %v", err)
|
|
}
|
|
if !strings.HasPrefix(got, "SO20260803100250") {
|
|
t.Fatalf("NextOrderSN = %q, want SO prefix and timestamp", got)
|
|
}
|
|
if len(got) != len("SO20260803100250")+8 {
|
|
t.Fatalf("NextOrderSN length = %d, want %d", len(got), len("SO20260803100250")+8)
|
|
}
|
|
}
|
|
|
|
func TestValidateContractOrderRequiredFields(t *testing.T) {
|
|
now := gtime.NewFromTime(time.Date(2026, 8, 3, 10, 2, 50, 0, time.Local))
|
|
order := &OrderDO{
|
|
OrderSn: "SO20260803100250ABCDEFGH",
|
|
CustomerAgentId: int64(200),
|
|
AgentId: int64(100),
|
|
TenantId: "000000",
|
|
CreatedDept: int64(100),
|
|
CreatedBy: int64(1),
|
|
CreatedAt: now,
|
|
UpdatedBy: int64(1),
|
|
UpdatedAt: now,
|
|
}
|
|
if err := ValidateOrderDO(order); err != nil {
|
|
t.Fatalf("ValidateOrderDO returned error: %v", err)
|
|
}
|
|
for _, testCase := range []struct {
|
|
name string
|
|
clear func(*OrderDO)
|
|
}{
|
|
{name: "order number", clear: func(order *OrderDO) { order.OrderSn = "" }},
|
|
{name: "customer agent", clear: func(order *OrderDO) { order.CustomerAgentId = int64(0) }},
|
|
{name: "seller agent", clear: func(order *OrderDO) { order.AgentId = int64(0) }},
|
|
{name: "tenant", clear: func(order *OrderDO) { order.TenantId = "" }},
|
|
{name: "creator department", clear: func(order *OrderDO) { order.CreatedDept = int64(0) }},
|
|
{name: "creator", clear: func(order *OrderDO) { order.CreatedBy = int64(0) }},
|
|
{name: "updater", clear: func(order *OrderDO) { order.UpdatedBy = int64(0) }},
|
|
{name: "created time", clear: func(order *OrderDO) { order.CreatedAt = nil }},
|
|
{name: "updated time", clear: func(order *OrderDO) { order.UpdatedAt = nil }},
|
|
} {
|
|
t.Run(testCase.name, func(t *testing.T) {
|
|
invalid := *order
|
|
testCase.clear(&invalid)
|
|
if err := ValidateOrderDO(&invalid); err == nil {
|
|
t.Fatalf("ValidateOrderDO accepted missing %s", testCase.name)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidateContractOrderItemRequiredFields(t *testing.T) {
|
|
beginAt := gtime.NewFromTime(time.Date(2026, 8, 3, 0, 0, 0, 0, time.Local))
|
|
endAt := gtime.NewFromTime(time.Date(2027, 8, 3, 0, 0, 0, 0, time.Local))
|
|
item := &OrderItemDO{
|
|
OrderId: int64(1),
|
|
OrderSn: "SO20260803100250ABCDEFGH",
|
|
CustomerAgentId: int64(200),
|
|
AgentId: int64(100),
|
|
Quantity: 2,
|
|
ProductId: int64(300),
|
|
ProductName: "package",
|
|
ProductSn: "PKG001",
|
|
ServiceBeginTime: beginAt,
|
|
ServiceEndTime: endAt,
|
|
TenantId: "000000",
|
|
CreatedDept: int64(100),
|
|
CreatedBy: int64(1),
|
|
CreatedAt: beginAt,
|
|
UpdatedBy: int64(1),
|
|
UpdatedAt: beginAt,
|
|
}
|
|
if err := ValidateOrderItemDO(item); err != nil {
|
|
t.Fatalf("ValidateOrderItemDO returned error: %v", err)
|
|
}
|
|
for _, testCase := range []struct {
|
|
name string
|
|
clear func(*OrderItemDO)
|
|
}{
|
|
{name: "order id", clear: func(item *OrderItemDO) { item.OrderId = int64(0) }},
|
|
{name: "order number", clear: func(item *OrderItemDO) { item.OrderSn = "" }},
|
|
{name: "customer agent", clear: func(item *OrderItemDO) { item.CustomerAgentId = int64(0) }},
|
|
{name: "seller agent", clear: func(item *OrderItemDO) { item.AgentId = int64(0) }},
|
|
{name: "quantity", clear: func(item *OrderItemDO) { item.Quantity = 0 }},
|
|
{name: "product id", clear: func(item *OrderItemDO) { item.ProductId = int64(0) }},
|
|
{name: "product name", clear: func(item *OrderItemDO) { item.ProductName = "" }},
|
|
{name: "product code", clear: func(item *OrderItemDO) { item.ProductSn = "" }},
|
|
{name: "service start", clear: func(item *OrderItemDO) { item.ServiceBeginTime = nil }},
|
|
{name: "service end", clear: func(item *OrderItemDO) { item.ServiceEndTime = nil }},
|
|
{name: "tenant", clear: func(item *OrderItemDO) { item.TenantId = "" }},
|
|
{name: "creator department", clear: func(item *OrderItemDO) { item.CreatedDept = int64(0) }},
|
|
{name: "creator", clear: func(item *OrderItemDO) { item.CreatedBy = int64(0) }},
|
|
{name: "updater", clear: func(item *OrderItemDO) { item.UpdatedBy = int64(0) }},
|
|
{name: "created time", clear: func(item *OrderItemDO) { item.CreatedAt = nil }},
|
|
{name: "updated time", clear: func(item *OrderItemDO) { item.UpdatedAt = nil }},
|
|
} {
|
|
t.Run(testCase.name, func(t *testing.T) {
|
|
invalid := *item
|
|
testCase.clear(&invalid)
|
|
if err := ValidateOrderItemDO(&invalid); err == nil {
|
|
t.Fatalf("ValidateOrderItemDO accepted missing %s", testCase.name)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func assertDOFields(t *testing.T, typ reflect.Type, want []string) {
|
|
t.Helper()
|
|
got := make([]string, 0, typ.NumField()-1)
|
|
for i := 0; i < typ.NumField(); i++ {
|
|
field := typ.Field(i)
|
|
if field.Name == "Meta" {
|
|
continue
|
|
}
|
|
got = append(got, field.Name)
|
|
}
|
|
if !reflect.DeepEqual(got, want) {
|
|
t.Fatalf("%s fields mismatch\n got: %v\nwant: %v", typ.Name(), got, want)
|
|
}
|
|
}
|
|
|
|
func assertDOColumnTags(t *testing.T, typ reflect.Type, want map[string]string) {
|
|
t.Helper()
|
|
for fieldName, column := range want {
|
|
field, ok := typ.FieldByName(fieldName)
|
|
if !ok {
|
|
t.Fatalf("%s missing field %s", typ.Name(), fieldName)
|
|
}
|
|
if got := field.Tag.Get("orm"); got != column {
|
|
t.Fatalf("%s.%s orm tag = %q, want %q", typ.Name(), fieldName, got, column)
|
|
}
|
|
}
|
|
}
|