完善 OAuth2OpenControllerTest 单元测试

This commit is contained in:
YunaiV 2022-05-25 23:22:48 +08:00
parent f87c4f75e8
commit 495f121463
6 changed files with 404 additions and 68 deletions

View File

@ -45,7 +45,7 @@ public class RandomUtils {
} }
// 如果是 typestatus 结尾的字段返回 tinyint 范围 // 如果是 typestatus 结尾的字段返回 tinyint 范围
if (StrUtil.endWithAnyIgnoreCase(attributeMetadata.getAttributeName(), if (StrUtil.endWithAnyIgnoreCase(attributeMetadata.getAttributeName(),
"type", "status", "category")) { "type", "status", "category", "scope")) {
return RandomUtil.randomInt(0, TINYINT_MAX + 1); return RandomUtil.randomInt(0, TINYINT_MAX + 1);
} }
return RandomUtil.randomInt(); return RandomUtil.randomInt();

View File

@ -52,8 +52,6 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti
* 考虑到本系统暂时不想做的过于复杂默认只有获取到 access token 之后可以访问本系统管理后台的 /system-api/* 所有接口除非手动添加 scope 控制 * 考虑到本系统暂时不想做的过于复杂默认只有获取到 access token 之后可以访问本系统管理后台的 /system-api/* 所有接口除非手动添加 scope 控制
* scope 的使用示例可见 {@link OAuth2UserController} * scope 的使用示例可见 {@link OAuth2UserController}
* *
*
*
* @author 芋道源码 * @author 芋道源码
*/ */
@Api(tags = "管理后台 - OAuth2.0 授权") @Api(tags = "管理后台 - OAuth2.0 授权")
@ -185,8 +183,7 @@ public class OAuth2OpenController {
// 0. 校验用户已经登录通过 Spring Security 实现 // 0. 校验用户已经登录通过 Spring Security 实现
// 1. 获得 Client 客户端的信息 // 1. 获得 Client 客户端的信息
OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientId, null, OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientId);
null, null, null);
// 2. 获得用户已经授权的信息 // 2. 获得用户已经授权的信息
List<OAuth2ApproveDO> approves = oauth2ApproveService.getApproveList(getLoginUserId(), getUserType(), clientId); List<OAuth2ApproveDO> approves = oauth2ApproveService.getApproveList(getLoginUserId(), getUserType(), clientId);
// 拼接返回 // 拼接返回
@ -223,7 +220,6 @@ public class OAuth2OpenController {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Map<String, Boolean> scopes = JsonUtils.parseObject(scope, Map.class); Map<String, Boolean> scopes = JsonUtils.parseObject(scope, Map.class);
scopes = ObjectUtil.defaultIfNull(scopes, Collections.emptyMap()); scopes = ObjectUtil.defaultIfNull(scopes, Collections.emptyMap());
// TODO 芋艿针对 approved + scopes 在看看 spring security 的实现
// 0. 校验用户已经登录通过 Spring Security 实现 // 0. 校验用户已经登录通过 Spring Security 实现
// 1.1 校验 responseType 是否满足 code 或者 token // 1.1 校验 responseType 是否满足 code 或者 token
@ -262,7 +258,7 @@ public class OAuth2OpenController {
if (StrUtil.equalsAny(responseType, "token")) { if (StrUtil.equalsAny(responseType, "token")) {
return OAuth2GrantTypeEnum.IMPLICIT; return OAuth2GrantTypeEnum.IMPLICIT;
} }
throw exception0(BAD_REQUEST.getCode(), "response_type 参数值允许 code 和 token"); throw exception0(BAD_REQUEST.getCode(), "response_type 参数值允许 code 和 token");
} }
private String getImplicitGrantRedirect(Long userId, OAuth2ClientDO client, private String getImplicitGrantRedirect(Long userId, OAuth2ClientDO client,

View File

@ -7,7 +7,7 @@ import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.util.Set; import java.util.List;
@ApiModel("管理后台 - 【开放接口】校验令牌 Response VO") @ApiModel("管理后台 - 【开放接口】校验令牌 Response VO")
@Data @Data
@ -28,13 +28,13 @@ public class OAuth2OpenCheckTokenRespVO {
@ApiModelProperty(value = "客户端编号", required = true, example = "car") @ApiModelProperty(value = "客户端编号", required = true, example = "car")
private String clientId; private String clientId;
@ApiModelProperty(value = "授权范围", required = true, example = "user_info") @ApiModelProperty(value = "授权范围", required = true, example = "user_info")
private Set<String> scopes; private List<String> scopes;
@ApiModelProperty(value = "访问令牌", required = true, example = "tudou") @ApiModelProperty(value = "访问令牌", required = true, example = "tudou")
@JsonProperty("access_token") @JsonProperty("access_token")
private String accessToken; private String accessToken;
@ApiModelProperty(value = "过期时间", required = true, example = "1593092157", notes = "时间戳 / 1000即单位") @ApiModelProperty(value = "过期时间", required = true, example = "1593092157", notes = "时间戳 / 1000即单位")
@JsonProperty("exp")
private Long exp; private Long exp;
} }

View File

@ -61,6 +61,7 @@ public class OAuth2Utils {
if (CollUtil.isNotEmpty(scopes)) { if (CollUtil.isNotEmpty(scopes)) {
vars.put("scope", buildScopeStr(scopes)); vars.put("scope", buildScopeStr(scopes));
} }
if (CollUtil.isNotEmpty(additionalInformation)) {
for (String key : additionalInformation.keySet()) { for (String key : additionalInformation.keySet()) {
Object value = additionalInformation.get(key); Object value = additionalInformation.get(key);
if (value != null) { if (value != null) {
@ -68,6 +69,7 @@ public class OAuth2Utils {
vars.put("extra_" + key, value); vars.put("extra_" + key, value);
} }
} }
}
// Do not include the refresh token (even if there is one) // Do not include the refresh token (even if there is one)
return HttpUtils.append(redirectUri, vars, keys, true); return HttpUtils.append(redirectUri, vars, keys, true);
} }

View File

@ -0,0 +1,330 @@
package cn.iocoder.yudao.module.system.controller.admin.oauth2;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAccessTokenRespVO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAuthorizeInfoRespVO;
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenCheckTokenRespVO;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ApproveDO;
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
import cn.iocoder.yudao.module.system.enums.auth.OAuth2GrantTypeEnum;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ApproveService;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientService;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2GrantService;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;
import org.assertj.core.util.Lists;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import javax.servlet.http.HttpServletRequest;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
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.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.randomPojo;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
import static java.util.Arrays.asList;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* {@link OAuth2OpenController} 的单元测试
*
* @author 芋道源码
*/
public class OAuth2OpenControllerTest extends BaseMockitoUnitTest {
@InjectMocks
private OAuth2OpenController oauth2OpenController;
@Mock
private OAuth2GrantService oauth2GrantService;
@Mock
private OAuth2ClientService oauth2ClientService;
@Mock
private OAuth2ApproveService oauth2ApproveService;
@Mock
private OAuth2TokenService oauth2TokenService;
@Test
public void testPostAccessToken_authorizationCode() {
// 准备参数
String granType = OAuth2GrantTypeEnum.AUTHORIZATION_CODE.getGrantType();
String code = randomString();
String redirectUri = randomString();
String state = randomString();
HttpServletRequest request = mockRequest("test_client_id", "test_client_secret");
// mock 方法client
OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("test_client_id");
when(oauth2ClientService.validOAuthClientFromCache(eq("test_client_id"), eq("test_client_secret"), eq(granType), eq(new ArrayList<>()), eq(redirectUri))).thenReturn(client);
// mock 方法访问令牌
OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class)
.setExpiresTime(addTime(Duration.ofMillis(30010L))); // 多给 10 毫秒保证可执行完
when(oauth2GrantService.grantAuthorizationCodeForAccessToken(eq("test_client_id"),
eq(code), eq(redirectUri), eq(state))).thenReturn(accessTokenDO);
// 调用
CommonResult<OAuth2OpenAccessTokenRespVO> result = oauth2OpenController.postAccessToken(request, granType,
code, redirectUri, state, null, null, null, null);
// 断言
assertEquals(0, result.getCode());
assertPojoEquals(accessTokenDO, result.getData());
assertEquals(30L, result.getData().getExpiresIn()); // 执行过程会过去几毫秒
}
@Test
public void testPostAccessToken_password() {
// 准备参数
String granType = OAuth2GrantTypeEnum.PASSWORD.getGrantType();
String username = randomString();
String password = randomString();
String scope = "write read";
HttpServletRequest request = mockRequest("test_client_id", "test_client_secret");
// mock 方法client
OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("test_client_id");
when(oauth2ClientService.validOAuthClientFromCache(eq("test_client_id"), eq("test_client_secret"),
eq(granType), eq(Lists.newArrayList("write", "read")), isNull())).thenReturn(client);
// mock 方法访问令牌
OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class)
.setExpiresTime(addTime(Duration.ofMillis(30010L))); // 多给 10 毫秒保证可执行完
when(oauth2GrantService.grantPassword(eq(username), eq(password), eq("test_client_id"),
eq(Lists.newArrayList("write", "read")))).thenReturn(accessTokenDO);
// 调用
CommonResult<OAuth2OpenAccessTokenRespVO> result = oauth2OpenController.postAccessToken(request, granType,
null, null, null, username, password, scope, null);
// 断言
assertEquals(0, result.getCode());
assertPojoEquals(accessTokenDO, result.getData());
assertEquals(30L, result.getData().getExpiresIn()); // 执行过程会过去几毫秒
}
@Test
public void testPostAccessToken_refreshToken() {
// 准备参数
String granType = OAuth2GrantTypeEnum.REFRESH_TOKEN.getGrantType();
String refreshToken = randomString();
String password = randomString();
HttpServletRequest request = mockRequest("test_client_id", "test_client_secret");
// mock 方法client
OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("test_client_id");
when(oauth2ClientService.validOAuthClientFromCache(eq("test_client_id"), eq("test_client_secret"),
eq(granType), eq(Lists.newArrayList()), isNull())).thenReturn(client);
// mock 方法访问令牌
OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class)
.setExpiresTime(addTime(Duration.ofMillis(30010L))); // 多给 10 毫秒保证可执行完
when(oauth2GrantService.grantRefreshToken(eq(refreshToken), eq("test_client_id"))).thenReturn(accessTokenDO);
// 调用
CommonResult<OAuth2OpenAccessTokenRespVO> result = oauth2OpenController.postAccessToken(request, granType,
null, null, null, null, password, null, refreshToken);
// 断言
assertEquals(0, result.getCode());
assertPojoEquals(accessTokenDO, result.getData());
assertEquals(30L, result.getData().getExpiresIn()); // 执行过程会过去几毫秒
}
@Test
public void testPostAccessToken_implicit() {
// 调用并断言
assertServiceException(() -> oauth2OpenController.postAccessToken(null,
OAuth2GrantTypeEnum.IMPLICIT.getGrantType(), null, null, null,
null, null, null, null),
new ErrorCode(400, "Token 接口不支持 implicit 授权模式"));
}
@Test
public void testRevokeToken() {
// 准备参数
HttpServletRequest request = mockRequest("demo_client_id", "demo_client_secret");
String token = randomString();
// mock 方法client
OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("demo_client_id");
when(oauth2ClientService.validOAuthClientFromCache(eq("demo_client_id"),
eq("demo_client_secret"), isNull(), isNull(), isNull())).thenReturn(client);
// mock 方法移除
when(oauth2GrantService.revokeToken(eq("demo_client_id"), eq(token))).thenReturn(true);
// 调用
CommonResult<Boolean> result = oauth2OpenController.revokeToken(request, token);
// 断言
assertEquals(0, result.getCode());
assertTrue(result.getData());
}
@Test
public void testCheckToken() {
// 准备参数
HttpServletRequest request = mockRequest("demo_client_id", "demo_client_secret");
String token = randomString();
// mock 方法
OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class).setUserType(UserTypeEnum.ADMIN.getValue()).setExpiresTime(new Date(1653485731195L));
when(oauth2TokenService.checkAccessToken(eq(token))).thenReturn(accessTokenDO);
// 调用
CommonResult<OAuth2OpenCheckTokenRespVO> result = oauth2OpenController.checkToken(request, token);
// 断言
assertEquals(0, result.getCode());
assertPojoEquals(accessTokenDO, result.getData());
assertEquals(1653485731L, result.getData().getExp()); // 执行过程会过去几毫秒
}
@Test
public void testAuthorize() {
// 准备参数
String clientId = randomString();
// mock 方法client
OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("demo_client_id").setScopes(ListUtil.toList("read", "write", "all"));
when(oauth2ClientService.validOAuthClientFromCache(eq(clientId))).thenReturn(client);
// mock 方法approve
List<OAuth2ApproveDO> approves = asList(
randomPojo(OAuth2ApproveDO.class).setScope("read").setApproved(true),
randomPojo(OAuth2ApproveDO.class).setScope("write").setApproved(false));
when(oauth2ApproveService.getApproveList(isNull(), eq(UserTypeEnum.ADMIN.getValue()), eq(clientId))).thenReturn(approves);
// 调用
CommonResult<OAuth2OpenAuthorizeInfoRespVO> result = oauth2OpenController.authorize(clientId);
// 断言
assertEquals(0, result.getCode());
assertPojoEquals(client, result.getData().getClient());
assertEquals(new KeyValue<>("read", true), result.getData().getScopes().get(0));
assertEquals(new KeyValue<>("write", false), result.getData().getScopes().get(1));
assertEquals(new KeyValue<>("all", false), result.getData().getScopes().get(2));
}
@Test
public void testApproveOrDeny_grantTypeError() {
// 调用并断言
assertServiceException(() -> oauth2OpenController.approveOrDeny(randomString(), null,
null, null, null, null),
new ErrorCode(400, "response_type 参数值只允许 code 和 token"));
}
@Test // autoApprove = true但是不通过
public void testApproveOrDeny_autoApproveNo() {
// 准备参数
String responseType = "code";
String clientId = randomString();
String scope = "{\"read\": true, \"write\": false}";
String redirectUri = randomString();
String state = randomString();
// mock 方法
OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class);
when(oauth2ClientService.validOAuthClientFromCache(eq(clientId), isNull(), eq("authorization_code"),
eq(asSet("read", "write")), eq(redirectUri))).thenReturn(client);
// 调用
CommonResult<String> result = oauth2OpenController.approveOrDeny(responseType, clientId,
scope, redirectUri, true, state);
// 断言
assertEquals(0, result.getCode());
assertNull(result.getData());
}
@Test // autoApprove = false但是不通过
public void testApproveOrDeny_ApproveNo() {
// 准备参数
String responseType = "token";
String clientId = randomString();
String scope = "{\"read\": true, \"write\": false}";
String redirectUri = "https://www.iocoder.cn";
String state = "test";
// mock 方法
OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class);
when(oauth2ClientService.validOAuthClientFromCache(eq(clientId), isNull(), eq("implicit"),
eq(asSet("read", "write")), eq(redirectUri))).thenReturn(client);
// 调用
CommonResult<String> result = oauth2OpenController.approveOrDeny(responseType, clientId,
scope, redirectUri, false, state);
// 断言
assertEquals(0, result.getCode());
assertEquals("https://www.iocoder.cn#error=access_denied&error_description=User%20denied%20access&state=test", result.getData());
}
@Test // autoApprove = true通过 + token
public void testApproveOrDeny_autoApproveWithToken() {
// 准备参数
String responseType = "token";
String clientId = randomString();
String scope = "{\"read\": true, \"write\": false}";
String redirectUri = "https://www.iocoder.cn";
String state = "test";
// mock 方法client)
OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId(clientId).setAdditionalInformation(null);
when(oauth2ClientService.validOAuthClientFromCache(eq(clientId), isNull(), eq("implicit"),
eq(asSet("read", "write")), eq(redirectUri))).thenReturn(client);
// mock 方法场景一
when(oauth2ApproveService.checkForPreApproval(isNull(), eq(UserTypeEnum.ADMIN.getValue()),
eq(clientId), eq(SetUtils.asSet("read", "write")))).thenReturn(true);
// mock 方法访问令牌
OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class)
.setAccessToken("test_access_token").setExpiresTime(addTime(Duration.ofMillis(30010L)));
when(oauth2GrantService.grantImplicit(isNull(), eq(UserTypeEnum.ADMIN.getValue()),
eq(clientId), eq(ListUtil.toList("read")))).thenReturn(accessTokenDO);
// 调用
CommonResult<String> result = oauth2OpenController.approveOrDeny(responseType, clientId,
scope, redirectUri, true, state);
// 断言
assertEquals(0, result.getCode());
assertEquals("https://www.iocoder.cn#access_token=test_access_token&token_type=bearer&state=test&expires_in=30&scope=read", result.getData());
}
@Test // autoApprove = false通过 + code
public void testApproveOrDeny_approveWithCode() {
// 准备参数
String responseType = "code";
String clientId = randomString();
String scope = "{\"read\": true, \"write\": false}";
String redirectUri = "https://www.iocoder.cn";
String state = "test";
// mock 方法client)
OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId(clientId).setAdditionalInformation(null);
when(oauth2ClientService.validOAuthClientFromCache(eq(clientId), isNull(), eq("authorization_code"),
eq(asSet("read", "write")), eq(redirectUri))).thenReturn(client);
// mock 方法场景二
when(oauth2ApproveService.updateAfterApproval(isNull(), eq(UserTypeEnum.ADMIN.getValue()), eq(clientId),
eq(MapUtil.builder(new LinkedHashMap<String, Boolean>()).put("read", true).put("write", false).build())))
.thenReturn(true);
// mock 方法访问令牌
String authorizationCode = "test_code";
when(oauth2GrantService.grantAuthorizationCodeForCode(isNull(), eq(UserTypeEnum.ADMIN.getValue()),
eq(clientId), eq(ListUtil.toList("read")), eq(redirectUri), eq(state))).thenReturn(authorizationCode);
// 调用
CommonResult<String> result = oauth2OpenController.approveOrDeny(responseType, clientId,
scope, redirectUri, false, state);
// 断言
assertEquals(0, result.getCode());
assertEquals("https://www.iocoder.cn?code=test_code&state=test", result.getData());
}
private HttpServletRequest mockRequest(String clientId, String secret) {
HttpServletRequest request = mock(HttpServletRequest.class);
when(request.getParameter(eq("client_id"))).thenReturn(clientId);
when(request.getParameter(eq("client_secret"))).thenReturn(secret);
return request;
}
}

