Commit cdcecd0d4a2d782cd7043cd34510e6004a837fea

Authored by YunaiV
1 parent 659023bb

完善 FileConfig 的单元测试

yudao-module-infra/yudao-module-infra-impl/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImpl.java
... ... @@ -18,6 +18,7 @@ import cn.iocoder.yudao.module.infra.convert.file.FileConfigConvert;
18 18 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO;
19 19 import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper;
20 20 import cn.iocoder.yudao.module.infra.mq.producer.file.FileConfigProducer;
  21 +import lombok.Getter;
21 22 import lombok.extern.slf4j.Slf4j;
22 23 import org.springframework.context.annotation.Lazy;
23 24 import org.springframework.scheduling.annotation.Scheduled;
... ... @@ -58,6 +59,7 @@ public class FileConfigServiceImpl implements FileConfigService {
58 59 /**
59 60 * 缓存菜单的最大更新时间,用于后续的增量轮询,判断是否有更新
60 61 */
  62 + @Getter
61 63 private volatile Date maxUpdateTime;
62 64  
63 65 @Resource
... ... @@ -65,6 +67,7 @@ public class FileConfigServiceImpl implements FileConfigService {
65 67 /**
66 68 * Master FileClient 对象,有且仅有一个,即 {@link FileConfigDO#getMaster()} 对应的
67 69 */
  70 + @Getter
68 71 private FileClient masterFileClient;
69 72  
70 73 @Resource
... ...
yudao-module-infra/yudao-module-infra-impl/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImplTest.java
1 1 package cn.iocoder.yudao.module.infra.service.file;
2 2  
  3 +import cn.hutool.core.map.MapUtil;
3 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.file.core.client.FileClient;
  6 +import cn.iocoder.yudao.framework.file.core.client.FileClientConfig;
  7 +import cn.iocoder.yudao.framework.file.core.client.FileClientFactory;
  8 +import cn.iocoder.yudao.framework.file.core.client.local.LocalFileClientConfig;
  9 +import cn.iocoder.yudao.framework.file.core.enums.FileStorageEnum;
4 10 import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigCreateReqVO;
5 11 import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigPageReqVO;
6 12 import cn.iocoder.yudao.module.infra.controller.admin.file.vo.config.FileConfigUpdateReqVO;
7 13 import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileConfigDO;
8 14 import cn.iocoder.yudao.module.infra.dal.mysql.file.FileConfigMapper;
  15 +import cn.iocoder.yudao.module.infra.mq.producer.file.FileConfigProducer;
9 16 import cn.iocoder.yudao.module.infra.test.BaseDbUnitTest;
10   -import org.junit.jupiter.api.Disabled;
  17 +import lombok.Data;
11 18 import org.junit.jupiter.api.Test;
  19 +import org.springframework.boot.test.mock.mockito.MockBean;
12 20 import org.springframework.context.annotation.Import;
13 21  
14 22 import javax.annotation.Resource;
  23 +import javax.validation.Validator;
  24 +import java.io.Serializable;
  25 +import java.util.Map;
15 26  
  27 +import static cn.hutool.core.util.RandomUtil.randomEle;
  28 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime;
16 29 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
  30 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.max;
17 31 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
18 32 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
19 33 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
20 34 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  35 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_CONFIG_DELETE_FAIL_MASTER;
21 36 import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_CONFIG_NOT_EXISTS;
22 37 import static org.junit.jupiter.api.Assertions.*;
  38 +import static org.mockito.ArgumentMatchers.eq;
  39 +import static org.mockito.Mockito.*;
23 40  
24 41 /**
25 42 * {@link FileConfigServiceImpl} 的单元测试类
... ... @@ -35,10 +52,44 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
35 52 @Resource
36 53 private FileConfigMapper fileConfigMapper;
37 54  
  55 + @MockBean
  56 + private FileConfigProducer fileConfigProducer;
  57 + @MockBean
  58 + private Validator validator;
  59 + @MockBean
  60 + private FileClientFactory fileClientFactory;
  61 +
  62 + @Test
  63 + public void testInitLocalCache() {
  64 + // mock 数据
  65 + FileConfigDO configDO1 = randomFileConfigDO().setId(1L).setMaster(true);
  66 + fileConfigMapper.insert(configDO1);
  67 + FileConfigDO configDO2 = randomFileConfigDO().setId(2L).setMaster(false);
  68 + fileConfigMapper.insert(configDO2);
  69 + // mock fileClientFactory 获得 master
  70 + FileClient masterFileClient = mock(FileClient.class);
  71 + when(fileClientFactory.getFileClient(eq(1L))).thenReturn(masterFileClient);
  72 +
  73 + // 调用
  74 + fileConfigService.initFileClients();
  75 + // 断言 fileClientFactory 调用
  76 + verify(fileClientFactory).createOrUpdateFileClient(eq(1L),
  77 + eq(configDO1.getStorage()), eq(configDO1.getConfig()));
  78 + verify(fileClientFactory).createOrUpdateFileClient(eq(2L),
  79 + eq(configDO2.getStorage()), eq(configDO2.getConfig()));
  80 + assertSame(masterFileClient, fileConfigService.getMasterFileClient());
  81 + // 断言 maxUpdateTime 缓存
  82 + assertEquals(max(configDO1.getUpdateTime(), configDO2.getUpdateTime()),
  83 + fileConfigService.getMaxUpdateTime());
  84 + }
  85 +
38 86 @Test
39 87 public void testCreateFileConfig_success() {
40 88 // 准备参数
41   - FileConfigCreateReqVO reqVO = randomPojo(FileConfigCreateReqVO.class);
  89 + Map<String, Object> config = MapUtil.<String, Object>builder().put("basePath", "/yunai")
  90 + .put("domain", "https://www.iocoder.cn").build();
  91 + FileConfigCreateReqVO reqVO = randomPojo(FileConfigCreateReqVO.class,
  92 + o -> o.setStorage(FileStorageEnum.LOCAL.getStorage()).setConfig(config));
42 93  
43 94 // 调用
44 95 Long fileConfigId = fileConfigService.createFileConfig(reqVO);
... ... @@ -46,24 +97,37 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
46 97 assertNotNull(fileConfigId);
47 98 // 校验记录的属性是否正确
48 99 FileConfigDO fileConfig = fileConfigMapper.selectById(fileConfigId);
49   - assertPojoEquals(reqVO, fileConfig);
  100 + assertPojoEquals(reqVO, fileConfig, "config");
  101 + assertFalse(fileConfig.getMaster());
  102 + assertEquals("/yunai", ((LocalFileClientConfig) fileConfig.getConfig()).getBasePath());
  103 + assertEquals("https://www.iocoder.cn", ((LocalFileClientConfig) fileConfig.getConfig()).getDomain());
  104 + // verify 调用
  105 + verify(fileConfigProducer).sendFileConfigRefreshMessage();
50 106 }
51 107  
52 108 @Test
53 109 public void testUpdateFileConfig_success() {
54 110 // mock 数据
55   - FileConfigDO dbFileConfig = randomPojo(FileConfigDO.class);
  111 + FileConfigDO dbFileConfig = randomPojo(FileConfigDO.class, o -> o.setStorage(FileStorageEnum.LOCAL.getStorage())
  112 + .setConfig(new LocalFileClientConfig().setBasePath("/yunai").setDomain("https://www.iocoder.cn")));
56 113 fileConfigMapper.insert(dbFileConfig);// @Sql: 先插入出一条存在的数据
57 114 // 准备参数
58 115 FileConfigUpdateReqVO reqVO = randomPojo(FileConfigUpdateReqVO.class, o -> {
59 116 o.setId(dbFileConfig.getId()); // 设置更新的 ID
  117 + Map<String, Object> config = MapUtil.<String, Object>builder().put("basePath", "/yunai2")
  118 + .put("domain", "https://doc.iocoder.cn").build();
  119 + o.setConfig(config);
60 120 });
61 121  
62 122 // 调用
63 123 fileConfigService.updateFileConfig(reqVO);
64 124 // 校验是否更新正确
65 125 FileConfigDO fileConfig = fileConfigMapper.selectById(reqVO.getId()); // 获取最新的
66   - assertPojoEquals(reqVO, fileConfig);
  126 + assertPojoEquals(reqVO, fileConfig, "config");
  127 + assertEquals("/yunai2", ((LocalFileClientConfig) fileConfig.getConfig()).getBasePath());
  128 + assertEquals("https://doc.iocoder.cn", ((LocalFileClientConfig) fileConfig.getConfig()).getDomain());
  129 + // verify 调用
  130 + verify(fileConfigProducer).sendFileConfigRefreshMessage();
67 131 }
68 132  
69 133 @Test
... ... @@ -76,9 +140,32 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
76 140 }
77 141  
78 142 @Test
  143 + public void testUpdateFileConfigMaster_success() {
  144 + // mock 数据
  145 + FileConfigDO dbFileConfig = randomFileConfigDO().setMaster(false);
  146 + fileConfigMapper.insert(dbFileConfig);// @Sql: 先插入出一条存在的数据
  147 + FileConfigDO masterFileConfig = randomFileConfigDO().setMaster(true);
  148 + fileConfigMapper.insert(masterFileConfig);// @Sql: 先插入出一条存在的数据
  149 +
  150 + // 调用
  151 + fileConfigService.updateFileConfigMaster(dbFileConfig.getId());
  152 + // 断言数据
  153 + assertTrue(fileConfigMapper.selectById(dbFileConfig.getId()).getMaster());
  154 + assertFalse(fileConfigMapper.selectById(masterFileConfig.getId()).getMaster());
  155 + // verify 调用
  156 + verify(fileConfigProducer).sendFileConfigRefreshMessage();
  157 + }
  158 +
  159 + @Test
  160 + public void testUpdateFileConfigMaster_notExists() {
  161 + // 调用, 并断言异常
  162 + assertServiceException(() -> fileConfigService.updateFileConfigMaster(randomLongId()), FILE_CONFIG_NOT_EXISTS);
  163 + }
  164 +
  165 + @Test
79 166 public void testDeleteFileConfig_success() {
80 167 // mock 数据
81   - FileConfigDO dbFileConfig = randomPojo(FileConfigDO.class);
  168 + FileConfigDO dbFileConfig = randomFileConfigDO().setMaster(false);
82 169 fileConfigMapper.insert(dbFileConfig);// @Sql: 先插入出一条存在的数据
83 170 // 准备参数
84 171 Long id = dbFileConfig.getId();
... ... @@ -87,6 +174,8 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
87 174 fileConfigService.deleteFileConfig(id);
88 175 // 校验数据不存在了
89 176 assertNull(fileConfigMapper.selectById(id));
  177 + // verify 调用
  178 + verify(fileConfigProducer).sendFileConfigRefreshMessage();
90 179 }
91 180  
92 181 @Test
... ... @@ -99,27 +188,36 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
99 188 }
100 189  
101 190 @Test
102   - @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
  191 + public void testDeleteFileConfig_master() {
  192 + // mock 数据
  193 + FileConfigDO dbFileConfig = randomFileConfigDO().setMaster(true);
  194 + fileConfigMapper.insert(dbFileConfig);// @Sql: 先插入出一条存在的数据
  195 + // 准备参数
  196 + Long id = dbFileConfig.getId();
  197 +
  198 + // 调用, 并断言异常
  199 + assertServiceException(() -> fileConfigService.deleteFileConfig(id), FILE_CONFIG_DELETE_FAIL_MASTER);
  200 + }
  201 +
  202 + @Test
103 203 public void testGetFileConfigPage() {
104 204 // mock 数据
105   - FileConfigDO dbFileConfig = randomPojo(FileConfigDO.class, o -> { // 等会查询到
106   - o.setName(null);
107   - o.setStorage(null);
108   - o.setCreateTime(null);
109   - });
  205 + FileConfigDO dbFileConfig = randomFileConfigDO().setName("芋道源码")
  206 + .setStorage(FileStorageEnum.LOCAL.getStorage());
  207 + dbFileConfig.setCreateTime(buildTime(2022, 11, 11));// 等会查询到
110 208 fileConfigMapper.insert(dbFileConfig);
111 209 // 测试 name 不匹配
112   - fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setName(null)));
  210 + fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setName("源码")));
113 211 // 测试 storage 不匹配
114   - fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setStorage(null)));
  212 + fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setStorage(FileStorageEnum.DB.getStorage())));
115 213 // 测试 createTime 不匹配
116   - fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setCreateTime(null)));
  214 + fileConfigMapper.insert(cloneIgnoreId(dbFileConfig, o -> o.setCreateTime(buildTime(2022, 12, 12))));
117 215 // 准备参数
118 216 FileConfigPageReqVO reqVO = new FileConfigPageReqVO();
119   - reqVO.setName(null);
120   - reqVO.setStorage(null);
121   - reqVO.setBeginCreateTime(null);
122   - reqVO.setEndCreateTime(null);
  217 + reqVO.setName("芋道");
  218 + reqVO.setStorage(FileStorageEnum.LOCAL.getStorage());
  219 + reqVO.setBeginCreateTime(buildTime(2022, 11, 10));
  220 + reqVO.setEndCreateTime(buildTime(2022, 11, 12));
123 221  
124 222 // 调用
125 223 PageResult<FileConfigDO> pageResult = fileConfigService.getFileConfigPage(reqVO);
... ... @@ -129,4 +227,30 @@ public class FileConfigServiceImplTest extends BaseDbUnitTest {
129 227 assertPojoEquals(dbFileConfig, pageResult.getList().get(0));
130 228 }
131 229  
  230 + @Test
  231 + public void testFileConfig() {
  232 + // mock 数据
  233 + FileConfigDO dbFileConfig = randomFileConfigDO().setMaster(false);
  234 + fileConfigMapper.insert(dbFileConfig);// @Sql: 先插入出一条存在的数据
  235 + // 准备参数
  236 + Long id = dbFileConfig.getId();
  237 + // mock 获得 Client
  238 + FileClient fileClient = mock(FileClient.class);
  239 + when(fileClientFactory.getFileClient(eq(id))).thenReturn(fileClient);
  240 + when(fileClient.upload(any(), any())).thenReturn("https://www.iocoder.cn");
  241 +
  242 + // 调用,并断言
  243 + assertEquals("https://www.iocoder.cn", fileConfigService.testFileConfig(id));
  244 + }
  245 +
  246 + private FileConfigDO randomFileConfigDO() {
  247 + return randomPojo(FileConfigDO.class).setStorage(randomEle(FileStorageEnum.values()).getStorage())
  248 + .setConfig(new EmptyFileClientConfig());
  249 + }
  250 +
  251 + @Data
  252 + public static class EmptyFileClientConfig implements FileClientConfig, Serializable {
  253 +
  254 + }
  255 +
132 256 }
... ...
yudao-module-infra/yudao-module-infra-impl/src/test/resources/application-unit-test.yaml
... ... @@ -26,8 +26,9 @@ spring:
26 26 port: 16379 # 端口(单元测试,使用 16379 端口)
27 27 database: 0 # 数据库索引
28 28  
29   -mybatis:
  29 +mybatis-plus:
30 30 lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试
  31 + type-aliases-package: ${yudao.info.base-package}.module.*.dal.dataobject
31 32  
32 33 --- #################### 定时任务相关配置 ####################
33 34  
... ... @@ -46,4 +47,4 @@ mybatis:
46 47 # 芋道配置项,设置当前项目所有自定义的配置
47 48 yudao:
48 49 info:
49   - base-package: cn.iocoder.yudao.module
  50 + base-package: cn.iocoder.yudao
... ...
yudao-module-infra/yudao-module-infra-impl/src/test/resources/sql/clean.sql
... ... @@ -8,3 +8,4 @@ DELETE FROM &quot;infra_api_access_log&quot;;
8 8 DELETE FROM "infra_file";
9 9 DELETE FROM "infra_api_error_log";
10 10 DELETE FROM "infra_test_demo";
  11 +DELETE FROM "infra_file_config";
... ...
yudao-module-infra/yudao-module-infra-impl/src/test/resources/sql/create_tables.sql
... ... @@ -16,6 +16,21 @@ CREATE TABLE IF NOT EXISTS &quot;infra_config&quot; (
16 16 PRIMARY KEY ("id")
17 17 ) COMMENT '参数配置表';
18 18  
  19 +CREATE TABLE IF NOT EXISTS "infra_file_config" (
  20 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  21 + "name" varchar(63) NOT NULL,
  22 + "storage" tinyint NOT NULL,
  23 + "remark" varchar(255),
  24 + "master" bit(1) NOT NULL,
  25 + "config" varchar(4096) NOT NULL,
  26 + "creator" varchar(64) DEFAULT '',
  27 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  28 + "updater" varchar(64) DEFAULT '',
  29 + "update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  30 + "deleted" bit NOT NULL DEFAULT FALSE,
  31 + PRIMARY KEY ("id")
  32 +) COMMENT '文件配置表';
  33 +
19 34 CREATE TABLE IF NOT EXISTS "infra_file" (
20 35 "id" varchar(188) NOT NULL,
21 36 "type" varchar(63) DEFAULT NULL,
... ...