完善 SmsCodeServiceImpl 单元测试
This commit is contained in:
parent
5a18223bc3
commit
ac25dbe286
@ -1,7 +1,7 @@
|
||||
package cn.iocoder.yudao.module.system.api.sms;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeCheckReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeValidateReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
|
||||
import cn.iocoder.yudao.module.system.enums.ApiConstants;
|
||||
@ -29,8 +29,8 @@ public interface SmsCodeApi {
|
||||
@ApiOperation("验证短信验证码,并进行使用")
|
||||
CommonResult<Boolean> useSmsCode(@Valid @RequestBody SmsCodeUseReqDTO reqDTO);
|
||||
|
||||
@GetMapping(PREFIX + "/check")
|
||||
@GetMapping(PREFIX + "/validate")
|
||||
@ApiOperation("检查验证码是否有效")
|
||||
CommonResult<Boolean> checkSmsCode(@Valid @RequestBody SmsCodeCheckReqDTO reqDTO);
|
||||
CommonResult<Boolean> validateSmsCode(@Valid @RequestBody SmsCodeValidateReqDTO reqDTO);
|
||||
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import javax.validation.constraints.NotNull;
|
||||
|
||||
@ApiModel("RPC 服务 - 短信验证码的校验 Request DTO")
|
||||
@Data
|
||||
public class SmsCodeCheckReqDTO {
|
||||
public class SmsCodeValidateReqDTO {
|
||||
|
||||
@ApiModelProperty(value = "手机号", required = true, example = "15601691300")
|
||||
@Mobile
|
@ -1,7 +1,7 @@
|
||||
package cn.iocoder.yudao.module.system.api.sms;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeCheckReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeValidateReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
|
||||
import cn.iocoder.yudao.module.system.service.sms.SmsCodeService;
|
||||
@ -35,8 +35,8 @@ public class SmsCodeApiImpl implements SmsCodeApi {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> checkSmsCode(SmsCodeCheckReqDTO reqDTO) {
|
||||
smsCodeService.checkSmsCode(reqDTO);
|
||||
public CommonResult<Boolean> validateSmsCode(SmsCodeValidateReqDTO reqDTO) {
|
||||
smsCodeService.validateSmsCode(reqDTO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
package cn.iocoder.yudao.module.system.service.sms;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeCheckReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeValidateReqDTO;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
@ -35,6 +35,6 @@ public interface SmsCodeService {
|
||||
*
|
||||
* @param reqDTO 校验请求
|
||||
*/
|
||||
void checkSmsCode(@Valid SmsCodeCheckReqDTO reqDTO);
|
||||
void validateSmsCode(@Valid SmsCodeValidateReqDTO reqDTO);
|
||||
|
||||
}
|
||||
|
@ -3,11 +3,9 @@ package cn.iocoder.yudao.module.system.service.sms;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
||||
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeCheckReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeValidateReqDTO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsCodeDO;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsCodeMapper;
|
||||
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
|
||||
@ -16,11 +14,11 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
import static cn.hutool.core.util.RandomUtil.randomInt;
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.isToday;
|
||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
|
||||
|
||||
/**
|
||||
@ -58,11 +56,11 @@ public class SmsCodeServiceImpl implements SmsCodeService {
|
||||
if (lastSmsCode != null) {
|
||||
if (LocalDateTimeUtil.between(lastSmsCode.getCreateTime(), LocalDateTime.now()).toMillis()
|
||||
< smsCodeProperties.getSendFrequency().toMillis()) { // 发送过于频繁
|
||||
throw ServiceExceptionUtil.exception(SMS_CODE_SEND_TOO_FAST);
|
||||
throw exception(SMS_CODE_SEND_TOO_FAST);
|
||||
}
|
||||
if (DateUtils.isToday(lastSmsCode.getCreateTime()) && // 必须是今天,才能计算超过当天的上限
|
||||
if (isToday(lastSmsCode.getCreateTime()) && // 必须是今天,才能计算超过当天的上限
|
||||
lastSmsCode.getTodayIndex() >= smsCodeProperties.getSendMaximumQuantityPerDay()) { // 超过当天发送的上限。
|
||||
throw ServiceExceptionUtil.exception(SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY);
|
||||
throw exception(SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY);
|
||||
}
|
||||
// TODO 芋艿:提升,每个 IP 每天可发送数量
|
||||
// TODO 芋艿:提升,每个 IP 每小时可发送数量
|
||||
@ -71,7 +69,7 @@ public class SmsCodeServiceImpl implements SmsCodeService {
|
||||
// 创建验证码记录
|
||||
String code = String.valueOf(randomInt(smsCodeProperties.getBeginCode(), smsCodeProperties.getEndCode() + 1));
|
||||
SmsCodeDO newSmsCode = SmsCodeDO.builder().mobile(mobile).code(code).scene(scene)
|
||||
.todayIndex(lastSmsCode != null && DateUtils.isToday(lastSmsCode.getCreateTime()) ? lastSmsCode.getTodayIndex() + 1 : 1)
|
||||
.todayIndex(lastSmsCode != null && isToday(lastSmsCode.getCreateTime()) ? lastSmsCode.getTodayIndex() + 1 : 1)
|
||||
.createIp(ip).used(false).build();
|
||||
smsCodeMapper.insert(newSmsCode);
|
||||
return code;
|
||||
@ -80,32 +78,32 @@ public class SmsCodeServiceImpl implements SmsCodeService {
|
||||
@Override
|
||||
public void useSmsCode(SmsCodeUseReqDTO reqDTO) {
|
||||
// 检测验证码是否有效
|
||||
SmsCodeDO lastSmsCode = this.checkSmsCode0(reqDTO.getMobile(), reqDTO.getCode(), reqDTO.getScene());
|
||||
SmsCodeDO lastSmsCode = validateSmsCode0(reqDTO.getMobile(), reqDTO.getCode(), reqDTO.getScene());
|
||||
// 使用验证码
|
||||
smsCodeMapper.updateById(SmsCodeDO.builder().id(lastSmsCode.getId())
|
||||
.used(true).usedTime(LocalDateTime.now()).usedIp(reqDTO.getUsedIp()).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkSmsCode(SmsCodeCheckReqDTO reqDTO) {
|
||||
checkSmsCode0(reqDTO.getMobile(), reqDTO.getCode(), reqDTO.getScene());
|
||||
public void validateSmsCode(SmsCodeValidateReqDTO reqDTO) {
|
||||
validateSmsCode0(reqDTO.getMobile(), reqDTO.getCode(), reqDTO.getScene());
|
||||
}
|
||||
|
||||
public SmsCodeDO checkSmsCode0(String mobile, String code, Integer scene) {
|
||||
private SmsCodeDO validateSmsCode0(String mobile, String code, Integer scene) {
|
||||
// 校验验证码
|
||||
SmsCodeDO lastSmsCode = smsCodeMapper.selectLastByMobile(mobile, code, scene);
|
||||
// 若验证码不存在,抛出异常
|
||||
if (lastSmsCode == null) {
|
||||
throw ServiceExceptionUtil.exception(SMS_CODE_NOT_FOUND);
|
||||
throw exception(SMS_CODE_NOT_FOUND);
|
||||
}
|
||||
// 超过时间
|
||||
if (LocalDateTimeUtil.between(lastSmsCode.getCreateTime(), LocalDateTime.now()).toMillis()
|
||||
>= smsCodeProperties.getExpireTimes().toMillis()) { // 验证码已过期
|
||||
throw ServiceExceptionUtil.exception(SMS_CODE_EXPIRED);
|
||||
throw exception(SMS_CODE_EXPIRED);
|
||||
}
|
||||
// 判断验证码是否已被使用
|
||||
if (Boolean.TRUE.equals(lastSmsCode.getUsed())) {
|
||||
throw ServiceExceptionUtil.exception(SMS_CODE_USED);
|
||||
throw exception(SMS_CODE_USED);
|
||||
}
|
||||
return lastSmsCode;
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
|
||||
@ -118,8 +117,8 @@ public class SmsChannelServiceTest extends BaseDbUnitTest {
|
||||
|
||||
// 调用
|
||||
smsChannelService.deleteSmsChannel(id);
|
||||
// 校验数据不存在了
|
||||
assertNull(smsChannelMapper.selectById(id));
|
||||
// 校验数据不存在了
|
||||
assertNull(smsChannelMapper.selectById(id));
|
||||
// 校验调用
|
||||
verify(smsProducer, times(1)).sendSmsChannelRefreshMessage();
|
||||
}
|
||||
@ -178,31 +177,31 @@ public class SmsChannelServiceTest extends BaseDbUnitTest {
|
||||
|
||||
@Test
|
||||
public void testGetSmsChannelPage() {
|
||||
// mock 数据
|
||||
SmsChannelDO dbSmsChannel = randomPojo(SmsChannelDO.class, o -> { // 等会查询到
|
||||
o.setSignature("芋道源码");
|
||||
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
o.setCreateTime(buildTime(2020, 12, 12));
|
||||
});
|
||||
smsChannelMapper.insert(dbSmsChannel);
|
||||
// 测试 signature 不匹配
|
||||
smsChannelMapper.insert(cloneIgnoreId(dbSmsChannel, o -> o.setSignature("源码")));
|
||||
// 测试 status 不匹配
|
||||
smsChannelMapper.insert(cloneIgnoreId(dbSmsChannel, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
|
||||
// 测试 createTime 不匹配
|
||||
smsChannelMapper.insert(cloneIgnoreId(dbSmsChannel, o -> o.setCreateTime(buildTime(2020, 11, 11))));
|
||||
// 准备参数
|
||||
SmsChannelPageReqVO reqVO = new SmsChannelPageReqVO();
|
||||
reqVO.setSignature("芋道");
|
||||
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
reqVO.setCreateTime(buildBetweenTime(2020, 12, 1, 2020, 12, 24));
|
||||
// mock 数据
|
||||
SmsChannelDO dbSmsChannel = randomPojo(SmsChannelDO.class, o -> { // 等会查询到
|
||||
o.setSignature("芋道源码");
|
||||
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
o.setCreateTime(buildTime(2020, 12, 12));
|
||||
});
|
||||
smsChannelMapper.insert(dbSmsChannel);
|
||||
// 测试 signature 不匹配
|
||||
smsChannelMapper.insert(cloneIgnoreId(dbSmsChannel, o -> o.setSignature("源码")));
|
||||
// 测试 status 不匹配
|
||||
smsChannelMapper.insert(cloneIgnoreId(dbSmsChannel, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
|
||||
// 测试 createTime 不匹配
|
||||
smsChannelMapper.insert(cloneIgnoreId(dbSmsChannel, o -> o.setCreateTime(buildTime(2020, 11, 11))));
|
||||
// 准备参数
|
||||
SmsChannelPageReqVO reqVO = new SmsChannelPageReqVO();
|
||||
reqVO.setSignature("芋道");
|
||||
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
reqVO.setCreateTime(buildBetweenTime(2020, 12, 1, 2020, 12, 24));
|
||||
|
||||
// 调用
|
||||
PageResult<SmsChannelDO> pageResult = smsChannelService.getSmsChannelPage(reqVO);
|
||||
// 断言
|
||||
assertEquals(1, pageResult.getTotal());
|
||||
assertEquals(1, pageResult.getList().size());
|
||||
assertPojoEquals(dbSmsChannel, pageResult.getList().get(0));
|
||||
// 调用
|
||||
PageResult<SmsChannelDO> pageResult = smsChannelService.getSmsChannelPage(reqVO);
|
||||
// 断言
|
||||
assertEquals(1, pageResult.getTotal());
|
||||
assertEquals(1, pageResult.getList().size());
|
||||
assertPojoEquals(dbSmsChannel, pageResult.getList().get(0));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,209 @@
|
||||
package cn.iocoder.yudao.module.system.service.sms;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.enums.SqlConstants;
|
||||
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
|
||||
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeValidateReqDTO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsCodeDO;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsCodeMapper;
|
||||
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
|
||||
import cn.iocoder.yudao.module.system.framework.sms.SmsCodeProperties;
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.hutool.core.util.RandomUtil.randomEle;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.isNull;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@Import(SmsCodeServiceImpl.class)
|
||||
public class SmsCodeServiceImplTest extends BaseDbUnitTest {
|
||||
|
||||
@Resource
|
||||
private SmsCodeServiceImpl smsCodeService;
|
||||
|
||||
@Resource
|
||||
private SmsCodeMapper smsCodeMapper;
|
||||
|
||||
@MockBean
|
||||
private SmsCodeProperties smsCodeProperties;
|
||||
@MockBean
|
||||
private SmsSendService smsSendService;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
when(smsCodeProperties.getExpireTimes()).thenReturn(Duration.ofMinutes(5));
|
||||
when(smsCodeProperties.getSendFrequency()).thenReturn(Duration.ofMinutes(1));
|
||||
when(smsCodeProperties.getSendMaximumQuantityPerDay()).thenReturn(10);
|
||||
when(smsCodeProperties.getBeginCode()).thenReturn(9999);
|
||||
when(smsCodeProperties.getEndCode()).thenReturn(9999);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sendSmsCode_success() {
|
||||
// 准备参数
|
||||
SmsCodeSendReqDTO reqDTO = randomPojo(SmsCodeSendReqDTO.class, o -> {
|
||||
o.setMobile("15601691300");
|
||||
o.setScene(SmsSceneEnum.MEMBER_LOGIN.getScene());
|
||||
});
|
||||
// mock 方法
|
||||
SqlConstants.init(DbType.MYSQL);
|
||||
|
||||
// 调用
|
||||
smsCodeService.sendSmsCode(reqDTO);
|
||||
// 断言 code 验证码
|
||||
SmsCodeDO smsCodeDO = smsCodeMapper.selectOne(null);
|
||||
assertPojoEquals(reqDTO, smsCodeDO);
|
||||
assertEquals("9999", smsCodeDO.getCode());
|
||||
assertEquals(1, smsCodeDO.getTodayIndex());
|
||||
assertFalse(smsCodeDO.getUsed());
|
||||
// 断言调用
|
||||
verify(smsSendService).sendSingleSms(eq(reqDTO.getMobile()), isNull(), isNull(),
|
||||
eq("user-sms-login"), eq(MapUtil.of("code", "9999")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sendSmsCode_tooFast() {
|
||||
// mock 数据
|
||||
SmsCodeDO smsCodeDO = randomPojo(SmsCodeDO.class,
|
||||
o -> o.setMobile("15601691300").setTodayIndex(1));
|
||||
smsCodeMapper.insert(smsCodeDO);
|
||||
// 准备参数
|
||||
SmsCodeSendReqDTO reqDTO = randomPojo(SmsCodeSendReqDTO.class, o -> {
|
||||
o.setMobile("15601691300");
|
||||
o.setScene(SmsSceneEnum.MEMBER_LOGIN.getScene());
|
||||
});
|
||||
// mock 方法
|
||||
SqlConstants.init(DbType.MYSQL);
|
||||
|
||||
// 调用,并断言异常
|
||||
assertServiceException(() -> smsCodeService.sendSmsCode(reqDTO),
|
||||
SMS_CODE_SEND_TOO_FAST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sendSmsCode_exceedDay() {
|
||||
// mock 数据
|
||||
SmsCodeDO smsCodeDO = randomPojo(SmsCodeDO.class,
|
||||
o -> o.setMobile("15601691300").setTodayIndex(10).setCreateTime(LocalDateTime.now()));
|
||||
smsCodeMapper.insert(smsCodeDO);
|
||||
// 准备参数
|
||||
SmsCodeSendReqDTO reqDTO = randomPojo(SmsCodeSendReqDTO.class, o -> {
|
||||
o.setMobile("15601691300");
|
||||
o.setScene(SmsSceneEnum.MEMBER_LOGIN.getScene());
|
||||
});
|
||||
// mock 方法
|
||||
SqlConstants.init(DbType.MYSQL);
|
||||
when(smsCodeProperties.getSendFrequency()).thenReturn(Duration.ofMillis(0));
|
||||
|
||||
// 调用,并断言异常
|
||||
assertServiceException(() -> smsCodeService.sendSmsCode(reqDTO),
|
||||
SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUseSmsCode_success() {
|
||||
// 准备参数
|
||||
SmsCodeUseReqDTO reqDTO = randomPojo(SmsCodeUseReqDTO.class, o -> {
|
||||
o.setMobile("15601691300");
|
||||
o.setScene(randomEle(SmsSceneEnum.values()).getScene());
|
||||
});
|
||||
// mock 数据
|
||||
SqlConstants.init(DbType.MYSQL);
|
||||
smsCodeMapper.insert(randomPojo(SmsCodeDO.class, o -> {
|
||||
o.setMobile(reqDTO.getMobile()).setScene(reqDTO.getScene())
|
||||
.setCode(reqDTO.getCode()).setUsed(false);
|
||||
}));
|
||||
|
||||
// 调用
|
||||
smsCodeService.useSmsCode(reqDTO);
|
||||
// 断言
|
||||
SmsCodeDO smsCodeDO = smsCodeMapper.selectOne(null);
|
||||
assertTrue(smsCodeDO.getUsed());
|
||||
assertNotNull(smsCodeDO.getUsedTime());
|
||||
assertEquals(reqDTO.getUsedIp(), smsCodeDO.getUsedIp());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateSmsCode_success() {
|
||||
// 准备参数
|
||||
SmsCodeValidateReqDTO reqDTO = randomPojo(SmsCodeValidateReqDTO.class, o -> {
|
||||
o.setMobile("15601691300");
|
||||
o.setScene(randomEle(SmsSceneEnum.values()).getScene());
|
||||
});
|
||||
// mock 数据
|
||||
SqlConstants.init(DbType.MYSQL);
|
||||
smsCodeMapper.insert(randomPojo(SmsCodeDO.class, o -> o.setMobile(reqDTO.getMobile())
|
||||
.setScene(reqDTO.getScene()).setCode(reqDTO.getCode()).setUsed(false)));
|
||||
|
||||
// 调用
|
||||
smsCodeService.validateSmsCode(reqDTO);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateSmsCode_notFound() {
|
||||
// 准备参数
|
||||
SmsCodeValidateReqDTO reqDTO = randomPojo(SmsCodeValidateReqDTO.class, o -> {
|
||||
o.setMobile("15601691300");
|
||||
o.setScene(randomEle(SmsSceneEnum.values()).getScene());
|
||||
});
|
||||
// mock 数据
|
||||
SqlConstants.init(DbType.MYSQL);
|
||||
|
||||
// 调用,并断言异常
|
||||
assertServiceException(() -> smsCodeService.validateSmsCode(reqDTO),
|
||||
SMS_CODE_NOT_FOUND);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateSmsCode_expired() {
|
||||
// 准备参数
|
||||
SmsCodeValidateReqDTO reqDTO = randomPojo(SmsCodeValidateReqDTO.class, o -> {
|
||||
o.setMobile("15601691300");
|
||||
o.setScene(randomEle(SmsSceneEnum.values()).getScene());
|
||||
});
|
||||
// mock 数据
|
||||
SqlConstants.init(DbType.MYSQL);
|
||||
smsCodeMapper.insert(randomPojo(SmsCodeDO.class, o -> o.setMobile(reqDTO.getMobile())
|
||||
.setScene(reqDTO.getScene()).setCode(reqDTO.getCode()).setUsed(false)
|
||||
.setCreateTime(LocalDateTime.now().minusMinutes(6))));
|
||||
|
||||
// 调用,并断言异常
|
||||
assertServiceException(() -> smsCodeService.validateSmsCode(reqDTO),
|
||||
SMS_CODE_EXPIRED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateSmsCode_used() {
|
||||
// 准备参数
|
||||
SmsCodeValidateReqDTO reqDTO = randomPojo(SmsCodeValidateReqDTO.class, o -> {
|
||||
o.setMobile("15601691300");
|
||||
o.setScene(randomEle(SmsSceneEnum.values()).getScene());
|
||||
});
|
||||
// mock 数据
|
||||
SqlConstants.init(DbType.MYSQL);
|
||||
smsCodeMapper.insert(randomPojo(SmsCodeDO.class, o -> o.setMobile(reqDTO.getMobile())
|
||||
.setScene(reqDTO.getScene()).setCode(reqDTO.getCode()).setUsed(true)
|
||||
.setCreateTime(LocalDateTime.now())));
|
||||
|
||||
// 调用,并断言异常
|
||||
assertServiceException(() -> smsCodeService.validateSmsCode(reqDTO),
|
||||
SMS_CODE_USED);
|
||||
}
|
||||
|
||||
}
|
@ -34,7 +34,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
@Import(SmsLogServiceImpl.class)
|
||||
public class SmsLogServiceTest extends BaseDbUnitTest {
|
||||
public class SmsLogServiceImplTest extends BaseDbUnitTest {
|
||||
|
||||
@Resource
|
||||
private SmsLogServiceImpl smsLogService;
|
||||
@ -44,47 +44,47 @@ public class SmsLogServiceTest extends BaseDbUnitTest {
|
||||
|
||||
@Test
|
||||
public void testGetSmsLogPage() {
|
||||
// mock 数据
|
||||
SmsLogDO dbSmsLog = randomSmsLogDO(o -> { // 等会查询到
|
||||
o.setChannelId(1L);
|
||||
o.setTemplateId(10L);
|
||||
o.setMobile("15601691300");
|
||||
o.setSendStatus(SmsSendStatusEnum.INIT.getStatus());
|
||||
o.setSendTime(buildTime(2020, 11, 11));
|
||||
o.setReceiveStatus(SmsReceiveStatusEnum.INIT.getStatus());
|
||||
o.setReceiveTime(buildTime(2021, 11, 11));
|
||||
});
|
||||
smsLogMapper.insert(dbSmsLog);
|
||||
// 测试 channelId 不匹配
|
||||
smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setChannelId(2L)));
|
||||
// 测试 templateId 不匹配
|
||||
smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setTemplateId(20L)));
|
||||
// 测试 mobile 不匹配
|
||||
smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setMobile("18818260999")));
|
||||
// 测试 sendStatus 不匹配
|
||||
smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setSendStatus(SmsSendStatusEnum.IGNORE.getStatus())));
|
||||
// 测试 sendTime 不匹配
|
||||
smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setSendTime(buildTime(2020, 12, 12))));
|
||||
// 测试 receiveStatus 不匹配
|
||||
smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setReceiveStatus(SmsReceiveStatusEnum.SUCCESS.getStatus())));
|
||||
// 测试 receiveTime 不匹配
|
||||
smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setReceiveTime(buildTime(2021, 12, 12))));
|
||||
// 准备参数
|
||||
SmsLogPageReqVO reqVO = new SmsLogPageReqVO();
|
||||
reqVO.setChannelId(1L);
|
||||
reqVO.setTemplateId(10L);
|
||||
reqVO.setMobile("156");
|
||||
reqVO.setSendStatus(SmsSendStatusEnum.INIT.getStatus());
|
||||
reqVO.setSendTime(buildBetweenTime(2020, 11, 1, 2020, 11, 30));
|
||||
reqVO.setReceiveStatus(SmsReceiveStatusEnum.INIT.getStatus());
|
||||
reqVO.setReceiveTime(buildBetweenTime(2021, 11, 1, 2021, 11, 30));
|
||||
// mock 数据
|
||||
SmsLogDO dbSmsLog = randomSmsLogDO(o -> { // 等会查询到
|
||||
o.setChannelId(1L);
|
||||
o.setTemplateId(10L);
|
||||
o.setMobile("15601691300");
|
||||
o.setSendStatus(SmsSendStatusEnum.INIT.getStatus());
|
||||
o.setSendTime(buildTime(2020, 11, 11));
|
||||
o.setReceiveStatus(SmsReceiveStatusEnum.INIT.getStatus());
|
||||
o.setReceiveTime(buildTime(2021, 11, 11));
|
||||
});
|
||||
smsLogMapper.insert(dbSmsLog);
|
||||
// 测试 channelId 不匹配
|
||||
smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setChannelId(2L)));
|
||||
// 测试 templateId 不匹配
|
||||
smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setTemplateId(20L)));
|
||||
// 测试 mobile 不匹配
|
||||
smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setMobile("18818260999")));
|
||||
// 测试 sendStatus 不匹配
|
||||
smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setSendStatus(SmsSendStatusEnum.IGNORE.getStatus())));
|
||||
// 测试 sendTime 不匹配
|
||||
smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setSendTime(buildTime(2020, 12, 12))));
|
||||
// 测试 receiveStatus 不匹配
|
||||
smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setReceiveStatus(SmsReceiveStatusEnum.SUCCESS.getStatus())));
|
||||
// 测试 receiveTime 不匹配
|
||||
smsLogMapper.insert(cloneIgnoreId(dbSmsLog, o -> o.setReceiveTime(buildTime(2021, 12, 12))));
|
||||
// 准备参数
|
||||
SmsLogPageReqVO reqVO = new SmsLogPageReqVO();
|
||||
reqVO.setChannelId(1L);
|
||||
reqVO.setTemplateId(10L);
|
||||
reqVO.setMobile("156");
|
||||
reqVO.setSendStatus(SmsSendStatusEnum.INIT.getStatus());
|
||||
reqVO.setSendTime(buildBetweenTime(2020, 11, 1, 2020, 11, 30));
|
||||
reqVO.setReceiveStatus(SmsReceiveStatusEnum.INIT.getStatus());
|
||||
reqVO.setReceiveTime(buildBetweenTime(2021, 11, 1, 2021, 11, 30));
|
||||
|
||||
// 调用
|
||||
PageResult<SmsLogDO> pageResult = smsLogService.getSmsLogPage(reqVO);
|
||||
// 断言
|
||||
assertEquals(1, pageResult.getTotal());
|
||||
assertEquals(1, pageResult.getList().size());
|
||||
assertPojoEquals(dbSmsLog, pageResult.getList().get(0));
|
||||
// 调用
|
||||
PageResult<SmsLogDO> pageResult = smsLogService.getSmsLogPage(reqVO);
|
||||
// 断言
|
||||
assertEquals(1, pageResult.getTotal());
|
||||
assertEquals(1, pageResult.getList().size());
|
||||
assertPojoEquals(dbSmsLog, pageResult.getList().get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -124,11 +124,11 @@ public class SmsLogServiceTest extends BaseDbUnitTest {
|
||||
reqVO.setReceiveStatus(SmsReceiveStatusEnum.INIT.getStatus());
|
||||
reqVO.setReceiveTime(buildBetweenTime(2021, 11, 1, 2021, 11, 30));
|
||||
|
||||
// 调用
|
||||
List<SmsLogDO> list = smsLogService.getSmsLogList(reqVO);
|
||||
// 断言
|
||||
assertEquals(1, list.size());
|
||||
assertPojoEquals(dbSmsLog, list.get(0));
|
||||
// 调用
|
||||
List<SmsLogDO> list = smsLogService.getSmsLogList(reqVO);
|
||||
// 断言
|
||||
assertEquals(1, list.size());
|
||||
assertPojoEquals(dbSmsLog, list.get(0));
|
||||
}
|
||||
|
||||
@Test
|
@ -1,288 +0,0 @@
|
||||
package cn.iocoder.yudao.module.system.service.sms;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.iocoder.yudao.framework.common.core.KeyValue;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
|
||||
import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory;
|
||||
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
|
||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
|
||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
|
||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
|
||||
import cn.iocoder.yudao.module.system.mq.message.sms.SmsSendMessage;
|
||||
import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer;
|
||||
import cn.iocoder.yudao.module.system.service.member.MemberService;
|
||||
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
|
||||
import org.assertj.core.util.Lists;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.hutool.core.util.RandomUtil.randomEle;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
|
||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
public class SmsSendServiceTest extends BaseMockitoUnitTest {
|
||||
|
||||
@InjectMocks
|
||||
private SmsSendServiceImpl smsService;
|
||||
|
||||
@Mock
|
||||
private AdminUserService adminUserService;
|
||||
@Mock
|
||||
private MemberService memberService;
|
||||
@Mock
|
||||
private SmsChannelService smsChannelService;
|
||||
@Mock
|
||||
private SmsTemplateService smsTemplateService;
|
||||
@Mock
|
||||
private SmsLogService smsLogService;
|
||||
@Mock
|
||||
private SmsProducer smsProducer;
|
||||
|
||||
@Mock
|
||||
private SmsClientFactory smsClientFactory;
|
||||
|
||||
@Test
|
||||
public void testSendSingleSmsToAdmin() {
|
||||
// 准备参数
|
||||
Long userId = randomLongId();
|
||||
String templateCode = randomString();
|
||||
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
|
||||
.put("op", "login").build();
|
||||
// mock adminUserService 的方法
|
||||
AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setMobile("15601691300"));
|
||||
when(adminUserService.getUser(eq(userId))).thenReturn(user);
|
||||
|
||||
// mock SmsTemplateService 的方法
|
||||
SmsTemplateDO template = randomPojo(SmsTemplateDO.class, o -> {
|
||||
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
o.setContent("验证码为{code}, 操作为{op}");
|
||||
o.setParams(Lists.newArrayList("code", "op"));
|
||||
});
|
||||
when(smsTemplateService.getSmsTemplateByCodeFromCache(eq(templateCode))).thenReturn(template);
|
||||
String content = randomString();
|
||||
when(smsTemplateService.formatSmsTemplateContent(eq(template.getContent()), eq(templateParams)))
|
||||
.thenReturn(content);
|
||||
// mock SmsChannelService 的方法
|
||||
SmsChannelDO smsChannel = randomPojo(SmsChannelDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()));
|
||||
when(smsChannelService.getSmsChannel(eq(template.getChannelId()))).thenReturn(smsChannel);
|
||||
// mock SmsLogService 的方法
|
||||
Long smsLogId = randomLongId();
|
||||
when(smsLogService.createSmsLog(eq(user.getMobile()), eq(userId), eq(UserTypeEnum.ADMIN.getValue()), eq(Boolean.TRUE), eq(template),
|
||||
eq(content), eq(templateParams))).thenReturn(smsLogId);
|
||||
|
||||
// 调用
|
||||
Long resultSmsLogId = smsService.sendSingleSmsToAdmin(null, userId, templateCode, templateParams);
|
||||
// 断言
|
||||
assertEquals(smsLogId, resultSmsLogId);
|
||||
// 断言调用
|
||||
verify(smsProducer).sendSmsSendMessage(eq(smsLogId), eq(user.getMobile()),
|
||||
eq(template.getChannelId()), eq(template.getApiTemplateId()),
|
||||
eq(Lists.newArrayList(new KeyValue<>("code", "1234"), new KeyValue<>("op", "login"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendSingleSmsToUser() {
|
||||
// 准备参数
|
||||
Long userId = randomLongId();
|
||||
String templateCode = randomString();
|
||||
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
|
||||
.put("op", "login").build();
|
||||
// mock adminUserService 的方法
|
||||
String mobile = "15601691300";
|
||||
when(memberService.getMemberUserMobile(eq(userId))).thenReturn(mobile);
|
||||
|
||||
// mock SmsTemplateService 的方法
|
||||
SmsTemplateDO template = randomPojo(SmsTemplateDO.class, o -> {
|
||||
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
o.setContent("验证码为{code}, 操作为{op}");
|
||||
o.setParams(Lists.newArrayList("code", "op"));
|
||||
});
|
||||
when(smsTemplateService.getSmsTemplateByCodeFromCache(eq(templateCode))).thenReturn(template);
|
||||
String content = randomString();
|
||||
when(smsTemplateService.formatSmsTemplateContent(eq(template.getContent()), eq(templateParams)))
|
||||
.thenReturn(content);
|
||||
// mock SmsChannelService 的方法
|
||||
SmsChannelDO smsChannel = randomPojo(SmsChannelDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()));
|
||||
when(smsChannelService.getSmsChannel(eq(template.getChannelId()))).thenReturn(smsChannel);
|
||||
// mock SmsLogService 的方法
|
||||
Long smsLogId = randomLongId();
|
||||
when(smsLogService.createSmsLog(eq(mobile), eq(userId), eq(UserTypeEnum.MEMBER.getValue()), eq(Boolean.TRUE), eq(template),
|
||||
eq(content), eq(templateParams))).thenReturn(smsLogId);
|
||||
|
||||
// 调用
|
||||
Long resultSmsLogId = smsService.sendSingleSmsToMember(null, userId, templateCode, templateParams);
|
||||
// 断言
|
||||
assertEquals(smsLogId, resultSmsLogId);
|
||||
// 断言调用
|
||||
verify(smsProducer).sendSmsSendMessage(eq(smsLogId), eq(mobile),
|
||||
eq(template.getChannelId()), eq(template.getApiTemplateId()),
|
||||
eq(Lists.newArrayList(new KeyValue<>("code", "1234"), new KeyValue<>("op", "login"))));
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送成功,当短信模板开启时
|
||||
*/
|
||||
@Test
|
||||
public void testSendSingleSms_successWhenSmsTemplateEnable() {
|
||||
// 准备参数
|
||||
String mobile = randomString();
|
||||
Long userId = randomLongId();
|
||||
Integer userType = randomEle(UserTypeEnum.values()).getValue();
|
||||
String templateCode = randomString();
|
||||
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
|
||||
.put("op", "login").build();
|
||||
// mock SmsTemplateService 的方法
|
||||
SmsTemplateDO template = randomPojo(SmsTemplateDO.class, o -> {
|
||||
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
o.setContent("验证码为{code}, 操作为{op}");
|
||||
o.setParams(Lists.newArrayList("code", "op"));
|
||||
});
|
||||
when(smsTemplateService.getSmsTemplateByCodeFromCache(eq(templateCode))).thenReturn(template);
|
||||
String content = randomString();
|
||||
when(smsTemplateService.formatSmsTemplateContent(eq(template.getContent()), eq(templateParams)))
|
||||
.thenReturn(content);
|
||||
// mock SmsChannelService 的方法
|
||||
SmsChannelDO smsChannel = randomPojo(SmsChannelDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()));
|
||||
when(smsChannelService.getSmsChannel(eq(template.getChannelId()))).thenReturn(smsChannel);
|
||||
// mock SmsLogService 的方法
|
||||
Long smsLogId = randomLongId();
|
||||
when(smsLogService.createSmsLog(eq(mobile), eq(userId), eq(userType), eq(Boolean.TRUE), eq(template),
|
||||
eq(content), eq(templateParams))).thenReturn(smsLogId);
|
||||
|
||||
// 调用
|
||||
Long resultSmsLogId = smsService.sendSingleSms(mobile, userId, userType, templateCode, templateParams);
|
||||
// 断言
|
||||
assertEquals(smsLogId, resultSmsLogId);
|
||||
// 断言调用
|
||||
verify(smsProducer).sendSmsSendMessage(eq(smsLogId), eq(mobile),
|
||||
eq(template.getChannelId()), eq(template.getApiTemplateId()),
|
||||
eq(Lists.newArrayList(new KeyValue<>("code", "1234"), new KeyValue<>("op", "login"))));
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送成功,当短信模板关闭时
|
||||
*/
|
||||
@Test
|
||||
public void testSendSingleSms_successWhenSmsTemplateDisable() {
|
||||
// 准备参数
|
||||
String mobile = randomString();
|
||||
Long userId = randomLongId();
|
||||
Integer userType = randomEle(UserTypeEnum.values()).getValue();
|
||||
String templateCode = randomString();
|
||||
Map<String, Object> templateParams = MapUtil.<String, Object>builder().put("code", "1234")
|
||||
.put("op", "login").build();
|
||||
// mock SmsTemplateService 的方法
|
||||
SmsTemplateDO template = randomPojo(SmsTemplateDO.class, o -> {
|
||||
o.setStatus(CommonStatusEnum.DISABLE.getStatus());
|
||||
o.setContent("验证码为{code}, 操作为{op}");
|
||||
o.setParams(Lists.newArrayList("code", "op"));
|
||||
});
|
||||
when(smsTemplateService.getSmsTemplateByCodeFromCache(eq(templateCode))).thenReturn(template);
|
||||
String content = randomString();
|
||||
when(smsTemplateService.formatSmsTemplateContent(eq(template.getContent()), eq(templateParams)))
|
||||
.thenReturn(content);
|
||||
// mock SmsChannelService 的方法
|
||||
SmsChannelDO smsChannel = randomPojo(SmsChannelDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()));
|
||||
when(smsChannelService.getSmsChannel(eq(template.getChannelId()))).thenReturn(smsChannel);
|
||||
// mock SmsLogService 的方法
|
||||
Long smsLogId = randomLongId();
|
||||
when(smsLogService.createSmsLog(eq(mobile), eq(userId), eq(userType), eq(Boolean.FALSE), eq(template),
|
||||
eq(content), eq(templateParams))).thenReturn(smsLogId);
|
||||
|
||||
// 调用
|
||||
Long resultSmsLogId = smsService.sendSingleSms(mobile, userId, userType, templateCode, templateParams);
|
||||
// 断言
|
||||
assertEquals(smsLogId, resultSmsLogId);
|
||||
// 断言调用
|
||||
verify(smsProducer, times(0)).sendSmsSendMessage(anyLong(), anyString(),
|
||||
anyLong(), any(), anyList());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckSmsTemplateValid_notExists() {
|
||||
// 准备参数
|
||||
String templateCode = randomString();
|
||||
// mock 方法
|
||||
|
||||
// 调用,并断言异常
|
||||
assertServiceException(() -> smsService.validateSmsTemplate(templateCode),
|
||||
SMS_SEND_TEMPLATE_NOT_EXISTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildTemplateParams_paramMiss() {
|
||||
// 准备参数
|
||||
SmsTemplateDO template = randomPojo(SmsTemplateDO.class,
|
||||
o -> o.setParams(Lists.newArrayList("code")));
|
||||
Map<String, Object> templateParams = new HashMap<>();
|
||||
// mock 方法
|
||||
|
||||
// 调用,并断言异常
|
||||
assertServiceException(() -> smsService.buildTemplateParams(template, templateParams),
|
||||
SMS_SEND_MOBILE_TEMPLATE_PARAM_MISS, "code");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckMobile_notExists() {
|
||||
// 准备参数
|
||||
// mock 方法
|
||||
|
||||
// 调用,并断言异常
|
||||
assertServiceException(() -> smsService.validateMobile(null),
|
||||
SMS_SEND_MOBILE_NOT_EXISTS);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testDoSendSms() {
|
||||
// 准备参数
|
||||
SmsSendMessage message = randomPojo(SmsSendMessage.class);
|
||||
// mock SmsClientFactory 的方法
|
||||
SmsClient smsClient = spy(SmsClient.class);
|
||||
when(smsClientFactory.getSmsClient(eq(message.getChannelId()))).thenReturn(smsClient);
|
||||
// mock SmsClient 的方法
|
||||
SmsCommonResult<SmsSendRespDTO> sendResult = randomPojo(SmsCommonResult.class, SmsSendRespDTO.class);
|
||||
when(smsClient.sendSms(eq(message.getLogId()), eq(message.getMobile()), eq(message.getApiTemplateId()),
|
||||
eq(message.getTemplateParams()))).thenReturn(sendResult);
|
||||
|
||||
// 调用
|
||||
smsService.doSendSms(message);
|
||||
// 断言
|
||||
verify(smsLogService).updateSmsSendResult(eq(message.getLogId()),
|
||||
eq(sendResult.getCode()), eq(sendResult.getMsg()), eq(sendResult.getApiCode()),
|
||||
eq(sendResult.getApiMsg()), eq(sendResult.getApiRequestId()), eq(sendResult.getData().getSerialNo()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReceiveSmsStatus() throws Throwable {
|
||||
// 准备参数
|
||||
String channelCode = randomString();
|
||||
String text = randomString();
|
||||
// mock SmsClientFactory 的方法
|
||||
SmsClient smsClient = spy(SmsClient.class);
|
||||
when(smsClientFactory.getSmsClient(eq(channelCode))).thenReturn(smsClient);
|
||||
// mock SmsClient 的方法
|
||||
List<SmsReceiveRespDTO> receiveResults = randomPojoList(SmsReceiveRespDTO.class);
|
||||
|
||||
// 调用
|
||||
smsService.receiveSmsStatus(channelCode, text);
|
||||
// 断言
|
||||
receiveResults.forEach(result -> smsLogService.updateSmsReceiveResult(eq(result.getLogId()), eq(result.getSuccess()),
|
||||
eq(result.getReceiveTime()), eq(result.getErrorCode()), eq(result.getErrorCode())));
|
||||
}
|
||||
|
||||
}
|
@ -1,14 +1,5 @@
|
||||
package cn.iocoder.yudao.module.system.service.sms;
|
||||
|
||||
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateCreateReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateExportReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsTemplateMapper;
|
||||
import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer;
|
||||
import cn.iocoder.yudao.module.system.enums.sms.SmsTemplateTypeEnum;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
@ -19,6 +10,15 @@ import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory;
|
||||
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
|
||||
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
|
||||
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateCreateReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateExportReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplatePageReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.sms.vo.template.SmsTemplateUpdateReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsChannelDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsTemplateDO;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.sms.SmsTemplateMapper;
|
||||
import cn.iocoder.yudao.module.system.enums.sms.SmsTemplateTypeEnum;
|
||||
import cn.iocoder.yudao.module.system.mq.producer.sms.SmsProducer;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
@ -30,20 +30,18 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static cn.hutool.core.bean.BeanUtil.getFieldValue;
|
||||
import static cn.hutool.core.util.RandomUtil.randomEle;
|
||||
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.max;
|
||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
|
||||
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
|
||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
|
||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@Import(SmsTemplateServiceImpl.class)
|
||||
public class SmsTemplateServiceTest extends BaseDbUnitTest {
|
||||
public class SmsTemplateServiceImplTest extends BaseDbUnitTest {
|
||||
|
||||
@Resource
|
||||
private SmsTemplateServiceImpl smsTemplateService;
|
||||
@ -176,8 +174,8 @@ public class SmsTemplateServiceTest extends BaseDbUnitTest {
|
||||
|
||||
// 调用
|
||||
smsTemplateService.deleteSmsTemplate(id);
|
||||
// 校验数据不存在了
|
||||
assertNull(smsTemplateMapper.selectById(id));
|
||||
// 校验数据不存在了
|
||||
assertNull(smsTemplateMapper.selectById(id));
|
||||
// 校验调用
|
||||
verify(smsProducer, times(1)).sendSmsTemplateRefreshMessage();
|
||||
}
|
||||
@ -193,47 +191,47 @@ public class SmsTemplateServiceTest extends BaseDbUnitTest {
|
||||
|
||||
@Test
|
||||
public void testGetSmsTemplatePage() {
|
||||
// mock 数据
|
||||
SmsTemplateDO dbSmsTemplate = randomPojo(SmsTemplateDO.class, o -> { // 等会查询到
|
||||
o.setType(SmsTemplateTypeEnum.PROMOTION.getType());
|
||||
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
o.setCode("tudou");
|
||||
o.setContent("芋道源码");
|
||||
o.setApiTemplateId("yunai");
|
||||
o.setChannelId(1L);
|
||||
o.setCreateTime(buildTime(2021, 11, 11));
|
||||
});
|
||||
smsTemplateMapper.insert(dbSmsTemplate);
|
||||
// 测试 type 不匹配
|
||||
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setType(SmsTemplateTypeEnum.VERIFICATION_CODE.getType())));
|
||||
// 测试 status 不匹配
|
||||
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
|
||||
// 测试 code 不匹配
|
||||
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCode("yuanma")));
|
||||
// 测试 content 不匹配
|
||||
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setContent("源码")));
|
||||
// 测试 apiTemplateId 不匹配
|
||||
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setApiTemplateId("nai")));
|
||||
// 测试 channelId 不匹配
|
||||
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setChannelId(2L)));
|
||||
// 测试 createTime 不匹配
|
||||
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCreateTime(buildTime(2021, 12, 12))));
|
||||
// 准备参数
|
||||
SmsTemplatePageReqVO reqVO = new SmsTemplatePageReqVO();
|
||||
reqVO.setType(SmsTemplateTypeEnum.PROMOTION.getType());
|
||||
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
reqVO.setCode("tu");
|
||||
reqVO.setContent("芋道");
|
||||
reqVO.setApiTemplateId("yu");
|
||||
reqVO.setChannelId(1L);
|
||||
reqVO.setCreateTime((new LocalDateTime[]{buildTime(2021, 11, 1),buildTime(2021, 12, 1)}));
|
||||
// mock 数据
|
||||
SmsTemplateDO dbSmsTemplate = randomPojo(SmsTemplateDO.class, o -> { // 等会查询到
|
||||
o.setType(SmsTemplateTypeEnum.PROMOTION.getType());
|
||||
o.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
o.setCode("tudou");
|
||||
o.setContent("芋道源码");
|
||||
o.setApiTemplateId("yunai");
|
||||
o.setChannelId(1L);
|
||||
o.setCreateTime(buildTime(2021, 11, 11));
|
||||
});
|
||||
smsTemplateMapper.insert(dbSmsTemplate);
|
||||
// 测试 type 不匹配
|
||||
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setType(SmsTemplateTypeEnum.VERIFICATION_CODE.getType())));
|
||||
// 测试 status 不匹配
|
||||
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
|
||||
// 测试 code 不匹配
|
||||
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCode("yuanma")));
|
||||
// 测试 content 不匹配
|
||||
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setContent("源码")));
|
||||
// 测试 apiTemplateId 不匹配
|
||||
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setApiTemplateId("nai")));
|
||||
// 测试 channelId 不匹配
|
||||
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setChannelId(2L)));
|
||||
// 测试 createTime 不匹配
|
||||
smsTemplateMapper.insert(ObjectUtils.cloneIgnoreId(dbSmsTemplate, o -> o.setCreateTime(buildTime(2021, 12, 12))));
|
||||
// 准备参数
|
||||
SmsTemplatePageReqVO reqVO = new SmsTemplatePageReqVO();
|
||||
reqVO.setType(SmsTemplateTypeEnum.PROMOTION.getType());
|
||||
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
reqVO.setCode("tu");
|
||||
reqVO.setContent("芋道");
|
||||
reqVO.setApiTemplateId("yu");
|
||||
reqVO.setChannelId(1L);
|
||||
reqVO.setCreateTime((new LocalDateTime[]{buildTime(2021, 11, 1),buildTime(2021, 12, 1)}));
|
||||
|
||||
// 调用
|
||||
PageResult<SmsTemplateDO> pageResult = smsTemplateService.getSmsTemplatePage(reqVO);
|
||||
// 断言
|
||||
assertEquals(1, pageResult.getTotal());
|
||||
assertEquals(1, pageResult.getList().size());
|
||||
assertPojoEquals(dbSmsTemplate, pageResult.getList().get(0));
|
||||
// 调用
|
||||
PageResult<SmsTemplateDO> pageResult = smsTemplateService.getSmsTemplatePage(reqVO);
|
||||
// 断言
|
||||
assertEquals(1, pageResult.getTotal());
|
||||
assertEquals(1, pageResult.getList().size());
|
||||
assertPojoEquals(dbSmsTemplate, pageResult.getList().get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -273,11 +271,11 @@ public class SmsTemplateServiceTest extends BaseDbUnitTest {
|
||||
reqVO.setChannelId(1L);
|
||||
reqVO.setCreateTime((new LocalDateTime[]{buildTime(2021, 11, 1),buildTime(2021, 12, 1)}));
|
||||
|
||||
// 调用
|
||||
List<SmsTemplateDO> list = smsTemplateService.getSmsTemplateList(reqVO);
|
||||
// 断言
|
||||
assertEquals(1, list.size());
|
||||
assertPojoEquals(dbSmsTemplate, list.get(0));
|
||||
// 调用
|
||||
List<SmsTemplateDO> list = smsTemplateService.getSmsTemplateList(reqVO);
|
||||
// 断言
|
||||
assertEquals(1, list.size());
|
||||
assertPojoEquals(dbSmsTemplate, list.get(0));
|
||||
}
|
||||
|
||||
@Test
|
@ -14,6 +14,7 @@ DELETE FROM "system_users";
|
||||
DELETE FROM "system_sms_channel";
|
||||
DELETE FROM "system_sms_template";
|
||||
DELETE FROM "system_sms_log";
|
||||
DELETE FROM "system_sms_code";
|
||||
DELETE FROM "system_error_code";
|
||||
DELETE FROM "system_social_user";
|
||||
DELETE FROM "system_social_user_bind";
|
||||
|
@ -377,6 +377,24 @@ CREATE TABLE IF NOT EXISTS "system_sms_log" (
|
||||
PRIMARY KEY ("id")
|
||||
) COMMENT '短信日志';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "system_sms_code" (
|
||||
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
|
||||
"mobile" varchar(11) NOT NULL,
|
||||
"code" varchar(11) NOT NULL,
|
||||
"scene" bigint NOT NULL,
|
||||
"create_ip" varchar NOT NULL,
|
||||
"today_index" int NOT NULL,
|
||||
"used" bit NOT NULL DEFAULT FALSE,
|
||||
"used_time" timestamp DEFAULT NULL,
|
||||
"used_ip" varchar NULL,
|
||||
"creator" varchar(64) DEFAULT '',
|
||||
"create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updater" varchar(64) DEFAULT '',
|
||||
"update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"deleted" bit NOT NULL DEFAULT FALSE,
|
||||
PRIMARY KEY ("id")
|
||||
) COMMENT '短信日志';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "system_error_code" (
|
||||
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
|
||||
"type" tinyint NOT NULL DEFAULT '0',
|
||||
@ -568,19 +586,19 @@ CREATE TABLE IF NOT EXISTS "system_oauth2_code" (
|
||||
) COMMENT 'OAuth2 刷新令牌';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "system_mail_account" (
|
||||
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
|
||||
"mail" varchar NOT NULL,
|
||||
"username" varchar NOT NULL,
|
||||
"password" varchar NOT NULL,
|
||||
"host" varchar NOT NULL,
|
||||
"port" int NOT NULL,
|
||||
"ssl_enable" bit NOT NULL,
|
||||
"creator" varchar DEFAULT '',
|
||||
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updater" varchar DEFAULT '',
|
||||
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
"deleted" bit NOT NULL DEFAULT FALSE,
|
||||
PRIMARY KEY ("id")
|
||||
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
|
||||
"mail" varchar NOT NULL,
|
||||
"username" varchar NOT NULL,
|
||||
"password" varchar NOT NULL,
|
||||
"host" varchar NOT NULL,
|
||||
"port" int NOT NULL,
|
||||
"ssl_enable" bit NOT NULL,
|
||||
"creator" varchar DEFAULT '',
|
||||
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updater" varchar DEFAULT '',
|
||||
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
"deleted" bit NOT NULL DEFAULT FALSE,
|
||||
PRIMARY KEY ("id")
|
||||
) COMMENT '邮箱账号表';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "system_mail_template" (
|
||||
@ -603,28 +621,28 @@ CREATE TABLE IF NOT EXISTS "system_mail_template" (
|
||||
) COMMENT '邮件模版表';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "system_mail_log" (
|
||||
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
|
||||
"user_id" bigint,
|
||||
"user_type" varchar,
|
||||
"to_mail" varchar NOT NULL,
|
||||
"account_id" bigint NOT NULL,
|
||||
"from_mail" varchar NOT NULL,
|
||||
"template_id" bigint NOT NULL,
|
||||
"template_code" varchar NOT NULL,
|
||||
"template_nickname" varchar,
|
||||
"template_title" varchar NOT NULL,
|
||||
"template_content" varchar NOT NULL,
|
||||
"template_params" varchar NOT NULL,
|
||||
"send_status" varchar NOT NULL,
|
||||
"send_time" datetime,
|
||||
"send_message_id" varchar,
|
||||
"send_exception" varchar,
|
||||
"creator" varchar DEFAULT '',
|
||||
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updater" varchar DEFAULT '',
|
||||
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
"deleted" bit NOT NULL DEFAULT FALSE,
|
||||
PRIMARY KEY ("id")
|
||||
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
|
||||
"user_id" bigint,
|
||||
"user_type" varchar,
|
||||
"to_mail" varchar NOT NULL,
|
||||
"account_id" bigint NOT NULL,
|
||||
"from_mail" varchar NOT NULL,
|
||||
"template_id" bigint NOT NULL,
|
||||
"template_code" varchar NOT NULL,
|
||||
"template_nickname" varchar,
|
||||
"template_title" varchar NOT NULL,
|
||||
"template_content" varchar NOT NULL,
|
||||
"template_params" varchar NOT NULL,
|
||||
"send_status" varchar NOT NULL,
|
||||
"send_time" datetime,
|
||||
"send_message_id" varchar,
|
||||
"send_exception" varchar,
|
||||
"creator" varchar DEFAULT '',
|
||||
"create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updater" varchar DEFAULT '',
|
||||
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
"deleted" bit NOT NULL DEFAULT FALSE,
|
||||
PRIMARY KEY ("id")
|
||||
) COMMENT '邮件日志表';
|
||||
|
||||
-- 将该建表 SQL 语句,添加到 yudao-module-system-biz 模块的 test/resources/sql/create_tables.sql 文件里
|
||||
|
Loading…
Reference in New Issue
Block a user