View File

@ -3,15 +3,17 @@ package cn.iocoder.yudao.module.system.service.permission;
import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.RandomUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum; import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleCreateReqVO; import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleCreateReqVO;
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleExportReqVO;
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RolePageReqVO; import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RolePageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleUpdateReqVO; import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleUpdateReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMapper; import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMapper;
import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum;
import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum; import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum;
import cn.iocoder.yudao.module.system.mq.producer.permission.RoleProducer; import cn.iocoder.yudao.module.system.mq.producer.permission.RoleProducer;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
@ -20,6 +22,7 @@ import javax.annotation.Resource;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
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.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.assertPojoEquals;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
@ -155,61 +158,66 @@ public class RoleServiceTest extends BaseDbUnitTest {
} }
@Test @Test
public void testGetRoles_success() { public void testGetRoles() {
Map<Long, RoleDO> idRoleMap = new HashMap<>(); // mock 数据
// 验证查询状态为1的角色 RoleDO dbRole = randomPojo(RoleDO.class, o -> { // 等会查询到
RoleDO roleDO1 = createRoleDO("role1", RoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 1); o.setName("土豆");
roleMapper.insert(roleDO1); o.setCode("tudou");
idRoleMap.put(roleDO1.getId(), roleDO1); o.setStatus(CommonStatusEnum.ENABLE.getStatus());
o.setCreateTime(DateUtils.buildTime(2022, 2, 8));
RoleDO roleDO2 = createRoleDO("role2", RoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 1); });
roleMapper.insert(roleDO2); roleMapper.insert(dbRole);
idRoleMap.put(roleDO2.getId(), roleDO2); // 测试 name 不匹配
roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setName("红薯")));
// 以下是排除的角色 // 测试 code 不匹配
RoleDO roleDO3 = createRoleDO("role3", RoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 2); roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setCode("hong")));
roleMapper.insert(roleDO3); // 测试 createTime 不匹配
roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setCreateTime(DateUtils.buildTime(2022, 2, 16))));
// 准备参数
RoleExportReqVO reqVO = new RoleExportReqVO();
reqVO.setName("土豆");
reqVO.setCode("tu");
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
reqVO.setBeginTime(DateUtils.buildTime(2022, 2, 1));
reqVO.setEndTime(DateUtils.buildTime(2022, 2, 12));
// 调用 // 调用
List<RoleDO> roles = roleService.getRoles(Arrays.asList(1)); List<RoleDO> list = roleService.getRoleList(reqVO);
// 断言 // 断言
assertEquals(2, roles.size()); assertEquals(1, list.size());
roles.stream().forEach(r -> assertPojoEquals(idRoleMap.get(r.getId()), r)); assertPojoEquals(dbRole, list.get(0));
} }
@Test @Test
public void testGetRolePage_success() { public void testGetRolePage() {
Map<Long, RoleDO> idRoleMap = new HashMap<>(); // mock 数据
// 验证名称包含"role", 状态为1,code为"code"的角色 RoleDO dbRole = randomPojo(RoleDO.class, o -> { // 等会查询到
// 第一页 o.setName("土豆");
RoleDO roleDO = createRoleDO("role1", RoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 1, "code"); o.setCode("tudou");
roleMapper.insert(roleDO); o.setStatus(CommonStatusEnum.ENABLE.getStatus());
idRoleMap.put(roleDO.getId(), roleDO); o.setCreateTime(DateUtils.buildTime(2022, 2, 8));
// 第二页 });
roleDO = createRoleDO("role2", RoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 1, "code"); roleMapper.insert(dbRole);
roleMapper.insert(roleDO); // 测试 name 不匹配
roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setName("红薯")));
// 以下是排除的角色 // 测试 code 不匹配
roleDO = createRoleDO("role3", RoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 2, "code"); roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setCode("hong")));
roleMapper.insert(roleDO); // 测试 createTime 不匹配
roleDO = createRoleDO("role4", RoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 1, "xxxxx"); roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setCreateTime(DateUtils.buildTime(2022, 2, 16))));
roleMapper.insert(roleDO); // 准备参数
RolePageReqVO reqVO = new RolePageReqVO();
reqVO.setName("土豆");
reqVO.setCode("tu");
reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
reqVO.setBeginTime(DateUtils.buildTime(2022, 2, 1));
reqVO.setEndTime(DateUtils.buildTime(2022, 2, 12));
// 调用 // 调用
RolePageReqVO reqVO = randomPojo(RolePageReqVO.class, o -> { PageResult<RoleDO> pageResult = roleService.getRolePage(reqVO);
o.setName("role"); // 断言
o.setCode("code"); assertEquals(1, pageResult.getTotal());
o.setStatus(1); assertEquals(1, pageResult.getList().size());
o.setPageNo(1); assertPojoEquals(dbRole, pageResult.getList().get(0));
o.setPageSize(1);
o.setBeginTime(null);
o.setEndTime(null);
});
PageResult<RoleDO> result = roleService.getRolePage(reqVO);
assertEquals(2, result.getTotal());
result.getList().stream().forEach(r -> assertPojoEquals(idRoleMap.get(r.getId()), r));
} }
@Test @Test