package usecase_test import ( "context" "testing" memberconfig "gateway/internal/model/member/config" "gateway/internal/model/member/domain/enum" domusecase "gateway/internal/model/member/domain/usecase" "gateway/internal/model/member/repository" "gateway/internal/model/member/usecase" redislib "gateway/internal/library/redis" "github.com/alicebob/miniredis/v2" "github.com/stretchr/testify/require" "github.com/zeromicro/go-zero/core/stores/redis" ) func TestOTPUseCase_GenerateAndVerify(t *testing.T) { mr := miniredis.RunT(t) rds, err := redislib.NewClient(redis.RedisConf{Host: mr.Addr(), Type: "node"}) require.NoError(t, err) uc := usecase.MustOTPUseCase(usecase.OTPUseCaseParam{ Store: repository.NewRedisOTPChallengeStore(rds), Config: memberconfig.Config{}.Defaults(), }) dto, code, err := uc.Generate(context.Background(), &domusecase.GenerateOTPRequest{ TenantID: "t1", UID: "u1", Purpose: enum.OTPPurposeBusinessEmail, Target: "user@example.com", }) require.NoError(t, err) require.NotEmpty(t, code) target, err := uc.Verify(context.Background(), &domusecase.VerifyOTPRequest{ TenantID: "t1", UID: "u1", ChallengeID: dto.ChallengeID, Code: code, Purpose: enum.OTPPurposeBusinessEmail, }) require.NoError(t, err) require.Equal(t, "user@example.com", target) } func TestOTPUseCase_VerifyUIDMismatch(t *testing.T) { mr := miniredis.RunT(t) rds, err := redislib.NewClient(redis.RedisConf{Host: mr.Addr(), Type: "node"}) require.NoError(t, err) uc := usecase.MustOTPUseCase(usecase.OTPUseCaseParam{ Store: repository.NewRedisOTPChallengeStore(rds), Config: memberconfig.Config{}.Defaults(), }) dto, code, err := uc.Generate(context.Background(), &domusecase.GenerateOTPRequest{ TenantID: "t1", UID: "victim", Purpose: enum.OTPPurposeBusinessEmail, Target: "user@example.com", }) require.NoError(t, err) _, err = uc.Verify(context.Background(), &domusecase.VerifyOTPRequest{ TenantID: "t1", UID: "attacker", ChallengeID: dto.ChallengeID, Code: code, Purpose: enum.OTPPurposeBusinessEmail, }) require.Error(t, err) } func TestOTPUseCase_MaxAttemptsLocks(t *testing.T) { mr := miniredis.RunT(t) rds, err := redislib.NewClient(redis.RedisConf{Host: mr.Addr(), Type: "node"}) require.NoError(t, err) cfg := memberconfig.Config{}.Defaults() cfg.OTP.MaxAttempts = 2 uc := usecase.MustOTPUseCase(usecase.OTPUseCaseParam{ Store: repository.NewRedisOTPChallengeStore(rds), Config: cfg, }) dto, _, err := uc.Generate(context.Background(), &domusecase.GenerateOTPRequest{ TenantID: "t1", UID: "u1", Purpose: enum.OTPPurposeBusinessEmail, Target: "user@example.com", }) require.NoError(t, err) for range cfg.OTP.MaxAttempts { _, err = uc.Verify(context.Background(), &domusecase.VerifyOTPRequest{ TenantID: "t1", UID: "u1", ChallengeID: dto.ChallengeID, Code: "000000", Purpose: enum.OTPPurposeBusinessEmail, }) require.Error(t, err) } _, err = uc.Verify(context.Background(), &domusecase.VerifyOTPRequest{ TenantID: "t1", UID: "u1", ChallengeID: dto.ChallengeID, Code: "000000", Purpose: enum.OTPPurposeBusinessEmail, }) require.Error(t, err) }