- 同步上游 DLC (聚鑫源) 最新 GoodID 映射: - suit_shadow_gothic: 6a13aa55e3bce430aca29b01 - top_black_elite_trainer: 6a13aaeae3bce430aca29b03 - suit_romantic_destiny: 6a13ab21e3bce430aca29b04 - 更新 delivery_helpers 缺省兜底映射表与 sync_product_images 常量 - 更新 provider_test 单元测试断言与 docs/商品目录.md 文档 - 验证方式:go test 单元测试通过,go vet 校验通过
148 lines
5.9 KiB
Go
148 lines
5.9 KiB
Go
package service
|
||
|
||
import (
|
||
"testing"
|
||
|
||
"affiliate_dash/internal/model"
|
||
)
|
||
|
||
func TestParseProductRoutingConfig(t *testing.T) {
|
||
// Case 1: 存量老商品未配置,根据 SKU 默认走 DLC
|
||
cfg1 := ParseProductRoutingConfig("", "suit_pink_sheep")
|
||
if cfg1.RoutingMode != RoutingModeDLC {
|
||
t.Fatalf("expected RoutingModeDLC, got %s", cfg1.RoutingMode)
|
||
}
|
||
if cfg1.DLCGoodID != "682ef3c5a8f40c4234c59f4d" {
|
||
t.Fatalf("expected builtin goodID 682ef3c5a8f40c4234c59f4d, got %s", cfg1.DLCGoodID)
|
||
}
|
||
|
||
// Case 2: 仅配置乐玩
|
||
cfg2JSON := `{"routing_mode":"lewan","lewan_product_id":"uuid-001","delivery_type":"LINK_BINDING"}`
|
||
cfg2 := ParseProductRoutingConfig(cfg2JSON, "any_sku")
|
||
if cfg2.RoutingMode != RoutingModeLewan {
|
||
t.Fatalf("expected RoutingModeLewan, got %s", cfg2.RoutingMode)
|
||
}
|
||
if cfg2.LewanProductID != "uuid-001" {
|
||
t.Fatalf("expected lewan_product_id uuid-001, got %s", cfg2.LewanProductID)
|
||
}
|
||
|
||
// Case 3: 双平台优先级 (乐玩优先)
|
||
cfg3JSON := `{"routing_mode":"priority","priority":["lewan","dlc"],"dlc_good_id":"dlc-123","lewan_product_id":"uuid-123"}`
|
||
cfg3 := ParseProductRoutingConfig(cfg3JSON, "any_sku")
|
||
if cfg3.RoutingMode != RoutingModePriority {
|
||
t.Fatalf("expected RoutingModePriority, got %s", cfg3.RoutingMode)
|
||
}
|
||
if len(cfg3.Priority) != 2 || cfg3.Priority[0] != ProviderLewan || cfg3.Priority[1] != ProviderDLC {
|
||
t.Fatalf("expected priority [lewan, dlc], got %+v", cfg3.Priority)
|
||
}
|
||
if cfg3.DLCGoodID != "dlc-123" || cfg3.LewanProductID != "uuid-123" {
|
||
t.Fatalf("mismatched IDs: dlc=%s lewan=%s", cfg3.DLCGoodID, cfg3.LewanProductID)
|
||
}
|
||
|
||
// Case 4: 兼容历史 legacy 单 provider 字段(无内置 DLC 时仍为 lewan-only)
|
||
cfg4JSON := `{"provider":"lewan","lewan_product_id":"uuid-999"}`
|
||
cfg4 := ParseProductRoutingConfig(cfg4JSON, "any_sku")
|
||
if cfg4.RoutingMode != RoutingModeLewan || cfg4.LewanProductID != "uuid-999" {
|
||
t.Fatalf("legacy lewan format failed: %+v", cfg4)
|
||
}
|
||
|
||
// Case 5: legacy 仅有 lewan_product_id,但 SKU 有内置 DLC → 应升为 priority
|
||
cfg5JSON := `{"lewan_product_id":"b1fff090-e389-4c6c-9c51-32751582239d"}`
|
||
cfg5 := ParseProductRoutingConfig(cfg5JSON, "suit_romantic_destiny")
|
||
if cfg5.RoutingMode != RoutingModePriority {
|
||
t.Fatalf("expected priority for dual-capable legacy config, got %s", cfg5.RoutingMode)
|
||
}
|
||
if cfg5.DLCGoodID != "6a13ab21e3bce430aca29b04" {
|
||
t.Fatalf("expected builtin DLC good id, got %s", cfg5.DLCGoodID)
|
||
}
|
||
|
||
cfgRock := ParseProductRoutingConfig(`{"routing_mode":"rock","priority":["rock"],"delivery_type":"LINK_BINDING"}`, "rock_black_tshirt")
|
||
if cfgRock.RoutingMode != RoutingModeRock || len(cfgRock.Priority) != 1 || cfgRock.Priority[0] != ProviderRock {
|
||
t.Fatalf("expected rock-only routing, got %+v", cfgRock)
|
||
}
|
||
}
|
||
|
||
func TestFulfillmentRouterResolution(t *testing.T) {
|
||
dlc := NewDLCProvider("https://bff.example", "dlc", nil)
|
||
lewan := NewLewanProvider(nil)
|
||
router := NewFulfillmentRouter(dlc, lewan)
|
||
|
||
// Case 1: 存量 DLC 商品
|
||
orderDLC := &model.FulfillmentOrder{
|
||
ProductSKU: "suit_alan_walker",
|
||
}
|
||
providers, _ := router.ResolveProviders(orderDLC)
|
||
if len(providers) != 1 || providers[0].Name() != ProviderDLC {
|
||
t.Fatalf("expected DLC provider for suit_alan_walker, got %d providers", len(providers))
|
||
}
|
||
|
||
// Case 2: 仅乐玩商品
|
||
orderLewan := &model.FulfillmentOrder{
|
||
ProductSKU: "custom_lewan_item",
|
||
MerchantProduct: &model.MerchantProduct{
|
||
FulfillmentConfig: `{"routing_mode":"lewan","lewan_product_id":"uuid-001"}`,
|
||
},
|
||
}
|
||
providers, _ = router.ResolveProviders(orderLewan)
|
||
if len(providers) != 1 || providers[0].Name() != ProviderLewan {
|
||
t.Fatalf("expected Lewan provider, got %d providers", len(providers))
|
||
}
|
||
|
||
// Case 2b: 显式 lewan 但 SKU 有内置 DLC → 应附带 DLC 回退
|
||
orderLewanWithDLC := &model.FulfillmentOrder{
|
||
ProductSKU: "suit_romantic_destiny",
|
||
MerchantProduct: &model.MerchantProduct{
|
||
FulfillmentConfig: `{"routing_mode":"lewan","lewan_product_id":"b1fff090-e389-4c6c-9c51-32751582239d","dlc_good_id":""}`,
|
||
},
|
||
}
|
||
providers, _ = router.ResolveProviders(orderLewanWithDLC)
|
||
if len(providers) != 2 || providers[0].Name() != ProviderLewan || providers[1].Name() != ProviderDLC {
|
||
t.Fatalf("expected [lewan, dlc] fallback, got %v", providerNames(providers))
|
||
}
|
||
|
||
// Case 3: 优先级路由 [lewan, dlc]
|
||
orderPriority := &model.FulfillmentOrder{
|
||
ProductSKU: "shared_item",
|
||
MerchantProduct: &model.MerchantProduct{
|
||
FulfillmentConfig: `{"routing_mode":"priority","priority":["lewan","dlc"],"lewan_product_id":"uuid-001","dlc_good_id":"dlc-001"}`,
|
||
},
|
||
}
|
||
providers, _ = router.ResolveProviders(orderPriority)
|
||
if len(providers) != 2 || providers[0].Name() != ProviderLewan || providers[1].Name() != ProviderDLC {
|
||
t.Fatalf("expected [lewan, dlc], got %v", providers)
|
||
}
|
||
|
||
// Case 4: 订单已锁定渠道(已在 result_data 中写明 provider=dlc)
|
||
orderLocked := &model.FulfillmentOrder{
|
||
ProductSKU: "shared_item",
|
||
MerchantProduct: &model.MerchantProduct{
|
||
FulfillmentConfig: `{"routing_mode":"priority","priority":["lewan","dlc"],"lewan_product_id":"uuid-001","dlc_good_id":"dlc-001"}`,
|
||
},
|
||
ResultData: `{"provider":"dlc"}`,
|
||
}
|
||
providers, _ = router.ResolveProviders(orderLocked)
|
||
if len(providers) != 1 || providers[0].Name() != ProviderDLC {
|
||
t.Fatalf("expected locked DLC provider, got %+v", providers)
|
||
}
|
||
|
||
// Case 5: 优先级 [dlc, lewan]
|
||
orderDLCFirst := &model.FulfillmentOrder{
|
||
ProductSKU: "shared_item",
|
||
MerchantProduct: &model.MerchantProduct{
|
||
FulfillmentConfig: `{"routing_mode":"priority","priority":["dlc","lewan"],"lewan_product_id":"uuid-001","dlc_good_id":"dlc-001"}`,
|
||
},
|
||
}
|
||
providers, _ = router.ResolveProviders(orderDLCFirst)
|
||
if len(providers) != 2 || providers[0].Name() != ProviderDLC || providers[1].Name() != ProviderLewan {
|
||
t.Fatalf("expected [dlc, lewan], got %v", providerNames(providers))
|
||
}
|
||
}
|
||
|
||
func providerNames(providers []FulfillmentProvider) []string {
|
||
names := make([]string, 0, len(providers))
|
||
for _, p := range providers {
|
||
names = append(names, p.Name())
|
||
}
|
||
return names
|
||
}
|