Files
platform/web/services/verifier_test.go

242 lines
5.7 KiB
Go

package services
import (
"context"
"platform/pkg/testutil"
"strconv"
"testing"
"time"
"github.com/alicebob/miniredis/v2"
)
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 := testutil.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 := testutil.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("限速锁验证成功后应删除,但仍存在")
}
}
})
}
}