完善 MenuService 的单元测试
This commit is contained in:
parent
be465d758b
commit
152fc70e86
|
@ -62,12 +62,12 @@ public interface MenuService {
|
|||
List<MenuDO> getMenuList(MenuListReqVO reqVO);
|
||||
|
||||
/**
|
||||
* 获得权限对应的菜单数组
|
||||
* 获得权限对应的菜单编号数组
|
||||
*
|
||||
* @param permission 权限标识
|
||||
* @return 数组
|
||||
*/
|
||||
List<MenuDO> getMenuListByPermissionFromCache(String permission);
|
||||
List<Long> getMenuIdListByPermissionFromCache(String permission);
|
||||
|
||||
/**
|
||||
* 获得菜单
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package cn.iocoder.yudao.module.system.service.permission;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuCreateReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuListReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuUpdateReqVO;
|
||||
|
@ -10,9 +11,9 @@ import cn.iocoder.yudao.module.system.dal.mysql.permission.MenuMapper;
|
|||
import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants;
|
||||
import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum;
|
||||
import cn.iocoder.yudao.module.system.service.tenant.TenantService;
|
||||
import com.baomidou.dynamic.datasource.annotation.Master;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
@ -23,6 +24,7 @@ import java.util.Collection;
|
|||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
import static cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO.ID_ROOT;
|
||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
|
||||
|
||||
|
@ -44,6 +46,7 @@ public class MenuServiceImpl implements MenuService {
|
|||
private TenantService tenantService;
|
||||
|
||||
@Override
|
||||
@CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, key = "#reqVO.permission")
|
||||
public Long createMenu(MenuCreateReqVO reqVO) {
|
||||
// 校验父菜单存在
|
||||
validateParentMenu(reqVO.getParentId(), null);
|
||||
|
@ -59,6 +62,8 @@ public class MenuServiceImpl implements MenuService {
|
|||
}
|
||||
|
||||
@Override
|
||||
@CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST,
|
||||
allEntries = true) // allEntries 清空所有缓存,因为 permission 如果变更,涉及到新老两个 permission。直接清理,简单有效
|
||||
public void updateMenu(MenuUpdateReqVO reqVO) {
|
||||
// 校验更新的菜单是否存在
|
||||
if (menuMapper.selectById(reqVO.getId()) == null) {
|
||||
|
@ -77,19 +82,21 @@ public class MenuServiceImpl implements MenuService {
|
|||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteMenu(Long menuId) {
|
||||
@CacheEvict(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST,
|
||||
allEntries = true) // allEntries 清空所有缓存,因为此时不知道 id 对应的 permission 是多少。直接清理,简单有效
|
||||
public void deleteMenu(Long id) {
|
||||
// 校验是否还有子菜单
|
||||
if (menuMapper.selectCountByParentId(menuId) > 0) {
|
||||
if (menuMapper.selectCountByParentId(id) > 0) {
|
||||
throw exception(MENU_EXISTS_CHILDREN);
|
||||
}
|
||||
// 校验删除的菜单是否存在
|
||||
if (menuMapper.selectById(menuId) == null) {
|
||||
if (menuMapper.selectById(id) == null) {
|
||||
throw exception(MENU_NOT_EXISTS);
|
||||
}
|
||||
// 标记删除
|
||||
menuMapper.deleteById(menuId);
|
||||
menuMapper.deleteById(id);
|
||||
// 删除授予给角色的权限
|
||||
permissionService.processMenuDeleted(menuId);
|
||||
permissionService.processMenuDeleted(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -112,8 +119,9 @@ public class MenuServiceImpl implements MenuService {
|
|||
|
||||
@Override
|
||||
@Cacheable(value = RedisKeyConstants.PERMISSION_MENU_ID_LIST, key = "#permission")
|
||||
public List<MenuDO> getMenuListByPermissionFromCache(String permission) {
|
||||
return menuMapper.selectListByPermission(permission);
|
||||
public List<Long> getMenuIdListByPermissionFromCache(String permission) {
|
||||
List<MenuDO> menus = menuMapper.selectListByPermission(permission);
|
||||
return convertList(menus, MenuDO::getId);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -7,7 +7,6 @@ import cn.hutool.extra.spring.SpringUtil;
|
|||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.dynamic.TenantDS;
|
||||
import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
|
||||
|
@ -206,19 +205,18 @@ public class PermissionServiceImpl implements PermissionService {
|
|||
* @param permission 权限标识
|
||||
* @return 是否拥有
|
||||
*/
|
||||
// TODO 芋艿:要想想咋继续优化
|
||||
private boolean hasAnyPermission(List<RoleDO> roles, String permission) {
|
||||
List<MenuDO> menuList = menuService.getMenuListByPermissionFromCache(permission);
|
||||
List<Long> menuIds = menuService.getMenuIdListByPermissionFromCache(permission);
|
||||
// 采用严格模式,如果权限找不到对应的 Menu 的话,也认为没有权限
|
||||
if (CollUtil.isEmpty(menuList)) {
|
||||
if (CollUtil.isEmpty(menuIds)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 判断是否有权限
|
||||
Set<Long> roleIds = convertSet(roles, RoleDO::getId);
|
||||
for (MenuDO menu : menuList) {
|
||||
for (Long menuId : menuIds) {
|
||||
// 拥有该角色的菜单编号数组
|
||||
Set<Long> menuRoleIds = getSelf().getMenuRoleIdListByMenuIdFromCache(menu.getId());
|
||||
Set<Long> menuRoleIds = getSelf().getMenuRoleIdListByMenuIdFromCache(menuId);
|
||||
// 如果有交集,说明有权限
|
||||
if (CollUtil.containsAny(menuRoleIds, roleIds)) {
|
||||
return true;
|
||||
|
|
|
@ -8,10 +8,7 @@ import cn.iocoder.yudao.module.system.controller.admin.permission.vo.menu.MenuUp
|
|||
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.permission.MenuMapper;
|
||||
import cn.iocoder.yudao.module.system.enums.permission.MenuTypeEnum;
|
||||
import cn.iocoder.yudao.module.system.mq.producer.permission.MenuProducer;
|
||||
import cn.iocoder.yudao.module.system.service.tenant.TenantService;
|
||||
import com.google.common.collect.LinkedListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
@ -26,8 +23,6 @@ import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServic
|
|||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
|
||||
import static cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO.ID_ROOT;
|
||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
|
@ -46,35 +41,12 @@ public class MenuServiceImplTest extends BaseDbUnitTest {
|
|||
@MockBean
|
||||
private PermissionService permissionService;
|
||||
@MockBean
|
||||
private MenuProducer menuProducer;
|
||||
@MockBean
|
||||
private TenantService tenantService;
|
||||
|
||||
@Test
|
||||
public void testInitLocalCache_success() {
|
||||
MenuDO menuDO1 = randomPojo(MenuDO.class);
|
||||
menuMapper.insert(menuDO1);
|
||||
MenuDO menuDO2 = randomPojo(MenuDO.class);
|
||||
menuMapper.insert(menuDO2);
|
||||
|
||||
// 调用
|
||||
menuService.initLocalCache();
|
||||
// 校验 menuCache 缓存
|
||||
Map<Long, MenuDO> menuCache = menuService.getMenuCache();
|
||||
assertEquals(2, menuCache.size());
|
||||
assertPojoEquals(menuDO1, menuCache.get(menuDO1.getId()));
|
||||
assertPojoEquals(menuDO2, menuCache.get(menuDO2.getId()));
|
||||
// 校验 permissionMenuCache 缓存
|
||||
Multimap<String, MenuDO> permissionMenuCache = menuService.getPermissionMenuCache();
|
||||
assertEquals(2, permissionMenuCache.size());
|
||||
assertPojoEquals(menuDO1, permissionMenuCache.get(menuDO1.getPermission()));
|
||||
assertPojoEquals(menuDO2, permissionMenuCache.get(menuDO2.getPermission()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateMenu_success() {
|
||||
// mock 数据(构造父菜单)
|
||||
MenuDO menuDO = createMenuDO(MenuTypeEnum.MENU,
|
||||
MenuDO menuDO = buildMenuDO(MenuTypeEnum.MENU,
|
||||
"parent", 0L);
|
||||
menuMapper.insert(menuDO);
|
||||
Long parentId = menuDO.getId();
|
||||
|
@ -89,14 +61,12 @@ public class MenuServiceImplTest extends BaseDbUnitTest {
|
|||
// 校验记录的属性是否正确
|
||||
MenuDO dbMenu = menuMapper.selectById(menuId);
|
||||
assertPojoEquals(reqVO, dbMenu);
|
||||
// 校验调用
|
||||
verify(menuProducer).sendMenuRefreshMessage();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateMenu_success() {
|
||||
// mock 数据(构造父子菜单)
|
||||
MenuDO sonMenuDO = initParentAndSonMenu();
|
||||
MenuDO sonMenuDO = createParentAndSonMenu();
|
||||
Long sonId = sonMenuDO.getId();
|
||||
// 准备参数
|
||||
MenuUpdateReqVO reqVO = randomPojo(MenuUpdateReqVO.class, o -> {
|
||||
|
@ -111,8 +81,6 @@ public class MenuServiceImplTest extends BaseDbUnitTest {
|
|||
// 校验记录的属性是否正确
|
||||
MenuDO dbMenu = menuMapper.selectById(sonId);
|
||||
assertPojoEquals(reqVO, dbMenu);
|
||||
// 校验调用
|
||||
verify(menuProducer).sendMenuRefreshMessage();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -137,7 +105,6 @@ public class MenuServiceImplTest extends BaseDbUnitTest {
|
|||
MenuDO dbMenuDO = menuMapper.selectById(id);
|
||||
assertNull(dbMenuDO);
|
||||
verify(permissionService).processMenuDeleted(id);
|
||||
verify(menuProducer).sendMenuRefreshMessage();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -149,7 +116,7 @@ public class MenuServiceImplTest extends BaseDbUnitTest {
|
|||
@Test
|
||||
public void testDeleteMenu_existChildren() {
|
||||
// mock 数据(构造父子菜单)
|
||||
MenuDO sonMenu = initParentAndSonMenu();
|
||||
MenuDO sonMenu = createParentAndSonMenu();
|
||||
// 准备参数
|
||||
Long parentId = sonMenu.getParentId();
|
||||
|
||||
|
@ -218,85 +185,6 @@ public class MenuServiceImplTest extends BaseDbUnitTest {
|
|||
assertPojoEquals(menu100, result.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListMenusFromCache_withoutId() {
|
||||
// mock 缓存
|
||||
Map<Long, MenuDO> menuCache = new HashMap<>();
|
||||
// 可被匹配
|
||||
MenuDO menuDO = randomPojo(MenuDO.class, o -> o.setId(1L)
|
||||
.setType(MenuTypeEnum.MENU.getType()).setStatus(CommonStatusEnum.ENABLE.getStatus()));
|
||||
menuCache.put(menuDO.getId(), menuDO);
|
||||
// 测试 type 不匹配
|
||||
menuCache.put(3L, randomPojo(MenuDO.class, o -> o.setId(3L)
|
||||
.setType(MenuTypeEnum.BUTTON.getType()).setStatus(CommonStatusEnum.ENABLE.getStatus())));
|
||||
// 测试 status 不匹配
|
||||
menuCache.put(4L, randomPojo(MenuDO.class, o -> o.setId(4L)
|
||||
.setType(MenuTypeEnum.MENU.getType()).setStatus(CommonStatusEnum.DISABLE.getStatus())));
|
||||
menuService.setMenuCache(menuCache);
|
||||
// 准备参数
|
||||
Collection<Integer> menuTypes = singletonList(MenuTypeEnum.MENU.getType());
|
||||
Collection<Integer> menusStatuses = singletonList(CommonStatusEnum.ENABLE.getStatus());
|
||||
|
||||
// 调用
|
||||
List<MenuDO> list = menuService.getMenuListFromCache(menuTypes, menusStatuses);
|
||||
// 断言
|
||||
assertEquals(1, list.size());
|
||||
assertPojoEquals(menuDO, list.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListMenusFromCache_withId() {
|
||||
// mock 缓存
|
||||
Map<Long, MenuDO> menuCache = new HashMap<>();
|
||||
// 可被匹配
|
||||
MenuDO menuDO = randomPojo(MenuDO.class, o -> o.setId(1L)
|
||||
.setType(MenuTypeEnum.MENU.getType()).setStatus(CommonStatusEnum.ENABLE.getStatus()));
|
||||
menuCache.put(menuDO.getId(), menuDO);
|
||||
// 测试 id 不匹配
|
||||
menuCache.put(2L, randomPojo(MenuDO.class, o -> o.setId(2L)
|
||||
.setType(MenuTypeEnum.MENU.getType()).setStatus(CommonStatusEnum.ENABLE.getStatus())));
|
||||
// 测试 type 不匹配
|
||||
menuCache.put(3L, randomPojo(MenuDO.class, o -> o.setId(3L)
|
||||
.setType(MenuTypeEnum.BUTTON.getType()).setStatus(CommonStatusEnum.ENABLE.getStatus())));
|
||||
// 测试 status 不匹配
|
||||
menuCache.put(4L, randomPojo(MenuDO.class, o -> o.setId(4L)
|
||||
.setType(MenuTypeEnum.MENU.getType()).setStatus(CommonStatusEnum.DISABLE.getStatus())));
|
||||
menuService.setMenuCache(menuCache);
|
||||
// 准备参数
|
||||
Collection<Long> menuIds = asList(1L, 3L, 4L);
|
||||
Collection<Integer> menuTypes = singletonList(MenuTypeEnum.MENU.getType());
|
||||
Collection<Integer> menusStatuses = singletonList(CommonStatusEnum.ENABLE.getStatus());
|
||||
|
||||
// 调用
|
||||
List<MenuDO> list = menuService.getMenuListFromCache(menuIds, menuTypes, menusStatuses);
|
||||
// 断言
|
||||
assertEquals(1, list.size());
|
||||
assertPojoEquals(menuDO, list.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMenuListByPermissionFromCache() {
|
||||
// mock 缓存
|
||||
Multimap<String, MenuDO> permissionMenuCache = LinkedListMultimap.create();
|
||||
// 可被匹配
|
||||
MenuDO menuDO01 = randomPojo(MenuDO.class, o -> o.setId(1L).setPermission("123"));
|
||||
permissionMenuCache.put(menuDO01.getPermission(), menuDO01);
|
||||
MenuDO menuDO02 = randomPojo(MenuDO.class, o -> o.setId(2L).setPermission("123"));
|
||||
permissionMenuCache.put(menuDO02.getPermission(), menuDO02);
|
||||
// 不可匹配
|
||||
permissionMenuCache.put("456", randomPojo(MenuDO.class, o -> o.setId(3L).setPermission("456")));
|
||||
menuService.setPermissionMenuCache(permissionMenuCache);
|
||||
// 准备参数
|
||||
String permission = "123";
|
||||
|
||||
// 调用
|
||||
List<MenuDO> list = menuService.getMenuListByPermissionFromCache(permission);
|
||||
// 断言
|
||||
assertEquals(2, list.size());
|
||||
assertPojoEquals(menuDO01, list.get(0));
|
||||
assertPojoEquals(menuDO02, list.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMenu() {
|
||||
// mock 数据
|
||||
|
@ -314,7 +202,7 @@ public class MenuServiceImplTest extends BaseDbUnitTest {
|
|||
@Test
|
||||
public void testValidateParentMenu_success() {
|
||||
// mock 数据
|
||||
MenuDO menuDO = createMenuDO(MenuTypeEnum.MENU, "parent", 0L);
|
||||
MenuDO menuDO = buildMenuDO(MenuTypeEnum.MENU, "parent", 0L);
|
||||
menuMapper.insert(menuDO);
|
||||
// 准备参数
|
||||
Long parentId = menuDO.getId();
|
||||
|
@ -340,7 +228,7 @@ public class MenuServiceImplTest extends BaseDbUnitTest {
|
|||
@Test
|
||||
public void testValidateParentMenu_parentTypeError() {
|
||||
// mock 数据
|
||||
MenuDO menuDO = createMenuDO(MenuTypeEnum.BUTTON, "parent", 0L);
|
||||
MenuDO menuDO = buildMenuDO(MenuTypeEnum.BUTTON, "parent", 0L);
|
||||
menuMapper.insert(menuDO);
|
||||
// 准备参数
|
||||
Long parentId = menuDO.getId();
|
||||
|
@ -353,7 +241,7 @@ public class MenuServiceImplTest extends BaseDbUnitTest {
|
|||
@Test
|
||||
public void testValidateMenu_success() {
|
||||
// mock 父子菜单
|
||||
MenuDO sonMenu = initParentAndSonMenu();
|
||||
MenuDO sonMenu = createParentAndSonMenu();
|
||||
// 准备参数
|
||||
Long parentId = sonMenu.getParentId();
|
||||
Long otherSonMenuId = randomLongId();
|
||||
|
@ -366,7 +254,7 @@ public class MenuServiceImplTest extends BaseDbUnitTest {
|
|||
@Test
|
||||
public void testValidateMenu_sonMenuNameDuplicate() {
|
||||
// mock 父子菜单
|
||||
MenuDO sonMenu = initParentAndSonMenu();
|
||||
MenuDO sonMenu = createParentAndSonMenu();
|
||||
// 准备参数
|
||||
Long parentId = sonMenu.getParentId();
|
||||
Long otherSonMenuId = randomLongId();
|
||||
|
@ -380,26 +268,26 @@ public class MenuServiceImplTest extends BaseDbUnitTest {
|
|||
// ====================== 初始化方法 ======================
|
||||
|
||||
/**
|
||||
* 构造父子菜单,返回子菜单
|
||||
* 插入父子菜单,返回子菜单
|
||||
*
|
||||
* @return 子菜单
|
||||
*/
|
||||
private MenuDO initParentAndSonMenu() {
|
||||
private MenuDO createParentAndSonMenu() {
|
||||
// 构造父子菜单
|
||||
MenuDO parentMenuDO = createMenuDO(MenuTypeEnum.MENU, "parent", ID_ROOT);
|
||||
MenuDO parentMenuDO = buildMenuDO(MenuTypeEnum.MENU, "parent", ID_ROOT);
|
||||
menuMapper.insert(parentMenuDO);
|
||||
// 构建子菜单
|
||||
MenuDO sonMenuDO = createMenuDO(MenuTypeEnum.MENU, "testSonName",
|
||||
MenuDO sonMenuDO = buildMenuDO(MenuTypeEnum.MENU, "testSonName",
|
||||
parentMenuDO.getParentId());
|
||||
menuMapper.insert(sonMenuDO);
|
||||
return sonMenuDO;
|
||||
}
|
||||
|
||||
private MenuDO createMenuDO(MenuTypeEnum type, String name, Long parentId) {
|
||||
return createMenuDO(type, name, parentId, randomCommonStatus());
|
||||
private MenuDO buildMenuDO(MenuTypeEnum type, String name, Long parentId) {
|
||||
return buildMenuDO(type, name, parentId, randomCommonStatus());
|
||||
}
|
||||
|
||||
private MenuDO createMenuDO(MenuTypeEnum type, String name, Long parentId, Integer status) {
|
||||
private MenuDO buildMenuDO(MenuTypeEnum type, String name, Long parentId, Integer status) {
|
||||
return randomPojo(MenuDO.class, o -> o.setId(null).setName(name).setParentId(parentId)
|
||||
.setType(type.getType()).setStatus(status));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue