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 }