package auth import ( "context" "testing" "time" smsprovider "hfb_sys/backend/internal/integrations/sms" "github.com/redis/go-redis/v9" "go.uber.org/zap" ) type recordProvider struct { sentPhones []string } func (p *recordProvider) SendLoginCode(ctx context.Context, phone string, code string) error { p.sentPhones = append(p.sentPhones, phone) return nil } func (p *recordProvider) SendTemplate(ctx context.Context, req smsprovider.TemplateRequest) error { p.sentPhones = append(p.sentPhones, req.Phone) return nil } type mockResolver struct { customProvider smsprovider.Provider calledSites []string } func (m *mockResolver) ResolveSMSProvider(ctx context.Context, siteCode, domain string) (smsprovider.Provider, error) { m.calledSites = append(m.calledSites, siteCode) if siteCode == "site_custom" { return m.customProvider, nil } return nil, nil } func TestSendSMSCode_SiteResolutionAndFallback(t *testing.T) { rdb := redis.NewClient(&redis.Options{ Addr: "127.0.0.1:16379", DB: 14, }) ctx := t.Context() if err := rdb.Ping(ctx).Err(); err != nil { t.Skipf("跳过测试:未检测到测试 Redis: %v", err) } t.Cleanup(func() { _ = rdb.FlushDB(context.Background()).Err() _ = rdb.Close() }) _ = rdb.FlushDB(ctx) defaultProv := &recordProvider{} customProv := &recordProvider{} resolver := &mockResolver{customProvider: customProv} svc := NewService(nil, rdb, nil, defaultProv, zap.NewNop()) svc.SetSiteSMSResolver(resolver) // 1. 无分站标识 -> 使用默认主站 provider if err := rdb.Set(ctx, "captcha:auth:sms:cap1", "ABCD", time.Minute).Err(); err != nil { t.Fatal(err) } phone1 := "13800138001" err := svc.SendSMSCode(ctx, phone1, "cap1", "ABCD") if err != nil { t.Fatalf("SendSMSCode failed: %v", err) } if len(defaultProv.sentPhones) != 1 || defaultProv.sentPhones[0] != phone1 { t.Fatalf("expected default provider to send, got %v", defaultProv.sentPhones) } if len(customProv.sentPhones) != 0 { t.Fatalf("custom provider should not be called without site") } // 2. 携带自定义短信分站标识 -> 使用 custom provider if err := rdb.Set(ctx, "captcha:auth:sms:cap2", "EFGH", time.Minute).Err(); err != nil { t.Fatal(err) } phone2 := "13800138002" err = svc.SendSMSCode(ctx, phone2, "cap2", "EFGH", "site_custom") if err != nil { t.Fatalf("SendSMSCode with custom site failed: %v", err) } if len(customProv.sentPhones) != 1 || customProv.sentPhones[0] != phone2 { t.Fatalf("expected custom provider to send, got %v", customProv.sentPhones) } // 3. 携带未配置短信分站标识 -> 优雅降级到 default provider if err := rdb.Set(ctx, "captcha:auth:sms:cap3", "JKLM", time.Minute).Err(); err != nil { t.Fatal(err) } phone3 := "13800138003" err = svc.SendSMSCode(ctx, phone3, "cap3", "JKLM", "site_fallback") if err != nil { t.Fatalf("SendSMSCode with fallback site failed: %v", err) } if len(defaultProv.sentPhones) != 2 || defaultProv.sentPhones[1] != phone3 { t.Fatalf("expected default provider to handle fallback, got %v", defaultProv.sentPhones) } }