Browse Source

短信模板的创建 Test 单元测试

YunaiV 5 years ago
parent
commit
fbbcd2717a

File diff suppressed because it is too large
+ 177 - 15
sql/ruoyi-vue-pro.sql


+ 0 - 97
sql/sms.sql

@@ -1,109 +0,0 @@
-/*
-    --2021.02.01 by fight, sms about table info
-*/
-
-DROP TABLE IF EXISTS `sms_channel`;
-CREATE TABLE `sms_channel`
-(
-    `id`               bigint(20)   NOT NULL AUTO_INCREMENT COMMENT '自增编号',
-    `code`             varchar(50)  NOT NULL COMMENT '编码(来自枚举类 阿里、华为、七牛等)',
-    `api_key`          varchar(100) NOT NULL COMMENT '账号id',
-    `api_secret`       varchar(100) NOT NULL COMMENT '账号秘钥',
-    `callback_url`     varchar(100) NOT NULL default '' COMMENT '回调请求路径',
-    `api_signature_id` varchar(100) NOT NULL COMMENT '实际渠道签名唯一标识',
-    `name`             varchar(50)  NOT NULL COMMENT '名称',
-    `signature`        varchar(50)  NOT NULL COMMENT '签名值',
-    `remark`           varchar(200) NOT NULL COMMENT '备注',
-
-    `status`           tinyint(4)   NOT NULL DEFAULT 0 COMMENT '启用状态(0正常 1停用)',
-    `create_by`        varchar(64)  NOT NULL DEFAULT '' COMMENT '创建者',
-    `create_time`      datetime              DEFAULT NULL COMMENT '创建时间',
-    `update_by`        varchar(64)           DEFAULT '' COMMENT '更新者',
-    `update_time`      datetime              DEFAULT NULL COMMENT '更新时间',
-    `deleted`          bit(1)                DEFAULT b'0' COMMENT '是否删除',
-    PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB
-  AUTO_INCREMENT = 1
-  DEFAULT CHARSET = utf8mb4 COMMENT ='短信渠道';
-/*
-	优先级值一样时,按照id顺序取值
-*/
-
-DROP TABLE IF EXISTS `sms_template`;
-CREATE TABLE `sms_template`
-(
-    `id`              bigint(20)    NOT NULL AUTO_INCREMENT COMMENT '自增编号',
-    `channel_code`    varchar(50)   NOT NULL COMMENT '短信渠道编码(来自枚举类)',
-    `channel_id`      bigint(20)    NOT NULL COMMENT '短信渠道id (对于前端来说就是绑定一个签名)',
-    `type`            tinyint(4)    NOT NULL DEFAULT 1 COMMENT '消息类型 [0验证码 1短信通知 2推广短信 3国际/港澳台消息]',
-    `biz_code`        varchar(50)   NOT NULL COMMENT '业务编码(来自数据字典, 用户自定义业务场景 一个场景可以有多个模板)',
-    `code`            varchar(50)   NOT NULL COMMENT '编码',
-    `name`            varchar(50)   NOT NULL COMMENT '名称',
-    `api_template_id` varchar(100)  NOT NULL COMMENT '实际渠道模板唯一标识',
-    `content`         varchar(1000) NOT NULL DEFAULT '' COMMENT '内容',
-    `params`          varchar(200)  NOT NULL DEFAULT '' COMMENT '参数数组(自动根据内容生成)',
-    `remark`          varchar(200)  NOT NULL COMMENT '备注',
-
-    `status`          tinyint(4)    NOT NULL DEFAULT 0 COMMENT '启用状态(0正常 1停用)',
-    `create_by`       varchar(64)   NOT NULL DEFAULT '' COMMENT '创建者',
-    `create_time`     datetime               DEFAULT NULL COMMENT '创建时间',
-    `update_by`       varchar(64)            DEFAULT '' COMMENT '更新者',
-    `update_time`     datetime               DEFAULT NULL COMMENT '更新时间',
-    `deleted`         bit(1)                 DEFAULT b'0' COMMENT '是否删除',
-    PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB
-  AUTO_INCREMENT = 1
-  DEFAULT CHARSET = utf8mb4 COMMENT ='短信模板';
-/*
-DROP TABLE IF EXISTS `sms_query_log`;
-CREATE TABLE `sms_query_log`
-(
-    `id`                bigint(20)    NOT NULL AUTO_INCREMENT COMMENT '自增编号',
-    `api_id`            varchar(100)  NOT NULL COMMENT '第三方唯一标识',
-    `channel_code`      varchar(50)   NOT NULL COMMENT '短信渠道编码(来自枚举类)',
-    `channel_id`        bigint(20)    NOT NULL COMMENT '短信渠道id',
-    `template_code`     varchar(50)   NOT NULL COMMENT '渠道编码',
-    `phone`             char(11)      NOT NULL COMMENT '手机号',
-    `content`           varchar(1000) NOT NULL DEFAULT '' COMMENT '内容',
-    `send_result_param` varchar(200)  NOT NULL DEFAULT '' COMMENT '查询短信发送结果的参数',
-    `send_status`       tinyint(1)    NOT NULL DEFAULT 2 COMMENT '发送状态(0本地异步中 1发送请求失败 2发送请求成功)',
-    `got_result`        bit(1)        NOT NULL DEFAULT b'0' COMMENT '是否获取发送结果',
-    `had_callback`      bit(1)        NOT NULL DEFAULT b'0' COMMENT '是否拥有回调函数',
-    `create_by`         varchar(64)   NOT NULL DEFAULT '' COMMENT '创建者',
-    `create_time`       datetime               DEFAULT NULL COMMENT '创建时间',
-    PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB
-  AUTO_INCREMENT = 1
-  DEFAULT CHARSET = utf8mb4 COMMENT ='短信请求日志';*/
-
-DROP TABLE IF EXISTS `sms_query_log`;
-CREATE TABLE `sms_query_log`
-(
-    `id`            bigint(20)    NOT NULL AUTO_INCREMENT COMMENT '自增编号',
-    `api_id`        varchar(100)  NOT NULL COMMENT '第三方唯一标识',
-    `channel_code`  varchar(50)   NOT NULL COMMENT '短信渠道编码(来自枚举类)',
-    `channel_id`    bigint(20)    NOT NULL COMMENT '短信渠道id',
-    `template_code` varchar(50)   NOT NULL COMMENT '渠道编码',
-    `phone`         char(11)      NOT NULL COMMENT '手机号',
-    `content`       varchar(1000) NOT NULL DEFAULT '' COMMENT '内容',
-    `send_status`   tinyint(1)    NOT NULL DEFAULT 0 COMMENT '发送状态 详情见:SmsSendStatusEnum',
-    `remark`        varchar(200)           DEFAULT NULL COMMENT '备注',
-    `create_by`     varchar(64)   NOT NULL DEFAULT '' COMMENT '创建者',
-    `create_time`   datetime               DEFAULT NULL COMMENT '创建时间',
-    `send_time`     datetime               DEFAULT NULL COMMENT '发送时间',
-    PRIMARY KEY (`id`) USING BTREE
-) ENGINE = InnoDB
-  AUTO_INCREMENT = 1
-  DEFAULT CHARSET = utf8mb4 COMMENT ='短信发送日志';

+ 1 - 1
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/sms/SysSmsTemplateMapper.java

@@ -13,7 +13,7 @@ import java.util.List;
 @Mapper
 public interface SysSmsTemplateMapper extends BaseMapperX<SysSmsTemplateDO> {
 
-    default SysSmsTemplateDO selectOneByCode(String code) {
+    default SysSmsTemplateDO selectByCode(String code) {
         return selectOne("code", code);
     }
 

+ 2 - 0
src/main/java/cn/iocoder/dashboard/modules/system/enums/SysErrorCodeConstants.java

@@ -80,9 +80,11 @@ public interface SysErrorCodeConstants {
 
     // ========== 短信渠道 1002011000 ==========
     ErrorCode SMS_CHANNEL_NOT_EXISTS = new ErrorCode(1002011000, "短信渠道不存在");
+    ErrorCode SMS_CHANNEL_DISABLE = new ErrorCode(1002011001, "短信渠道不处于开启状态,不允许选择");
 
     // ========== 短信模板 1002011000 ==========
     ErrorCode SMS_TEMPLATE_NOT_EXISTS = new ErrorCode(1002011000, "短信模板不存在");
+    ErrorCode SMS_TEMPLATE_CODE_DUPLICATE = new ErrorCode(1002011001, "已经存在编码为【{}}】的短信模板");
 
     // ========== 短信发送 1002012000 ==========
     ErrorCode SMS_SEND_MOBILE_NOT_EXISTS = new ErrorCode(1002012000, "手机号不存在");

+ 57 - 5
src/main/java/cn/iocoder/dashboard/modules/system/service/sms/impl/SysSmsTemplateServiceImpl.java

@@ -1,24 +1,31 @@
 package cn.iocoder.dashboard.modules.system.service.sms.impl;
 
+import cn.hutool.core.util.ReUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
 import cn.iocoder.dashboard.common.pojo.PageResult;
 import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateCreateReqVO;
 import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateExportReqVO;
 import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplatePageReqVO;
 import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateUpdateReqVO;
 import cn.iocoder.dashboard.modules.system.convert.sms.SysSmsTemplateConvert;
+import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO;
 import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
 import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsTemplateMapper;
+import cn.iocoder.dashboard.modules.system.service.sms.SysSmsChannelService;
 import cn.iocoder.dashboard.modules.system.service.sms.SysSmsTemplateService;
+import com.google.common.annotations.VisibleForTesting;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+import java.util.regex.Pattern;
 
 import static cn.iocoder.dashboard.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.SMS_TEMPLATE_NOT_EXISTS;
+import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.*;
 
 /**
  * 短信模板Service实现类
@@ -29,12 +36,20 @@ import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.SM
 @Service
 public class SysSmsTemplateServiceImpl implements SysSmsTemplateService {
 
+    /**
+     * 正则表达式,匹配 {} 中的变量
+     */
+    private static final Pattern PATTERN_PARAMS = Pattern.compile("\\{(.*?)}");
+
     @Resource
     private SysSmsTemplateMapper smsTemplateMapper;
 
+    @Resource
+    private SysSmsChannelService smsChannelService;
+
     @Override
     public SysSmsTemplateDO getSmsTemplateByCode(String code) {
-        return smsTemplateMapper.selectOneByCode(code);
+        return smsTemplateMapper.selectByCode(code);
     }
 
     @Override
@@ -42,13 +57,25 @@ public class SysSmsTemplateServiceImpl implements SysSmsTemplateService {
         return StrUtil.format(content, params);
     }
 
+    @VisibleForTesting
+    public List<String> parseTemplateContentParams(String content) {
+        return ReUtil.findAllGroup1(PATTERN_PARAMS, content);
+    }
+
     @Override
     public Long createSmsTemplate(SysSmsTemplateCreateReqVO createReqVO) {
+        // 校验短信渠道
+        SysSmsChannelDO channelDO = checkSmsChannel(createReqVO.getChannelId());
+        // 校验短信编码是否重复
+        checkSmsTemplateCodeDuplicate(null, createReqVO.getCode());
+
         // 插入
-        SysSmsTemplateDO smsTemplate = SysSmsTemplateConvert.INSTANCE.convert(createReqVO);
-        smsTemplateMapper.insert(smsTemplate);
+        SysSmsTemplateDO template = SysSmsTemplateConvert.INSTANCE.convert(createReqVO);
+        template.setParams(parseTemplateContentParams(template.getContent()));
+        template.setChannelCode(channelDO.getCode());
+        smsTemplateMapper.insert(template);
         // 返回
-        return smsTemplate.getId();
+        return template.getId();
     }
 
     @Override
@@ -94,4 +121,29 @@ public class SysSmsTemplateServiceImpl implements SysSmsTemplateService {
         return smsTemplateMapper.selectList(exportReqVO);
     }
 
+    private SysSmsChannelDO checkSmsChannel(Long channelId) {
+        SysSmsChannelDO channelDO = smsChannelService.getSmsChannel(channelId);
+        if (channelDO == null) {
+            throw exception(SMS_CHANNEL_NOT_EXISTS);
+        }
+        if (!Objects.equals(channelDO.getStatus(), CommonStatusEnum.ENABLE.getStatus())) {
+            throw exception(SMS_CHANNEL_DISABLE);
+        }
+        return channelDO;
+    }
+
+    private void checkSmsTemplateCodeDuplicate(Long id, String code) {
+        SysSmsTemplateDO template = smsTemplateMapper.selectByCode(code);
+        if (template == null) {
+            return;
+        }
+        // 如果 id 为空,说明不用比较是否为相同 id 的字典类型
+        if (id == null) {
+            throw exception(SMS_TEMPLATE_CODE_DUPLICATE);
+        }
+        if (!template.getId().equals(id)) {
+            throw exception(SMS_TEMPLATE_CODE_DUPLICATE);
+        }
+    }
+
 }

+ 48 - 2
src/test/java/cn/iocoder/dashboard/modules/system/service/sms/SysSmsTemplateServiceTest.java

@@ -1,27 +1,37 @@
 package cn.iocoder.dashboard.modules.system.service.sms;
 
 import cn.iocoder.dashboard.BaseDbUnitTest;
+import cn.iocoder.dashboard.common.enums.CommonStatusEnum;
 import cn.iocoder.dashboard.common.pojo.PageResult;
 import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateCreateReqVO;
 import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateExportReqVO;
 import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplatePageReqVO;
 import cn.iocoder.dashboard.modules.system.controller.sms.vo.template.SysSmsTemplateUpdateReqVO;
+import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsChannelDO;
 import cn.iocoder.dashboard.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
 import cn.iocoder.dashboard.modules.system.dal.mysql.sms.SysSmsTemplateMapper;
+import cn.iocoder.dashboard.modules.system.enums.sms.SysSmsTemplateTypeEnum;
 import cn.iocoder.dashboard.modules.system.service.sms.impl.SysSmsTemplateServiceImpl;
+import cn.iocoder.dashboard.util.collection.ArrayUtils;
 import cn.iocoder.dashboard.util.object.ObjectUtils;
+import com.google.common.collect.Lists;
 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.util.List;
+import java.util.function.Consumer;
 
+import static cn.hutool.core.util.RandomUtil.randomEle;
 import static cn.iocoder.dashboard.modules.system.enums.SysErrorCodeConstants.SMS_TEMPLATE_NOT_EXISTS;
 import static cn.iocoder.dashboard.util.AssertUtils.assertPojoEquals;
 import static cn.iocoder.dashboard.util.AssertUtils.assertServiceException;
 import static cn.iocoder.dashboard.util.RandomUtils.randomLongId;
 import static cn.iocoder.dashboard.util.RandomUtils.randomPojo;
 import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
 
 /**
 * {@link SysSmsTemplateServiceImpl} 的单元测试类
@@ -37,10 +47,35 @@ public class SysSmsTemplateServiceTest extends BaseDbUnitTest {
     @Resource
     private SysSmsTemplateMapper smsTemplateMapper;
 
+    @MockBean
+    private SysSmsChannelService smsChannelService;
+
+    @Test
+    public void testParseTemplateContentParams() {
+        // 准备参数
+        String content = "正在进行登录操作{operation},您的验证码是{code}";
+        // mock 方法
+
+        // 调用
+        List<String> params = smsTemplateService.parseTemplateContentParams(content);
+        // 断言
+        assertEquals(Lists.newArrayList("operation", "code"), params);
+    }
+
     @Test
     public void testCreateSmsTemplate_success() {
         // 准备参数
-        SysSmsTemplateCreateReqVO reqVO = randomPojo(SysSmsTemplateCreateReqVO.class);
+        SysSmsTemplateCreateReqVO reqVO = randomPojo(SysSmsTemplateCreateReqVO.class, o -> {
+            o.setContent("正在进行登录操作{operation},您的验证码是{code}");
+            o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
+            o.setType(randomEle(SysSmsTemplateTypeEnum.values()).getType()); // 保证 type 的泛微
+        });
+        // mock 方法
+        SysSmsChannelDO channelDO = randomPojo(SysSmsChannelDO.class, o -> {
+            o.setId(reqVO.getChannelId());
+            o.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 保证 status 开启,创建必须处于这个状态
+        });
+        when(smsChannelService.getSmsChannel(eq(channelDO.getId()))).thenReturn(channelDO);
 
         // 调用
         Long smsTemplateId = smsTemplateService.createSmsTemplate(reqVO);
@@ -49,6 +84,8 @@ public class SysSmsTemplateServiceTest extends BaseDbUnitTest {
         // 校验记录的属性是否正确
         SysSmsTemplateDO smsTemplate = smsTemplateMapper.selectById(smsTemplateId);
         assertPojoEquals(reqVO, smsTemplate);
+        assertEquals(Lists.newArrayList("operation", "code"), smsTemplate.getParams());
+        assertEquals(channelDO.getCode(), smsTemplate.getChannelCode());
     }
 
     @Test
@@ -80,7 +117,7 @@ public class SysSmsTemplateServiceTest extends BaseDbUnitTest {
     @Test
     public void testDeleteSmsTemplate_success() {
         // mock 数据
-        SysSmsTemplateDO dbSmsTemplate = randomPojo(SysSmsTemplateDO.class);
+        SysSmsTemplateDO dbSmsTemplate = randomSmsTemplateDO();
         smsTemplateMapper.insert(dbSmsTemplate);// @Sql: 先插入出一条存在的数据
         // 准备参数
         Long id = dbSmsTemplate.getId();
@@ -191,4 +228,13 @@ public class SysSmsTemplateServiceTest extends BaseDbUnitTest {
        assertPojoEquals(dbSmsTemplate, list.get(0));
     }
 
+    @SafeVarargs
+    private static SysSmsTemplateDO randomSmsTemplateDO(Consumer<SysSmsTemplateDO>... consumers) {
+        Consumer<SysSmsTemplateDO> consumer = (o) -> {
+            o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
+            o.setType(randomEle(SysSmsTemplateTypeEnum.values()).getType()); // 保证 type 的泛微
+        };
+        return randomPojo(SysSmsTemplateDO.class, ArrayUtils.append(consumer, consumers));
+    }
+
 }

+ 20 - 0
src/test/resources/sql/create_tables.sql

@@ -358,3 +358,23 @@ CREATE TABLE IF NOT EXISTS "sys_sms_channel" (
    "deleted" bit NOT NULL DEFAULT FALSE,
    PRIMARY KEY ("id")
 ) COMMENT '短信渠道';
+
+CREATE TABLE "sys_sms_template" (
+    "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
+    "type" tinyint NOT NULL,
+    "status" tinyint NOT NULL,
+    "code" varchar(63) NOT NULL,
+    "name" varchar(63) NOT NULL,
+    "content" varchar(255) NOT NULL,
+    "params" varchar(255) NOT NULL,
+    "remark" varchar(255) DEFAULT NULL,
+    "api_template_id" varchar(63) NOT NULL,
+    "channel_id" bigint NOT NULL,
+    "channel_code" varchar(63) NOT 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 '短信模板';