From 81d89ba3507e9aa1f5252614bd8cd4839a6bf848 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 27 Feb 2022 00:15:13 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=A7=9F=E6=88=B7=E3=80=81?= =?UTF-8?q?=E7=A7=9F=E6=88=B7=E5=A5=97=E9=A4=90=E7=9A=84=E5=8D=95=E5=85=83?= =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mq/config/YudaoMQAutoConfiguration.java | 2 +- .../admin/tenant/TenantController.java | 18 +- .../dal/mysql/tenant/TenantPackageMapper.java | 2 +- .../service/logger/OperateLogServiceImpl.java | 8 +- .../system/service/tenant/TenantService.java | 9 - .../service/tenant/TenantServiceImpl.java | 17 +- .../service/tenant/TenantServiceImplTest.java | 327 +++++++++++++++++- .../src/test/resources/sql/create_tables.sql | 2 +- 更新日志.md | 2 +- 9 files changed, 345 insertions(+), 42 deletions(-) diff --git a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/config/YudaoMQAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/config/YudaoMQAutoConfiguration.java index b7422b8d5..76e89358d 100644 --- a/yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/config/YudaoMQAutoConfiguration.java +++ b/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 { String version = MapUtil.getStr(info, "redis_version"); // 校验最低版本必须大于等于 5.0.0 int majorVersion = Integer.parseInt(StrUtil.subBefore(version, '.', false)); - if (majorVersion < 7) { + if (majorVersion < 5) { throw new IllegalStateException(StrUtil.format("您当前的 Redis 版本为 {},小于最低要求的 5.0.0 版本!" + "请参考 {} 文档进行安装。", version, DocumentEnum.REDIS_INSTALL.getUrl())); } diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java index fe5a72f97..427172b18 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java +++ b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java @@ -1,13 +1,13 @@ package cn.iocoder.yudao.module.system.controller.admin.tenant; -import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.*; -import cn.iocoder.yudao.module.system.convert.tenant.TenantConvert; -import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; -import cn.iocoder.yudao.module.system.service.tenant.TenantService; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.*; +import cn.iocoder.yudao.module.system.convert.tenant.TenantConvert; +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; +import cn.iocoder.yudao.module.system.service.tenant.TenantService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; @@ -18,7 +18,6 @@ import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; import java.io.IOException; -import java.util.Collection; import java.util.List; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -73,15 +72,6 @@ public class TenantController { return success(TenantConvert.INSTANCE.convert(tenant)); } - @GetMapping("/list") - @ApiOperation("获得租户列表") - @ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class) - @PreAuthorize("@ss.hasPermission('system:tenant:query')") - public CommonResult> getTenantList(@RequestParam("ids") Collection ids) { - List list = tenantService.getTenantList(ids); - return success(TenantConvert.INSTANCE.convertList(list)); - } - @GetMapping("/page") @ApiOperation("获得租户分页") @PreAuthorize("@ss.hasPermission('system:tenant:query')") diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantPackageMapper.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantPackageMapper.java index 7e280fbd6..2f7006555 100755 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/tenant/TenantPackageMapper.java +++ b/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 { return selectPage(reqVO, new LambdaQueryWrapperX() .likeIfPresent(TenantPackageDO::getName, reqVO.getName()) .eqIfPresent(TenantPackageDO::getStatus, reqVO.getStatus()) - .eqIfPresent(TenantPackageDO::getRemark, reqVO.getRemark()) + .likeIfPresent(TenantPackageDO::getRemark, reqVO.getRemark()) .betweenIfPresent(TenantPackageDO::getCreateTime, reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()) .orderByDesc(TenantPackageDO::getId)); } diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImpl.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImpl.java index b1e0383fe..48f1b5b15 100644 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/logger/OperateLogServiceImpl.java +++ b/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; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.string.StrUtils; +import cn.iocoder.yudao.framework.operatelog.core.dto.OperateLogCreateReqDTO; import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogExportReqVO; import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO; import cn.iocoder.yudao.module.system.convert.logger.OperateLogConvert; @@ -9,9 +12,6 @@ import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO; import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; import cn.iocoder.yudao.module.system.dal.mysql.logger.OperateLogMapper; import cn.iocoder.yudao.module.system.service.user.AdminUserService; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.string.StrUtils; -import cn.iocoder.yudao.framework.operatelog.core.dto.OperateLogCreateReqDTO; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.AsyncResult; @@ -24,9 +24,9 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.Future; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO.JAVA_METHOD_ARGS_MAX_LENGTH; import static cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO.RESULT_MAX_LENGTH; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; @Service @Validated diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantService.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantService.java index ad99c6226..dd4efa1ae 100755 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantService.java +++ b/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; import cn.iocoder.yudao.module.system.service.tenant.handler.TenantMenuHandler; import javax.validation.Valid; -import java.util.Collection; import java.util.List; import java.util.Set; @@ -66,14 +65,6 @@ public interface TenantService extends TenantFrameworkService { */ TenantDO getTenant(Long id); - /** - * 获得租户列表 - * - * @param ids 编号 - * @return 租户列表 - */ - List getTenantList(Collection ids); - /** * 获得租户分页 * diff --git a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java b/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java index c4b52eaa8..27611e098 100755 --- a/yudao-module-system/yudao-module-system-impl/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java +++ b/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; import cn.iocoder.yudao.module.system.service.tenant.handler.TenantInfoHandler; import cn.iocoder.yudao.module.system.service.tenant.handler.TenantMenuHandler; import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Lazy; import org.springframework.scheduling.annotation.Scheduled; @@ -44,7 +45,10 @@ import javax.annotation.Resource; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertImmutableMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getMaxValue; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; +import static java.util.Collections.singleton; /** * 租户 Service 实现类 @@ -68,10 +72,12 @@ public class TenantServiceImpl implements TenantService { * * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 */ + @Getter private volatile Map tenantCache; /** * 缓存角色的最大更新时间,用于后续的增量轮询,判断是否有更新 */ + @Getter private volatile Date maxUpdateTime; @Resource @@ -108,8 +114,8 @@ public class TenantServiceImpl implements TenantService { } // 写入缓存 - tenantCache = CollectionUtils.convertImmutableMap(tenantList, TenantDO::getId); - maxUpdateTime = CollectionUtils.getMaxValue(tenantList, TenantDO::getUpdateTime); + tenantCache = convertImmutableMap(tenantList, TenantDO::getId); + maxUpdateTime = getMaxValue(tenantList, TenantDO::getUpdateTime); log.info("[initLocalCache][初始化 Tenant 数量为 {}]", tenantList.size()); } @@ -190,7 +196,7 @@ public class TenantServiceImpl implements TenantService { // 创建用户 Long userId = userService.createUser(TenantConvert.INSTANCE.convert02(createReqVO)); // 分配角色 - permissionService.assignUserRole(userId, Collections.singleton(roleId)); + permissionService.assignUserRole(userId, singleton(roleId)); return userId; } @@ -279,11 +285,6 @@ public class TenantServiceImpl implements TenantService { return tenantMapper.selectById(id); } - @Override - public List getTenantList(Collection ids) { - return tenantMapper.selectBatchIds(ids); - } - @Override public PageResult getTenantPage(TenantPageReqVO pageReqVO) { return tenantMapper.selectPage(pageReqVO); diff --git a/yudao-module-system/yudao-module-system-impl/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java b/yudao-module-system/yudao-module-system-impl/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java index 8f529f076..53c77a20f 100644 --- a/yudao-module-system/yudao-module-system-impl/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java +++ b/yudao-module-system/yudao-module-system-impl/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java @@ -1,34 +1,56 @@ package cn.iocoder.yudao.module.system.service.tenant; +import cn.hutool.core.util.ReflectUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.tenant.config.TenantProperties; +import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantExportReqVO; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantUpdateReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; +import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO; +import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantPackageDO; import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantMapper; +import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum; +import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum; import cn.iocoder.yudao.module.system.mq.producer.tenant.TenantProducer; import cn.iocoder.yudao.module.system.service.permission.MenuService; import cn.iocoder.yudao.module.system.service.permission.PermissionService; import cn.iocoder.yudao.module.system.service.permission.RoleService; +import cn.iocoder.yudao.module.system.service.tenant.handler.TenantInfoHandler; +import cn.iocoder.yudao.module.system.service.tenant.handler.TenantMenuHandler; import cn.iocoder.yudao.module.system.service.user.AdminUserService; import cn.iocoder.yudao.module.system.test.BaseDbUnitTest; +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.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.Map; +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.addTime; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.buildTime; import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.max; 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.TENANT_NOT_EXISTS; +import static cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO.PACKAGE_ID_SYSTEM; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; +import static java.util.Arrays.asList; +import static java.util.Collections.singleton; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; /** * {@link TenantServiceImpl} 的单元测试类 @@ -59,10 +81,118 @@ public class TenantServiceImplTest extends BaseDbUnitTest { @MockBean private TenantProducer tenantProducer; + @BeforeEach + public void setUp() { + // 清理缓存 + ReflectUtil.setFieldValue(tenantService, "tenantCache", Collections.emptyMap()); + ReflectUtil.setFieldValue(tenantService, "maxUpdateTime", null); + // 清理租户上下文 + TenantContextHolder.clear(); + } + @Test - public void testCreateTenant_success() { + public void testInitLocalCache() { + // mock 数据 + TenantDO tenantDO1 = randomPojo(TenantDO.class); + tenantMapper.insert(tenantDO1); + TenantDO tenantDO2 = randomPojo(TenantDO.class); + tenantMapper.insert(tenantDO2); + + // 调用 + tenantService.initLocalCache(); + // 断言 tenantCache 缓存 + Map tenantCache = tenantService.getTenantCache(); + assertEquals(2, tenantCache.size()); + assertPojoEquals(tenantDO1, tenantCache.get(tenantDO1.getId())); + assertPojoEquals(tenantDO2, tenantCache.get(tenantDO2.getId())); + // 断言 maxUpdateTime 缓存 + assertEquals(max(tenantDO1.getUpdateTime(), tenantDO2.getUpdateTime()), tenantService.getMaxUpdateTime()); + } + + @Test + public void testGetTenantIds() { + // mock 数据 + TenantDO tenant = randomPojo(TenantDO.class, o -> o.setId(1L)); + tenantMapper.insert(tenant); + tenantService.initLocalCache(); + + // 调用,并断言业务异常 + List result = tenantService.getTenantIds(); + assertEquals(Collections.singletonList(1L), result); + } + + @Test + public void testValidTenant_notExists() { + assertServiceException(() -> tenantService.validTenant(randomLongId()), TENANT_NOT_EXISTS); + } + + @Test + public void testValidTenant_disable() { + // mock 数据 + TenantDO tenant = randomPojo(TenantDO.class, o -> o.setId(1L).setStatus(CommonStatusEnum.DISABLE.getStatus())); + tenantMapper.insert(tenant); + tenantService.initLocalCache(); + + // 调用,并断言业务异常 + assertServiceException(() -> tenantService.validTenant(1L), TENANT_DISABLE, tenant.getName()); + } + + @Test + public void testValidTenant_expired() { + // mock 数据 + TenantDO tenant = randomPojo(TenantDO.class, o -> o.setId(1L).setStatus(CommonStatusEnum.ENABLE.getStatus()) + .setExpireTime(buildTime(2020, 2, 2))); + tenantMapper.insert(tenant); + tenantService.initLocalCache(); + + // 调用,并断言业务异常 + assertServiceException(() -> tenantService.validTenant(1L), TENANT_EXPIRE, tenant.getName()); + } + + @Test + public void testValidTenant_success() { + // mock 数据 + TenantDO tenant = randomPojo(TenantDO.class, o -> o.setId(1L).setStatus(CommonStatusEnum.ENABLE.getStatus()) + .setExpireTime(addTime(Duration.ofDays(1)))); + tenantMapper.insert(tenant); + tenantService.initLocalCache(); + + // 调用,并断言业务异常 + tenantService.validTenant(1L); + } + + @Test + public void testCreateTenant() { + // mock 套餐 100L + TenantPackageDO tenantPackage = randomPojo(TenantPackageDO.class, o -> o.setId(100L)); + when(tenantPackageService.validTenantPackage(eq(100L))).thenReturn(tenantPackage); + // mock 角色 200L + when(roleService.createRole(argThat(role -> { + assertEquals(RoleCodeEnum.TENANT_ADMIN.getName(), role.getName()); + assertEquals(RoleCodeEnum.TENANT_ADMIN.getCode(), role.getCode()); + assertEquals(0, role.getSort()); + assertEquals("系统自动生成", role.getRemark()); + return true; + }), eq(RoleTypeEnum.SYSTEM.getType()))).thenReturn(200L); + // mock 用户 300L + when(userService.createUser(argThat(user -> { + assertEquals("yudao", user.getUsername()); + assertEquals("yuanma", user.getPassword()); + assertEquals("芋道", user.getNickname()); + assertEquals("15601691300", user.getMobile()); + return true; + }))).thenReturn(300L); + // 准备参数 - TenantCreateReqVO reqVO = randomPojo(TenantCreateReqVO.class, o -> o.setStatus(randomCommonStatus())); + TenantCreateReqVO reqVO = randomPojo(TenantCreateReqVO.class, o -> { + o.setContactName("芋道"); + o.setContactMobile("15601691300"); + o.setPackageId(100L); + o.setStatus(randomCommonStatus()); + o.setDomain("https://www.iocoder.cn"); + o.setUsername("yudao"); + o.setPassword("yuanma"); + }); // 调用 Long tenantId = tenantService.createTenant(reqVO); @@ -71,6 +201,13 @@ public class TenantServiceImplTest extends BaseDbUnitTest { // 校验记录的属性是否正确 TenantDO tenant = tenantMapper.selectById(tenantId); assertPojoEquals(reqVO, tenant); + assertEquals(300L, tenant.getContactUserId()); + // verify 分配权限 + verify(permissionService).assignRoleMenu(eq(200L), same(tenantPackage.getMenuIds())); + // verify 分配角色 + verify(permissionService).assignUserRole(eq(300L), eq(singleton(200L))); + // verify 发送刷新消息 + verify(tenantProducer).sendTenantRefreshMessage(); } @Test @@ -82,13 +219,32 @@ public class TenantServiceImplTest extends BaseDbUnitTest { TenantUpdateReqVO reqVO = randomPojo(TenantUpdateReqVO.class, o -> { o.setId(dbTenant.getId()); // 设置更新的 ID o.setStatus(randomCommonStatus()); + o.setDomain(randomString()); }); + // mock 套餐 + TenantPackageDO tenantPackage = randomPojo(TenantPackageDO.class, + o -> o.setMenuIds(asSet(200L, 201L))); + when(tenantPackageService.validTenantPackage(eq(reqVO.getPackageId()))).thenReturn(tenantPackage); + // mock 所有角色 + RoleDO role100 = randomPojo(RoleDO.class, o -> o.setId(100L).setCode(RoleCodeEnum.TENANT_ADMIN.getCode())); + role100.setTenantId(dbTenant.getId()); + RoleDO role101 = randomPojo(RoleDO.class, o -> o.setId(101L)); + role101.setTenantId(dbTenant.getId()); + when(roleService.getRoles(isNull())).thenReturn(asList(role100, role101)); + // mock 每个角色的权限 + when(permissionService.getRoleMenuIds(eq(101L))).thenReturn(asSet(201L, 202L)); + // 调用 tenantService.updateTenant(reqVO); // 校验是否更新正确 TenantDO tenant = tenantMapper.selectById(reqVO.getId()); // 获取最新的 assertPojoEquals(reqVO, tenant); + // verify 发送刷新消息 + verify(tenantProducer).sendTenantRefreshMessage(); + // verify 设置角色权限 + verify(permissionService).assignRoleMenu(eq(100L), eq(asSet(200L, 201L))); + verify(permissionService).assignRoleMenu(eq(101L), eq(asSet(201L))); } @Test @@ -100,6 +256,20 @@ public class TenantServiceImplTest extends BaseDbUnitTest { assertServiceException(() -> tenantService.updateTenant(reqVO), TENANT_NOT_EXISTS); } + @Test + public void testUpdateTenant_system() { + // mock 数据 + TenantDO dbTenant = randomPojo(TenantDO.class, o -> o.setPackageId(PACKAGE_ID_SYSTEM)); + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据 + // 准备参数 + TenantUpdateReqVO reqVO = randomPojo(TenantUpdateReqVO.class, o -> { + o.setId(dbTenant.getId()); // 设置更新的 ID + }); + + // 调用,校验业务异常 + assertServiceException(() -> tenantService.updateTenant(reqVO), TENANT_CAN_NOT_UPDATE_SYSTEM); + } + @Test public void testDeleteTenant_success() { // mock 数据 @@ -124,6 +294,32 @@ public class TenantServiceImplTest extends BaseDbUnitTest { assertServiceException(() -> tenantService.deleteTenant(id), TENANT_NOT_EXISTS); } + @Test + public void testDeleteTenant_system() { + // mock 数据 + TenantDO dbTenant = randomPojo(TenantDO.class, o -> o.setPackageId(PACKAGE_ID_SYSTEM)); + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbTenant.getId(); + + // 调用, 并断言异常 + assertServiceException(() -> tenantService.deleteTenant(id), TENANT_CAN_NOT_UPDATE_SYSTEM); + } + + @Test + public void testGetTenant() { + // mock 数据 + TenantDO dbTenant = randomPojo(TenantDO.class); + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbTenant.getId(); + + // 调用 + TenantDO result = tenantService.getTenant(id); + // 校验存在 + assertPojoEquals(result, dbTenant); + } + @Test public void testGetTenantPage() { // mock 数据 @@ -199,4 +395,129 @@ public class TenantServiceImplTest extends BaseDbUnitTest { assertPojoEquals(dbTenant, list.get(0)); } + + @Test + public void testGetTenantByName() { + // mock 数据 + TenantDO dbTenant = randomPojo(TenantDO.class, o -> o.setName("芋道")); + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据 + + // 调用 + TenantDO result = tenantService.getTenantByName("芋道"); + // 校验存在 + assertPojoEquals(result, dbTenant); + } + + @Test + public void testGetTenantListByPackageId() { + // mock 数据 + TenantDO dbTenant1 = randomPojo(TenantDO.class, o -> o.setPackageId(1L)); + tenantMapper.insert(dbTenant1);// @Sql: 先插入出一条存在的数据 + TenantDO dbTenant2 = randomPojo(TenantDO.class, o -> o.setPackageId(2L)); + tenantMapper.insert(dbTenant2);// @Sql: 先插入出一条存在的数据 + + // 调用 + List result = tenantService.getTenantListByPackageId(1L); + assertEquals(1, result.size()); + assertPojoEquals(dbTenant1, result.get(0)); + } + + @Test + public void testGetTenantCountByPackageId() { + // mock 数据 + TenantDO dbTenant1 = randomPojo(TenantDO.class, o -> o.setPackageId(1L)); + tenantMapper.insert(dbTenant1);// @Sql: 先插入出一条存在的数据 + TenantDO dbTenant2 = randomPojo(TenantDO.class, o -> o.setPackageId(2L)); + tenantMapper.insert(dbTenant2);// @Sql: 先插入出一条存在的数据 + + // 调用 + Integer count = tenantService.getTenantCountByPackageId(1L); + assertEquals(1, count); + } + + @Test + public void testHandleTenantInfo_disable() { + // 准备参数 + TenantInfoHandler handler = mock(TenantInfoHandler.class); + // mock 禁用 + when(tenantProperties.getEnable()).thenReturn(false); + + // 调用 + tenantService.handleTenantInfo(handler); + // 断言 + verify(handler, never()).handle(any()); + } + + @Test + public void testHandleTenantInfo_success() { + // 准备参数 + TenantInfoHandler handler = mock(TenantInfoHandler.class); + // mock 未禁用 + when(tenantProperties.getEnable()).thenReturn(true); + // mock 租户 + TenantDO dbTenant = randomPojo(TenantDO.class); + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据 + TenantContextHolder.setTenantId(dbTenant.getId()); + + // 调用 + tenantService.handleTenantInfo(handler); + // 断言 + verify(handler).handle(argThat(argument -> { + assertPojoEquals(dbTenant, argument); + return true; + })); + } + + @Test + public void testHandleTenantMenu_disable() { + // 准备参数 + TenantMenuHandler handler = mock(TenantMenuHandler.class); + // mock 禁用 + when(tenantProperties.getEnable()).thenReturn(false); + + // 调用 + tenantService.handleTenantMenu(handler); + // 断言 + verify(handler, never()).handle(any()); + } + + @Test // 系统租户的情况 + public void testHandleTenantMenu_system() { + // 准备参数 + TenantMenuHandler handler = mock(TenantMenuHandler.class); + // mock 未禁用 + when(tenantProperties.getEnable()).thenReturn(true); + // mock 租户 + TenantDO dbTenant = randomPojo(TenantDO.class, o -> o.setPackageId(PACKAGE_ID_SYSTEM)); + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据 + TenantContextHolder.setTenantId(dbTenant.getId()); + // mock 菜单 + when(menuService.getMenus()).thenReturn(Arrays.asList(randomPojo(MenuDO.class, o -> o.setId(100L)), + randomPojo(MenuDO.class, o -> o.setId(101L)))); + + // 调用 + tenantService.handleTenantMenu(handler); + // 断言 + verify(handler).handle(asSet(100L, 101L)); + } + + @Test // 普通租户的情况 + public void testHandleTenantMenu_normal() { + // 准备参数 + TenantMenuHandler handler = mock(TenantMenuHandler.class); + // mock 未禁用 + when(tenantProperties.getEnable()).thenReturn(true); + // mock 租户 + TenantDO dbTenant = randomPojo(TenantDO.class, o -> o.setPackageId(200L)); + tenantMapper.insert(dbTenant);// @Sql: 先插入出一条存在的数据 + TenantContextHolder.setTenantId(dbTenant.getId()); + // mock 菜单 + when(tenantPackageService.getTenantPackage(eq(200L))).thenReturn(randomPojo(TenantPackageDO.class, + o -> o.setMenuIds(asSet(100L, 101L)))); + + // 调用 + tenantService.handleTenantMenu(handler); + // 断言 + verify(handler).handle(asSet(100L, 101L)); + } } diff --git a/yudao-module-system/yudao-module-system-impl/src/test/resources/sql/create_tables.sql b/yudao-module-system/yudao-module-system-impl/src/test/resources/sql/create_tables.sql index c9163bec9..724986704 100644 --- a/yudao-module-system/yudao-module-system-impl/src/test/resources/sql/create_tables.sql +++ b/yudao-module-system/yudao-module-system-impl/src/test/resources/sql/create_tables.sql @@ -394,7 +394,7 @@ CREATE TABLE IF NOT EXISTS "system_social_user" ( CREATE TABLE IF NOT EXISTS "system_tenant" ( "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "name" varchar(63) NOT NULL, - "contact_user_id" bigint NOT NULL, + "contact_user_id" bigint NOT NULL DEFAULT '0', "contact_name" varchar(255) NOT NULL, "contact_mobile" varchar(255), "status" tinyint NOT NULL, diff --git a/更新日志.md b/更新日志.md index 30e60d451..506cd6625 100644 --- a/更新日志.md +++ b/更新日志.md @@ -32,7 +32,7 @@ TODO * 【新增】新增 `@TenantIgnore` 注解,标记指定方法,忽略多租户的自动过滤,适合实现跨租户的逻辑 [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/4d53944771c66b563da1e3d68d3ba43405af8a06) * 【新增】租户套餐的管理,可配置每个租户的可使用的功能权限 [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/6b6d676a6baa2dad16ae9bf03d5002209064c8cc) * 【优化】新建租户时,自动创建对应的管理员账号、角色等基础信息 [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/2598c033a95d4b61d5f5ab3da5f1414f25c510d6) -* 【优化】Redis 最低版本 5.0.0 检测,解决搭建环境过程中无法理解 XREADGROUP 指令的报错 [commit]() +* 【优化】Redis 最低版本 5.0.0 检测,解决搭建环境过程中无法理解 XREADGROUP 指令的报错 [commit](https://gitee.com/zhijiantianya/ruoyi-vue-pro/commit/c64bb81caeee2721e0c373eee014e3977d88cb37) ### 🐞 Bug Fixes