Commit 81d89ba3507e9aa1f5252614bd8cd4839a6bf848

Authored by YunaiV
1 parent 66ebb71b

增加租户、租户套餐的单元测试

yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/config/YudaoMQAutoConfiguration.java
... ... @@ -134,7 +134,7 @@ public class YudaoMQAutoConfiguration {
134 134 String version = MapUtil.getStr(info, "redis_version");
135 135 // 校验最低版本必须大于等于 5.0.0
136 136 int majorVersion = Integer.parseInt(StrUtil.subBefore(version, '.', false));
137   - if (majorVersion < 7) {
  137 + if (majorVersion < 5) {
138 138 throw new IllegalStateException(StrUtil.format("您当前的 Redis 版本为 {},小于最低要求的 5.0.0 版本!" +
139 139 "请参考 {} 文档进行安装。", version, DocumentEnum.REDIS_INSTALL.getUrl()));
140 140 }
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java
1 1 package cn.iocoder.yudao.module.system.controller.admin.tenant;
2 2  
3   -import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.*;
4   -import cn.iocoder.yudao.module.system.convert.tenant.TenantConvert;
5   -import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO;
6   -import cn.iocoder.yudao.module.system.service.tenant.TenantService;
7 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
8 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
9 5 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
10 6 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
  7 +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.*;
  8 +import cn.iocoder.yudao.module.system.convert.tenant.TenantConvert;
  9 +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO;
  10 +import cn.iocoder.yudao.module.system.service.tenant.TenantService;
11 11 import io.swagger.annotations.Api;
12 12 import io.swagger.annotations.ApiImplicitParam;
13 13 import io.swagger.annotations.ApiOperation;
... ... @@ -18,7 +18,6 @@ import javax.annotation.Resource;
18 18 import javax.servlet.http.HttpServletResponse;
19 19 import javax.validation.Valid;
20 20 import java.io.IOException;
21   -import java.util.Collection;
22 21 import java.util.List;
23 22  
24 23 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
... ... @@ -73,15 +72,6 @@ public class TenantController {
73 72 return success(TenantConvert.INSTANCE.convert(tenant));
74 73 }
75 74  
76   - @GetMapping("/list")
77   - @ApiOperation("获得租户列表")
78   - @ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class)
79   - @PreAuthorize("@ss.hasPermission('system:tenant:query')")
80   - public CommonResult<List<TenantRespVO>> getTenantList(@RequestParam("ids") Collection<Long> ids) {
81   - List<TenantDO> list = tenantService.getTenantList(ids);
82   - return success(TenantConvert.INSTANCE.convertList(list));
83   - }
84   -
85 75 @GetMapping("/page")
86 76 @ApiOperation("获得租户分页")
87 77 @PreAuthorize("@ss.hasPermission('system:tenant:query')")
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantPackageMapper.java
... ... @@ -21,7 +21,7 @@ public interface TenantPackageMapper extends BaseMapperX&lt;TenantPackageDO&gt; {
21 21 return selectPage(reqVO, new LambdaQueryWrapperX<TenantPackageDO>()
22 22 .likeIfPresent(TenantPackageDO::getName, reqVO.getName())
23 23 .eqIfPresent(TenantPackageDO::getStatus, reqVO.getStatus())
24   - .eqIfPresent(TenantPackageDO::getRemark, reqVO.getRemark())
  24 + .likeIfPresent(TenantPackageDO::getRemark, reqVO.getRemark())
25 25 .betweenIfPresent(TenantPackageDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
26 26 .orderByDesc(TenantPackageDO::getId));
27 27 }
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImpl.java
... ... @@ -2,6 +2,9 @@ package cn.iocoder.yudao.module.system.service.logger;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.util.StrUtil;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.string.StrUtils;
  7 +import cn.iocoder.yudao.framework.operatelog.core.dto.OperateLogCreateReqDTO;
5 8 import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogExportReqVO;
6 9 import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO;
7 10 import cn.iocoder.yudao.module.system.convert.logger.OperateLogConvert;
... ... @@ -9,9 +12,6 @@ import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO;
9 12 import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
10 13 import cn.iocoder.yudao.module.system.dal.mysql.logger.OperateLogMapper;
11 14 import cn.iocoder.yudao.module.system.service.user.AdminUserService;
12   -import cn.iocoder.yudao.framework.common.pojo.PageResult;
13   -import cn.iocoder.yudao.framework.common.util.string.StrUtils;
14   -import cn.iocoder.yudao.framework.operatelog.core.dto.OperateLogCreateReqDTO;
15 15 import lombok.extern.slf4j.Slf4j;
16 16 import org.springframework.scheduling.annotation.Async;
17 17 import org.springframework.scheduling.annotation.AsyncResult;
... ... @@ -24,9 +24,9 @@ import java.util.Collections;
24 24 import java.util.List;
25 25 import java.util.concurrent.Future;
26 26  
  27 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
27 28 import static cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO.JAVA_METHOD_ARGS_MAX_LENGTH;
28 29 import static cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO.RESULT_MAX_LENGTH;
29   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
30 30  
31 31 @Service
32 32 @Validated
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantService.java
... ... @@ -12,7 +12,6 @@ import cn.iocoder.yudao.module.system.service.tenant.handler.TenantInfoHandler;
12 12 import cn.iocoder.yudao.module.system.service.tenant.handler.TenantMenuHandler;
13 13  
14 14 import javax.validation.Valid;
15   -import java.util.Collection;
16 15 import java.util.List;
17 16 import java.util.Set;
18 17  
... ... @@ -67,14 +66,6 @@ public interface TenantService extends TenantFrameworkService {
67 66 TenantDO getTenant(Long id);
68 67  
69 68 /**
70   - * 获得租户列表
71   - *
72   - * @param ids 编号
73   - * @return 租户列表
74   - */
75   - List<TenantDO> getTenantList(Collection<Long> ids);
76   -
77   - /**
78 69 * 获得租户分页
79 70 *
80 71 * @param pageReqVO 分页查询
... ...
yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java
... ... @@ -30,6 +30,7 @@ import cn.iocoder.yudao.module.system.service.permission.RoleService;
30 30 import cn.iocoder.yudao.module.system.service.tenant.handler.TenantInfoHandler;
31 31 import cn.iocoder.yudao.module.system.service.tenant.handler.TenantMenuHandler;
32 32 import cn.iocoder.yudao.module.system.service.user.AdminUserService;
  33 +import lombok.Getter;
33 34 import lombok.extern.slf4j.Slf4j;
34 35 import org.springframework.context.annotation.Lazy;
35 36 import org.springframework.scheduling.annotation.Scheduled;
... ... @@ -44,7 +45,10 @@ import javax.annotation.Resource;
44 45 import java.util.*;
45 46  
46 47 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  48 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertImmutableMap;
  49 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue;
47 50 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
  51 +import static java.util.Collections.singleton;
48 52  
49 53 /**
50 54 * 租户 Service 实现类
... ... @@ -68,10 +72,12 @@ public class TenantServiceImpl implements TenantService {
68 72 *
69 73 * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向
70 74 */
  75 + @Getter
71 76 private volatile Map<Long, TenantDO> tenantCache;
72 77 /**
73 78 * 缓存角色的最大更新时间,用于后续的增量轮询,判断是否有更新
74 79 */
  80 + @Getter
75 81 private volatile Date maxUpdateTime;
76 82  
77 83 @Resource
... ... @@ -108,8 +114,8 @@ public class TenantServiceImpl implements TenantService {
108 114 }
109 115  
110 116 // 写入缓存
111   - tenantCache = CollectionUtils.convertImmutableMap(tenantList, TenantDO::getId);
112   - maxUpdateTime = CollectionUtils.getMaxValue(tenantList, TenantDO::getUpdateTime);
  117 + tenantCache = convertImmutableMap(tenantList, TenantDO::getId);
  118 + maxUpdateTime = getMaxValue(tenantList, TenantDO::getUpdateTime);
113 119 log.info("[initLocalCache][初始化 Tenant 数量为 {}]", tenantList.size());
114 120 }
115 121  
... ... @@ -190,7 +196,7 @@ public class TenantServiceImpl implements TenantService {
190 196 // 创建用户
191 197 Long userId = userService.createUser(TenantConvert.INSTANCE.convert02(createReqVO));
192 198 // 分配角色
193   - permissionService.assignUserRole(userId, Collections.singleton(roleId));
  199 + permissionService.assignUserRole(userId, singleton(roleId));
194 200 return userId;
195 201 }
196 202  
... ... @@ -280,11 +286,6 @@ public class TenantServiceImpl implements TenantService {
280 286 }
281 287  
282 288 @Override
283   - public List<TenantDO> getTenantList(Collection<Long> ids) {
284   - return tenantMapper.selectBatchIds(ids);
285   - }
286   -
287   - @Override
288 289 public PageResult<TenantDO> getTenantPage(TenantPageReqVO pageReqVO) {
289 290 return tenantMapper.selectPage(pageReqVO);
290 291 }
... ...
yudao-module-system/yudao-module-system-impl/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java
1 1 package cn.iocoder.yudao.module.system.service.tenant;
2 2  
  3 +import cn.hutool.core.util.ReflectUtil;
3 4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 6 import cn.iocoder.yudao.framework.tenant.config.TenantProperties;
  7 +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
6 8 import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantCreateReqVO;
7 9 import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantExportReqVO;
8 10 import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO;
9 11 import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantUpdateReqVO;
  12 +import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
  13 +import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
10 14 import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO;
  15 +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO;
11 16 import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantMapper;
  17 +import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum;
  18 +import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum;
12 19 import cn.iocoder.yudao.module.system.mq.producer.tenant.TenantProducer;
13 20 import cn.iocoder.yudao.module.system.service.permission.MenuService;
14 21 import cn.iocoder.yudao.module.system.service.permission.PermissionService;
15 22 import cn.iocoder.yudao.module.system.service.permission.RoleService;
  23 +import cn.iocoder.yudao.module.system.service.tenant.handler.TenantInfoHandler;
  24 +import cn.iocoder.yudao.module.system.service.tenant.handler.TenantMenuHandler;
16 25 import cn.iocoder.yudao.module.system.service.user.AdminUserService;
17 26 import cn.iocoder.yudao.module.system.test.BaseDbUnitTest;
  27 +import org.junit.jupiter.api.BeforeEach;
18 28 import org.junit.jupiter.api.Test;
19 29 import org.springframework.boot.test.mock.mockito.MockBean;
20 30 import org.springframework.context.annotation.Import;
21 31  
22 32 import javax.annotation.Resource;
  33 +import java.time.Duration;
  34 +import java.util.Arrays;
  35 +import java.util.Collections;
23 36 import java.util.List;
  37 +import java.util.Map;
24 38  
  39 +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
  40 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.addTime;
25 41 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime;
26 42 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
  43 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.max;
27 44 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
28 45 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
29 46 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
30   -import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.TENANT_NOT_EXISTS;
  47 +import static cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO.PACKAGE_ID_SYSTEM;
  48 +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
  49 +import static java.util.Arrays.asList;
  50 +import static java.util.Collections.singleton;
31 51 import static org.junit.jupiter.api.Assertions.*;
  52 +import static org.mockito.ArgumentMatchers.*;
  53 +import static org.mockito.Mockito.*;
32 54  
33 55 /**
34 56 * {@link TenantServiceImpl} 的单元测试类
... ... @@ -59,10 +81,118 @@ public class TenantServiceImplTest extends BaseDbUnitTest {
59 81 @MockBean
60 82 private TenantProducer tenantProducer;
61 83  
  84 + @BeforeEach
  85 + public void setUp() {
  86 + // 清理缓存
  87 + ReflectUtil.setFieldValue(tenantService, "tenantCache", Collections.emptyMap());
  88 + ReflectUtil.setFieldValue(tenantService, "maxUpdateTime", null);
  89 + // 清理租户上下文
  90 + TenantContextHolder.clear();
  91 + }
  92 +
  93 + @Test
  94 + public void testInitLocalCache() {
  95 + // mock 数据
  96 + TenantDO tenantDO1 = randomPojo(TenantDO.class);
  97 + tenantMapper.insert(tenantDO1);
  98 + TenantDO tenantDO2 = randomPojo(TenantDO.class);
  99 + tenantMapper.insert(tenantDO2);
  100 +
  101 + // 调用
  102 + tenantService.initLocalCache();
  103 + // 断言 tenantCache 缓存
  104 + Map<Long, TenantDO> tenantCache = tenantService.getTenantCache();
  105 + assertEquals(2, tenantCache.size());
  106 + assertPojoEquals(tenantDO1, tenantCache.get(tenantDO1.getId()));
  107 + assertPojoEquals(tenantDO2, tenantCache.get(tenantDO2.getId()));
  108 + // 断言 maxUpdateTime 缓存
  109 + assertEquals(max(tenantDO1.getUpdateTime(), tenantDO2.getUpdateTime()), tenantService.getMaxUpdateTime());
  110 + }
  111 +
  112 + @Test
  113 + public void testGetTenantIds() {
  114 + // mock 数据
  115 + TenantDO tenant = randomPojo(TenantDO.class, o -> o.setId(1L));
  116 + tenantMapper.insert(tenant);
  117 + tenantService.initLocalCache();
  118 +
  119 + // 调用,并断言业务异常
  120 + List<Long> result = tenantService.getTenantIds();
  121 + assertEquals(Collections.singletonList(1L), result);
  122 + }
  123 +
  124 + @Test
  125 + public void testValidTenant_notExists() {
  126 + assertServiceException(() -> tenantService.validTenant(randomLongId()), TENANT_NOT_EXISTS);
  127 + }
  128 +
  129 + @Test
  130 + public void testValidTenant_disable() {
  131 + // mock 数据
  132 + TenantDO tenant = randomPojo(TenantDO.class, o -> o.setId(1L).setStatus(CommonStatusEnum.DISABLE.getStatus()));
  133 + tenantMapper.insert(tenant);
  134 + tenantService.initLocalCache();
  135 +
  136 + // 调用,并断言业务异常
  137 + assertServiceException(() -> tenantService.validTenant(1L), TENANT_DISABLE, tenant.getName());
  138 + }
  139 +
  140 + @Test
  141 + public void testValidTenant_expired() {
  142 + // mock 数据
  143 + TenantDO tenant = randomPojo(TenantDO.class, o -> o.setId(1L).setStatus(CommonStatusEnum.ENABLE.getStatus())
  144 + .setExpireTime(buildTime(2020, 2, 2)));
  145 + tenantMapper.insert(tenant);
  146 + tenantService.initLocalCache();
  147 +
  148 + // 调用,并断言业务异常
  149 + assertServiceException(() -> tenantService.validTenant(1L), TENANT_EXPIRE, tenant.getName());
  150 + }
  151 +
  152 + @Test
  153 + public void testValidTenant_success() {
  154 + // mock 数据
  155 + TenantDO tenant = randomPojo(TenantDO.class, o -> o.setId(1L).setStatus(CommonStatusEnum.ENABLE.getStatus())
  156 + .setExpireTime(addTime(Duration.ofDays(1))));
  157 + tenantMapper.insert(tenant);
  158 + tenantService.initLocalCache();
  159 +
  160 + // 调用,并断言业务异常
  161 + tenantService.validTenant(1L);
  162 + }
  163 +
62 164 @Test
63   - public void testCreateTenant_success() {
  165 + public void testCreateTenant() {
  166 + // mock 套餐 100L
  167 + TenantPackageDO tenantPackage = randomPojo(TenantPackageDO.class, o -> o.setId(100L));
  168 + when(tenantPackageService.validTenantPackage(eq(100L))).thenReturn(tenantPackage);
  169 + // mock 角色 200L
  170 + when(roleService.createRole(argThat(role -> {
  171 + assertEquals(RoleCodeEnum.TENANT_ADMIN.getName(), role.getName());
  172 + assertEquals(RoleCodeEnum.TENANT_ADMIN.getCode(), role.getCode());
  173 + assertEquals(0, role.getSort());
  174 + assertEquals("系统自动生成", role.getRemark());
  175 + return true;
  176 + }), eq(RoleTypeEnum.SYSTEM.getType()))).thenReturn(200L);
  177 + // mock 用户 300L
  178 + when(userService.createUser(argThat(user -> {
  179 + assertEquals("yudao", user.getUsername());
  180 + assertEquals("yuanma", user.getPassword());
  181 + assertEquals("芋道", user.getNickname());
  182 + assertEquals("15601691300", user.getMobile());
  183 + return true;
  184 + }))).thenReturn(300L);
  185 +
64 186 // 准备参数
65   - TenantCreateReqVO reqVO = randomPojo(TenantCreateReqVO.class, o -> o.setStatus(randomCommonStatus()));
  187 + TenantCreateReqVO reqVO = randomPojo(TenantCreateReqVO.class, o -> {
  188 + o.setContactName("芋道");
  189 + o.setContactMobile("15601691300");
  190 + o.setPackageId(100L);
  191 + o.setStatus(randomCommonStatus());
  192 + o.setDomain("https://www.iocoder.cn");
  193 + o.setUsername("yudao");
  194 + o.setPassword("yuanma");
  195 + });
66 196  
67 197 // 调用
68 198 Long tenantId = tenantService.createTenant(reqVO);
... ... @@ -71,6 +201,13 @@ public class TenantServiceImplTest extends BaseDbUnitTest {
71 201 // 校验记录的属性是否正确
72 202 TenantDO tenant = tenantMapper.selectById(tenantId);
73 203 assertPojoEquals(reqVO, tenant);
  204 + assertEquals(300L, tenant.getContactUserId());
  205 + // verify 分配权限
  206 + verify(permissionService).assignRoleMenu(eq(200L), same(tenantPackage.getMenuIds()));
  207 + // verify 分配角色
  208 + verify(permissionService).assignUserRole(eq(300L), eq(singleton(200L)));
  209 + // verify 发送刷新消息
  210 + verify(tenantProducer).sendTenantRefreshMessage();
74 211 }
75 212  
76 213 @Test
... ... @@ -82,13 +219,32 @@ public class TenantServiceImplTest extends BaseDbUnitTest {
82 219 TenantUpdateReqVO reqVO = randomPojo(TenantUpdateReqVO.class, o -> {
83 220 o.setId(dbTenant.getId()); // 设置更新的 ID
84 221 o.setStatus(randomCommonStatus());
  222 + o.setDomain(randomString());
85 223 });
86 224  
  225 + // mock 套餐
  226 + TenantPackageDO tenantPackage = randomPojo(TenantPackageDO.class,
  227 + o -> o.setMenuIds(asSet(200L, 201L)));
  228 + when(tenantPackageService.validTenantPackage(eq(reqVO.getPackageId()))).thenReturn(tenantPackage);
  229 + // mock 所有角色
  230 + RoleDO role100 = randomPojo(RoleDO.class, o -> o.setId(100L).setCode(RoleCodeEnum.TENANT_ADMIN.getCode()));
  231 + role100.setTenantId(dbTenant.getId());
  232 + RoleDO role101 = randomPojo(RoleDO.class, o -> o.setId(101L));
  233 + role101.setTenantId(dbTenant.getId());
  234 + when(roleService.getRoles(isNull())).thenReturn(asList(role100, role101));
  235 + // mock 每个角色的权限
  236 + when(permissionService.getRoleMenuIds(eq(101L))).thenReturn(asSet(201L, 202L));
  237 +
87 238 // 调用
88 239 tenantService.updateTenant(reqVO);
89 240 // 校验是否更新正确
90 241 TenantDO tenant = tenantMapper.selectById(reqVO.getId()); // 获取最新的
91 242 assertPojoEquals(reqVO, tenant);
  243 + // verify 发送刷新消息
  244 + verify(tenantProducer).sendTenantRefreshMessage();
  245 + // verify 设置角色权限
  246 + verify(permissionService).assignRoleMenu(eq(100L), eq(asSet(200L, 201L)));
  247 + verify(permissionService).assignRoleMenu(eq(101L), eq(asSet(201L)));
92 248 }
93 249  
94 250 @Test
... ... @@ -101,6 +257,20 @@ public class TenantServiceImplTest extends BaseDbUnitTest {
101 257 }
102 258  
103 259 @Test
  260 + public void testUpdateTenant_system() {
  261 + // mock 数据
  262 + TenantDO dbTenant = randomPojo(TenantDO.class, o -> o.setPackageId(PACKAGE_ID_SYSTEM));
  263 + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据
  264 + // 准备参数
  265 + TenantUpdateReqVO reqVO = randomPojo(TenantUpdateReqVO.class, o -> {
  266 + o.setId(dbTenant.getId()); // 设置更新的 ID
  267 + });
  268 +
  269 + // 调用,校验业务异常
  270 + assertServiceException(() -> tenantService.updateTenant(reqVO), TENANT_CAN_NOT_UPDATE_SYSTEM);
  271 + }
  272 +
  273 + @Test
104 274 public void testDeleteTenant_success() {
105 275 // mock 数据
106 276 TenantDO dbTenant = randomPojo(TenantDO.class,
... ... @@ -125,6 +295,32 @@ public class TenantServiceImplTest extends BaseDbUnitTest {
125 295 }
126 296  
127 297 @Test
  298 + public void testDeleteTenant_system() {
  299 + // mock 数据
  300 + TenantDO dbTenant = randomPojo(TenantDO.class, o -> o.setPackageId(PACKAGE_ID_SYSTEM));
  301 + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据
  302 + // 准备参数
  303 + Long id = dbTenant.getId();
  304 +
  305 + // 调用, 并断言异常
  306 + assertServiceException(() -> tenantService.deleteTenant(id), TENANT_CAN_NOT_UPDATE_SYSTEM);
  307 + }
  308 +
  309 + @Test
  310 + public void testGetTenant() {
  311 + // mock 数据
  312 + TenantDO dbTenant = randomPojo(TenantDO.class);
  313 + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据
  314 + // 准备参数
  315 + Long id = dbTenant.getId();
  316 +
  317 + // 调用
  318 + TenantDO result = tenantService.getTenant(id);
  319 + // 校验存在
  320 + assertPojoEquals(result, dbTenant);
  321 + }
  322 +
  323 + @Test
128 324 public void testGetTenantPage() {
129 325 // mock 数据
130 326 TenantDO dbTenant = randomPojo(TenantDO.class, o -> { // 等会查询到
... ... @@ -199,4 +395,129 @@ public class TenantServiceImplTest extends BaseDbUnitTest {
199 395 assertPojoEquals(dbTenant, list.get(0));
200 396 }
201 397  
  398 +
  399 + @Test
  400 + public void testGetTenantByName() {
  401 + // mock 数据
  402 + TenantDO dbTenant = randomPojo(TenantDO.class, o -> o.setName("芋道"));
  403 + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据
  404 +
  405 + // 调用
  406 + TenantDO result = tenantService.getTenantByName("芋道");
  407 + // 校验存在
  408 + assertPojoEquals(result, dbTenant);
  409 + }
  410 +
  411 + @Test
  412 + public void testGetTenantListByPackageId() {
  413 + // mock 数据
  414 + TenantDO dbTenant1 = randomPojo(TenantDO.class, o -> o.setPackageId(1L));
  415 + tenantMapper.insert(dbTenant1);// @Sql: 先插入出一条存在的数据
  416 + TenantDO dbTenant2 = randomPojo(TenantDO.class, o -> o.setPackageId(2L));
  417 + tenantMapper.insert(dbTenant2);// @Sql: 先插入出一条存在的数据
  418 +
  419 + // 调用
  420 + List<TenantDO> result = tenantService.getTenantListByPackageId(1L);
  421 + assertEquals(1, result.size());
  422 + assertPojoEquals(dbTenant1, result.get(0));
  423 + }
  424 +
  425 + @Test
  426 + public void testGetTenantCountByPackageId() {
  427 + // mock 数据
  428 + TenantDO dbTenant1 = randomPojo(TenantDO.class, o -> o.setPackageId(1L));
  429 + tenantMapper.insert(dbTenant1);// @Sql: 先插入出一条存在的数据
  430 + TenantDO dbTenant2 = randomPojo(TenantDO.class, o -> o.setPackageId(2L));
  431 + tenantMapper.insert(dbTenant2);// @Sql: 先插入出一条存在的数据
  432 +
  433 + // 调用
  434 + Integer count = tenantService.getTenantCountByPackageId(1L);
  435 + assertEquals(1, count);
  436 + }
  437 +
  438 + @Test
  439 + public void testHandleTenantInfo_disable() {
  440 + // 准备参数
  441 + TenantInfoHandler handler = mock(TenantInfoHandler.class);
  442 + // mock 禁用
  443 + when(tenantProperties.getEnable()).thenReturn(false);
  444 +
  445 + // 调用
  446 + tenantService.handleTenantInfo(handler);
  447 + // 断言
  448 + verify(handler, never()).handle(any());
  449 + }
  450 +
  451 + @Test
  452 + public void testHandleTenantInfo_success() {
  453 + // 准备参数
  454 + TenantInfoHandler handler = mock(TenantInfoHandler.class);
  455 + // mock 未禁用
  456 + when(tenantProperties.getEnable()).thenReturn(true);
  457 + // mock 租户
  458 + TenantDO dbTenant = randomPojo(TenantDO.class);
  459 + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据
  460 + TenantContextHolder.setTenantId(dbTenant.getId());
  461 +
  462 + // 调用
  463 + tenantService.handleTenantInfo(handler);
  464 + // 断言
  465 + verify(handler).handle(argThat(argument -> {
  466 + assertPojoEquals(dbTenant, argument);
  467 + return true;
  468 + }));
  469 + }
  470 +
  471 + @Test
  472 + public void testHandleTenantMenu_disable() {
  473 + // 准备参数
  474 + TenantMenuHandler handler = mock(TenantMenuHandler.class);
  475 + // mock 禁用
  476 + when(tenantProperties.getEnable()).thenReturn(false);
  477 +
  478 + // 调用
  479 + tenantService.handleTenantMenu(handler);
  480 + // 断言
  481 + verify(handler, never()).handle(any());
  482 + }
  483 +
  484 + @Test // 系统租户的情况
  485 + public void testHandleTenantMenu_system() {
  486 + // 准备参数
  487 + TenantMenuHandler handler = mock(TenantMenuHandler.class);
  488 + // mock 未禁用
  489 + when(tenantProperties.getEnable()).thenReturn(true);
  490 + // mock 租户
  491 + TenantDO dbTenant = randomPojo(TenantDO.class, o -> o.setPackageId(PACKAGE_ID_SYSTEM));
  492 + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据
  493 + TenantContextHolder.setTenantId(dbTenant.getId());
  494 + // mock 菜单
  495 + when(menuService.getMenus()).thenReturn(Arrays.asList(randomPojo(MenuDO.class, o -> o.setId(100L)),
  496 + randomPojo(MenuDO.class, o -> o.setId(101L))));
  497 +
  498 + // 调用
  499 + tenantService.handleTenantMenu(handler);
  500 + // 断言
  501 + verify(handler).handle(asSet(100L, 101L));
  502 + }
  503 +
  504 + @Test // 普通租户的情况
  505 + public void testHandleTenantMenu_normal() {
  506 + // 准备参数
  507 + TenantMenuHandler handler = mock(TenantMenuHandler.class);
  508 + // mock 未禁用
  509 + when(tenantProperties.getEnable()).thenReturn(true);
  510 + // mock 租户
  511 + TenantDO dbTenant = randomPojo(TenantDO.class, o -> o.setPackageId(200L));
  512 + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据
  513 + TenantContextHolder.setTenantId(dbTenant.getId());
  514 + // mock 菜单
  515 + when(tenantPackageService.getTenantPackage(eq(200L))).thenReturn(randomPojo(TenantPackageDO.class,
  516 + o -> o.setMenuIds(asSet(100L, 101L))));
  517 +
  518 + // 调用
  519 + tenantService.handleTenantMenu(handler);
  520 + // 断言
  521 + verify(handler).handle(asSet(100L, 101L));
  522 + }
202 523 }
... ...
yudao-module-system/yudao-module-system-impl/src/test/resources/sql/create_tables.sql
... ... @@ -394,7 +394,7 @@ CREATE TABLE IF NOT EXISTS &quot;system_social_user&quot; (
394 394 CREATE TABLE IF NOT EXISTS "system_tenant" (
395 395 "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
396 396 "name" varchar(63) NOT NULL,
397   - "contact_user_id" bigint NOT NULL,
  397 + "contact_user_id" bigint NOT NULL DEFAULT '0',
398 398 "contact_name" varchar(255) NOT NULL,
399 399 "contact_mobile" varchar(255),
400 400 "status" tinyint NOT NULL,
... ...
更新日志.md
... ... @@ -32,7 +32,7 @@ TODO
32 32 * 【新增】新增 `@TenantIgnore` 注解,标记指定方法,忽略多租户的自动过滤,适合实现跨租户的逻辑 [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/4d53944771c66b563da1e3d68d3ba43405af8a06)
33 33 * 【新增】租户套餐的管理,可配置每个租户的可使用的功能权限 [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/6b6d676a6baa2dad16ae9bf03d5002209064c8cc)
34 34 * 【优化】新建租户时,自动创建对应的管理员账号、角色等基础信息 [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/2598c033a95d4b61d5f5ab3da5f1414f25c510d6)
35   -* 【优化】Redis 最低版本 5.0.0 检测,解决搭建环境过程中无法理解 XREADGROUP 指令的报错 [commit]()
  35 +* 【优化】Redis 最低版本 5.0.0 检测,解决搭建环境过程中无法理解 XREADGROUP 指令的报错 [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/c64bb81caeee2721e0c373eee014e3977d88cb37)
36 36  
37 37 ### 🐞 Bug Fixes
38 38  
... ...