认证授权测试代码与业务代码质量修复
This commit is contained in:
257
web/services/verifier_test.go
Normal file
257
web/services/verifier_test.go
Normal file
@@ -0,0 +1,257 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"platform/init/rds"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/alicebob/miniredis/v2"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
// 设置测试的 Redis 环境
|
||||
func setupRedisTest(t *testing.T) *miniredis.Miniredis {
|
||||
mr, err := miniredis.Run()
|
||||
if err != nil {
|
||||
t.Fatalf("设置 miniredis 失败: %v", err)
|
||||
}
|
||||
|
||||
// 替换 redis 客户端为测试客户端
|
||||
rds.Client = redis.NewClient(&redis.Options{
|
||||
Addr: mr.Addr(),
|
||||
})
|
||||
|
||||
return mr
|
||||
}
|
||||
|
||||
func Test_verifierService_SendSms(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
phone string
|
||||
purpose VerifierSmsPurpose
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
setup func(mr *miniredis.Miniredis)
|
||||
wantErr bool
|
||||
wantErrType error
|
||||
}{
|
||||
{
|
||||
name: "正常发送成功(无旧验证码)",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
phone: "13812345678",
|
||||
purpose: VerifierSmsPurposeLogin,
|
||||
},
|
||||
setup: func(mr *miniredis.Miniredis) {},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "正常发送成功(有旧验证码)",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
phone: "13812345679",
|
||||
purpose: VerifierSmsPurposeLogin,
|
||||
},
|
||||
setup: func(mr *miniredis.Miniredis) {
|
||||
key := smsKey("13812345679", VerifierSmsPurposeLogin)
|
||||
mr.Set(key, "123456")
|
||||
mr.SetTTL(key, 10*time.Minute)
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "发送频率过快",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
phone: "13812345680",
|
||||
purpose: VerifierSmsPurposeLogin,
|
||||
},
|
||||
setup: func(mr *miniredis.Miniredis) {
|
||||
key := smsKey("13812345680", VerifierSmsPurposeLogin) + ":lock"
|
||||
mr.Set(key, "")
|
||||
mr.SetTTL(key, 1*time.Minute)
|
||||
},
|
||||
wantErr: true,
|
||||
wantErrType: VerifierServiceSendLimitErr(0),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// 设置 Redis 测试环境
|
||||
mr := setupRedisTest(t)
|
||||
defer mr.Close()
|
||||
|
||||
// 执行测试前的设置
|
||||
if tt.setup != nil {
|
||||
tt.setup(mr)
|
||||
}
|
||||
|
||||
s := &verifierService{}
|
||||
err := s.SendSms(tt.args.ctx, tt.args.phone, tt.args.purpose)
|
||||
|
||||
// 验证错误
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("SendSms() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证错误类型
|
||||
if tt.wantErr && tt.wantErrType != nil {
|
||||
if _, isSendLimitErr := err.(VerifierServiceSendLimitErr); isSendLimitErr {
|
||||
if _, wantSendLimitErr := tt.wantErrType.(VerifierServiceSendLimitErr); !wantSendLimitErr {
|
||||
t.Errorf("SendSms() error type = %T, wantErrType %T", err, tt.wantErrType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 验证 Redis 中的记录
|
||||
if !tt.wantErr {
|
||||
key := smsKey(tt.args.phone, tt.args.purpose)
|
||||
keyLock := key + ":lock"
|
||||
|
||||
// 验证码应存在
|
||||
val, err := mr.Get(key)
|
||||
if err != nil {
|
||||
t.Errorf("验证码应存在但不存在: %v", err)
|
||||
}
|
||||
|
||||
// 限速锁应存在
|
||||
_, err = mr.Get(keyLock)
|
||||
if err != nil {
|
||||
t.Errorf("限速锁应存在但不存在: %v", err)
|
||||
}
|
||||
|
||||
// 验证码应为6位数字
|
||||
code, err := strconv.Atoi(val)
|
||||
if err != nil || code < 100000 || code > 999999 {
|
||||
t.Errorf("验证码应为6位数字: %v", val)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_verifierService_VerifySms(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
phone string
|
||||
code string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
setup func(mr *miniredis.Miniredis)
|
||||
wantErr bool
|
||||
wantErrType error
|
||||
}{
|
||||
{
|
||||
name: "验证码正确",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
phone: "13812345678",
|
||||
code: "123456",
|
||||
},
|
||||
setup: func(mr *miniredis.Miniredis) {
|
||||
key := smsKey("13812345678", VerifierSmsPurposeLogin)
|
||||
keyLock := key + ":lock"
|
||||
mr.Set(key, "123456")
|
||||
mr.SetTTL(key, 10*time.Minute)
|
||||
mr.Set(keyLock, "")
|
||||
mr.SetTTL(keyLock, 1*time.Minute)
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "验证码错误",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
phone: "13812345679",
|
||||
code: "654321",
|
||||
},
|
||||
setup: func(mr *miniredis.Miniredis) {
|
||||
key := smsKey("13812345679", VerifierSmsPurposeLogin)
|
||||
keyLock := key + ":lock"
|
||||
mr.Set(key, "123456")
|
||||
mr.SetTTL(key, 10*time.Minute)
|
||||
mr.Set(keyLock, "")
|
||||
mr.SetTTL(keyLock, 1*time.Minute)
|
||||
},
|
||||
wantErr: true,
|
||||
wantErrType: ErrVerifierServiceInvalid,
|
||||
},
|
||||
{
|
||||
name: "验证码过期",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
phone: "13812345680",
|
||||
code: "123456",
|
||||
},
|
||||
setup: func(mr *miniredis.Miniredis) {
|
||||
// 不设置验证码,模拟过期情况
|
||||
},
|
||||
wantErr: true,
|
||||
wantErrType: ErrVerifierServiceInvalid,
|
||||
},
|
||||
{
|
||||
name: "手机号错误",
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
phone: "13812345681",
|
||||
code: "123456",
|
||||
},
|
||||
setup: func(mr *miniredis.Miniredis) {
|
||||
// 设置一个不同手机号的验证码
|
||||
key := smsKey("13800000000", VerifierSmsPurposeLogin)
|
||||
mr.Set(key, "123456")
|
||||
mr.SetTTL(key, 10*time.Minute)
|
||||
},
|
||||
wantErr: true,
|
||||
wantErrType: ErrVerifierServiceInvalid,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// 设置 Redis 测试环境
|
||||
mr := setupRedisTest(t)
|
||||
defer mr.Close()
|
||||
|
||||
// 执行测试前的设置
|
||||
if tt.setup != nil {
|
||||
tt.setup(mr)
|
||||
}
|
||||
|
||||
s := &verifierService{}
|
||||
err := s.VerifySms(tt.args.ctx, tt.args.phone, tt.args.code)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("VerifySms() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
|
||||
// 检查错误类型
|
||||
if tt.wantErr && tt.wantErrType != nil && err != tt.wantErrType {
|
||||
t.Errorf("VerifySms() error = %v, wantErrType %v", err, tt.wantErrType)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证成功后 Redis 中应该没有该记录
|
||||
if err == nil {
|
||||
key := smsKey(tt.args.phone, VerifierSmsPurposeLogin)
|
||||
keyLock := key + ":lock"
|
||||
|
||||
_, redisErr := mr.Get(key)
|
||||
if redisErr == nil {
|
||||
t.Errorf("验证码验证成功后应删除,但仍存在")
|
||||
}
|
||||
|
||||
_, redisErr = mr.Get(keyLock)
|
||||
if redisErr == nil {
|
||||
t.Errorf("限速锁验证成功后应删除,但仍存在")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user