Commit 495f121463febd9a0c7ce280444757277d090f0b

Authored by YunaiV
1 parent f87c4f75

完善 OAuth2OpenControllerTest 单元测试

yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java
... ... @@ -45,7 +45,7 @@ public class RandomUtils {
45 45 }
46 46 // 如果是 type、status 结尾的字段,返回 tinyint 范围
47 47 if (StrUtil.endWithAnyIgnoreCase(attributeMetadata.getAttributeName(),
48   - "type", "status", "category")) {
  48 + "type", "status", "category", "scope")) {
49 49 return RandomUtil.randomInt(0, TINYINT_MAX + 1);
50 50 }
51 51 return RandomUtil.randomInt();
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.java
... ... @@ -52,8 +52,6 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti
52 52 * 考虑到【本系统】暂时不想做的过于复杂,默认只有获取到 access token 之后,可以访问【本系统】管理后台的 /system-api/* 所有接口,除非手动添加 scope 控制。
53 53 * scope 的使用示例,可见 {@link OAuth2UserController} 类
54 54 *
55   - *
56   - *
57 55 * @author 芋道源码
58 56 */
59 57 @Api(tags = "管理后台 - OAuth2.0 授权")
... ... @@ -185,8 +183,7 @@ public class OAuth2OpenController {
185 183 // 0. 校验用户已经登录。通过 Spring Security 实现
186 184  
187 185 // 1. 获得 Client 客户端的信息
188   - OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientId, null,
189   - null, null, null);
  186 + OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientId);
190 187 // 2. 获得用户已经授权的信息
191 188 List<OAuth2ApproveDO> approves = oauth2ApproveService.getApproveList(getLoginUserId(), getUserType(), clientId);
192 189 // 拼接返回
... ... @@ -223,7 +220,6 @@ public class OAuth2OpenController {
223 220 @SuppressWarnings("unchecked")
224 221 Map<String, Boolean> scopes = JsonUtils.parseObject(scope, Map.class);
225 222 scopes = ObjectUtil.defaultIfNull(scopes, Collections.emptyMap());
226   - // TODO 芋艿:针对 approved + scopes 在看看 spring security 的实现
227 223 // 0. 校验用户已经登录。通过 Spring Security 实现
228 224  
229 225 // 1.1 校验 responseType 是否满足 code 或者 token 值
... ... @@ -262,7 +258,7 @@ public class OAuth2OpenController {
262 258 if (StrUtil.equalsAny(responseType, "token")) {
263 259 return OAuth2GrantTypeEnum.IMPLICIT;
264 260 }
265   - throw exception0(BAD_REQUEST.getCode(), "response_type 参数值允许 code 和 token");
  261 + throw exception0(BAD_REQUEST.getCode(), "response_type 参数值只允许 code 和 token");
266 262 }
267 263  
268 264 private String getImplicitGrantRedirect(Long userId, OAuth2ClientDO client,
... ... @@ -279,7 +275,7 @@ public class OAuth2OpenController {
279 275 private String getAuthorizationCodeRedirect(Long userId, OAuth2ClientDO client,
280 276 List<String> scopes, String redirectUri, String state) {
281 277 // 1. 创建 code 授权码
282   - String authorizationCode = oauth2GrantService.grantAuthorizationCodeForCode(userId,getUserType(), client.getClientId(), scopes,
  278 + String authorizationCode = oauth2GrantService.grantAuthorizationCodeForCode(userId, getUserType(), client.getClientId(), scopes,
283 279 redirectUri, state);
284 280 // 2. 拼接重定向的 URL
285 281 return OAuth2Utils.buildAuthorizationCodeRedirectUri(redirectUri, authorizationCode, state);
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenCheckTokenRespVO.java
... ... @@ -7,7 +7,7 @@ import lombok.AllArgsConstructor;
7 7 import lombok.Data;
8 8 import lombok.NoArgsConstructor;
9 9  
10   -import java.util.Set;
  10 +import java.util.List;
11 11  
12 12 @ApiModel("管理后台 - 【开放接口】校验令牌 Response VO")
13 13 @Data
... ... @@ -28,13 +28,13 @@ public class OAuth2OpenCheckTokenRespVO {
28 28 @ApiModelProperty(value = "客户端编号", required = true, example = "car")
29 29 private String clientId;
30 30 @ApiModelProperty(value = "授权范围", required = true, example = "user_info")
31   - private Set<String> scopes;
  31 + private List<String> scopes;
32 32  
33 33 @ApiModelProperty(value = "访问令牌", required = true, example = "tudou")
34 34 @JsonProperty("access_token")
35 35 private String accessToken;
36 36  
37 37 @ApiModelProperty(value = "过期时间", required = true, example = "1593092157", notes = "时间戳 / 1000,即单位:秒")
38   - @JsonProperty("exp")
39 38 private Long exp;
  39 +
40 40 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/util/oauth2/OAuth2Utils.java
... ... @@ -61,11 +61,13 @@ public class OAuth2Utils {
61 61 if (CollUtil.isNotEmpty(scopes)) {
62 62 vars.put("scope", buildScopeStr(scopes));
63 63 }
64   - for (String key : additionalInformation.keySet()) {
65   - Object value = additionalInformation.get(key);
66   - if (value != null) {
67   - keys.put("extra_" + key, key);
68   - vars.put("extra_" + key, value);
  64 + if (CollUtil.isNotEmpty(additionalInformation)) {
  65 + for (String key : additionalInformation.keySet()) {
  66 + Object value = additionalInformation.get(key);
  67 + if (value != null) {
  68 + keys.put("extra_" + key, key);
  69 + vars.put("extra_" + key, value);
  70 + }
69 71 }
70 72 }
71 73 // Do not include the refresh token (even if there is one)
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenControllerTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.system.controller.admin.oauth2;
  2 +
  3 +import cn.hutool.core.collection.ListUtil;
  4 +import cn.hutool.core.map.MapUtil;
  5 +import cn.iocoder.yudao.framework.common.core.KeyValue;
  6 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
  7 +import cn.iocoder.yudao.framework.common.exception.ErrorCode;
  8 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  9 +import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
  10 +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
  11 +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAccessTokenRespVO;
  12 +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenAuthorizeInfoRespVO;
  13 +import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.open.OAuth2OpenCheckTokenRespVO;
  14 +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
  15 +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ApproveDO;
  16 +import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
  17 +import cn.iocoder.yudao.module.system.enums.auth.OAuth2GrantTypeEnum;
  18 +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ApproveService;
  19 +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientService;
  20 +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2GrantService;
  21 +import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;
  22 +import org.assertj.core.util.Lists;
  23 +import org.junit.jupiter.api.Test;
  24 +import org.mockito.InjectMocks;
  25 +import org.mockito.Mock;
  26 +
  27 +import javax.servlet.http.HttpServletRequest;
  28 +import java.time.Duration;
  29 +import java.util.ArrayList;
  30 +import java.util.Date;
  31 +import java.util.LinkedHashMap;
  32 +import java.util.List;
  33 +
  34 +import static cn.iocoder.yudao.framework.common.util.collection.SetUtils.asSet;
  35 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.addTime;
  36 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
  37 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
  38 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  39 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
  40 +import static java.util.Arrays.asList;
  41 +import static org.junit.jupiter.api.Assertions.*;
  42 +import static org.mockito.ArgumentMatchers.eq;
  43 +import static org.mockito.ArgumentMatchers.isNull;
  44 +import static org.mockito.Mockito.mock;
  45 +import static org.mockito.Mockito.when;
  46 +
  47 +/**
  48 + * {@link OAuth2OpenController} 的单元测试
  49 + *
  50 + * @author 芋道源码
  51 + */
  52 +public class OAuth2OpenControllerTest extends BaseMockitoUnitTest {
  53 +
  54 + @InjectMocks
  55 + private OAuth2OpenController oauth2OpenController;
  56 +
  57 + @Mock
  58 + private OAuth2GrantService oauth2GrantService;
  59 + @Mock
  60 + private OAuth2ClientService oauth2ClientService;
  61 + @Mock
  62 + private OAuth2ApproveService oauth2ApproveService;
  63 + @Mock
  64 + private OAuth2TokenService oauth2TokenService;
  65 +
  66 + @Test
  67 + public void testPostAccessToken_authorizationCode() {
  68 + // 准备参数
  69 + String granType = OAuth2GrantTypeEnum.AUTHORIZATION_CODE.getGrantType();
  70 + String code = randomString();
  71 + String redirectUri = randomString();
  72 + String state = randomString();
  73 + HttpServletRequest request = mockRequest("test_client_id", "test_client_secret");
  74 + // mock 方法(client)
  75 + OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("test_client_id");
  76 + when(oauth2ClientService.validOAuthClientFromCache(eq("test_client_id"), eq("test_client_secret"), eq(granType), eq(new ArrayList<>()), eq(redirectUri))).thenReturn(client);
  77 +
  78 + // mock 方法(访问令牌)
  79 + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class)
  80 + .setExpiresTime(addTime(Duration.ofMillis(30010L))); // 多给 10 毫秒,保证可执行完
  81 + when(oauth2GrantService.grantAuthorizationCodeForAccessToken(eq("test_client_id"),
  82 + eq(code), eq(redirectUri), eq(state))).thenReturn(accessTokenDO);
  83 +
  84 + // 调用
  85 + CommonResult<OAuth2OpenAccessTokenRespVO> result = oauth2OpenController.postAccessToken(request, granType,
  86 + code, redirectUri, state, null, null, null, null);
  87 + // 断言
  88 + assertEquals(0, result.getCode());
  89 + assertPojoEquals(accessTokenDO, result.getData());
  90 + assertEquals(30L, result.getData().getExpiresIn()); // 执行过程会过去几毫秒
  91 + }
  92 +
  93 + @Test
  94 + public void testPostAccessToken_password() {
  95 + // 准备参数
  96 + String granType = OAuth2GrantTypeEnum.PASSWORD.getGrantType();
  97 + String username = randomString();
  98 + String password = randomString();
  99 + String scope = "write read";
  100 + HttpServletRequest request = mockRequest("test_client_id", "test_client_secret");
  101 + // mock 方法(client)
  102 + OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("test_client_id");
  103 + when(oauth2ClientService.validOAuthClientFromCache(eq("test_client_id"), eq("test_client_secret"),
  104 + eq(granType), eq(Lists.newArrayList("write", "read")), isNull())).thenReturn(client);
  105 +
  106 + // mock 方法(访问令牌)
  107 + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class)
  108 + .setExpiresTime(addTime(Duration.ofMillis(30010L))); // 多给 10 毫秒,保证可执行完
  109 + when(oauth2GrantService.grantPassword(eq(username), eq(password), eq("test_client_id"),
  110 + eq(Lists.newArrayList("write", "read")))).thenReturn(accessTokenDO);
  111 +
  112 + // 调用
  113 + CommonResult<OAuth2OpenAccessTokenRespVO> result = oauth2OpenController.postAccessToken(request, granType,
  114 + null, null, null, username, password, scope, null);
  115 + // 断言
  116 + assertEquals(0, result.getCode());
  117 + assertPojoEquals(accessTokenDO, result.getData());
  118 + assertEquals(30L, result.getData().getExpiresIn()); // 执行过程会过去几毫秒
  119 + }
  120 +
  121 + @Test
  122 + public void testPostAccessToken_refreshToken() {
  123 + // 准备参数
  124 + String granType = OAuth2GrantTypeEnum.REFRESH_TOKEN.getGrantType();
  125 + String refreshToken = randomString();
  126 + String password = randomString();
  127 + HttpServletRequest request = mockRequest("test_client_id", "test_client_secret");
  128 + // mock 方法(client)
  129 + OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("test_client_id");
  130 + when(oauth2ClientService.validOAuthClientFromCache(eq("test_client_id"), eq("test_client_secret"),
  131 + eq(granType), eq(Lists.newArrayList()), isNull())).thenReturn(client);
  132 +
  133 + // mock 方法(访问令牌)
  134 + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class)
  135 + .setExpiresTime(addTime(Duration.ofMillis(30010L))); // 多给 10 毫秒,保证可执行完
  136 + when(oauth2GrantService.grantRefreshToken(eq(refreshToken), eq("test_client_id"))).thenReturn(accessTokenDO);
  137 +
  138 + // 调用
  139 + CommonResult<OAuth2OpenAccessTokenRespVO> result = oauth2OpenController.postAccessToken(request, granType,
  140 + null, null, null, null, password, null, refreshToken);
  141 + // 断言
  142 + assertEquals(0, result.getCode());
  143 + assertPojoEquals(accessTokenDO, result.getData());
  144 + assertEquals(30L, result.getData().getExpiresIn()); // 执行过程会过去几毫秒
  145 + }
  146 +
  147 + @Test
  148 + public void testPostAccessToken_implicit() {
  149 + // 调用,并断言
  150 + assertServiceException(() -> oauth2OpenController.postAccessToken(null,
  151 + OAuth2GrantTypeEnum.IMPLICIT.getGrantType(), null, null, null,
  152 + null, null, null, null),
  153 + new ErrorCode(400, "Token 接口不支持 implicit 授权模式"));
  154 + }
  155 +
  156 + @Test
  157 + public void testRevokeToken() {
  158 + // 准备参数
  159 + HttpServletRequest request = mockRequest("demo_client_id", "demo_client_secret");
  160 + String token = randomString();
  161 + // mock 方法(client)
  162 + OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("demo_client_id");
  163 + when(oauth2ClientService.validOAuthClientFromCache(eq("demo_client_id"),
  164 + eq("demo_client_secret"), isNull(), isNull(), isNull())).thenReturn(client);
  165 + // mock 方法(移除)
  166 + when(oauth2GrantService.revokeToken(eq("demo_client_id"), eq(token))).thenReturn(true);
  167 +
  168 + // 调用
  169 + CommonResult<Boolean> result = oauth2OpenController.revokeToken(request, token);
  170 + // 断言
  171 + assertEquals(0, result.getCode());
  172 + assertTrue(result.getData());
  173 + }
  174 +
  175 + @Test
  176 + public void testCheckToken() {
  177 + // 准备参数
  178 + HttpServletRequest request = mockRequest("demo_client_id", "demo_client_secret");
  179 + String token = randomString();
  180 + // mock 方法
  181 + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class).setUserType(UserTypeEnum.ADMIN.getValue()).setExpiresTime(new Date(1653485731195L));
  182 + when(oauth2TokenService.checkAccessToken(eq(token))).thenReturn(accessTokenDO);
  183 +
  184 + // 调用
  185 + CommonResult<OAuth2OpenCheckTokenRespVO> result = oauth2OpenController.checkToken(request, token);
  186 + // 断言
  187 + assertEquals(0, result.getCode());
  188 + assertPojoEquals(accessTokenDO, result.getData());
  189 + assertEquals(1653485731L, result.getData().getExp()); // 执行过程会过去几毫秒
  190 + }
  191 +
  192 + @Test
  193 + public void testAuthorize() {
  194 + // 准备参数
  195 + String clientId = randomString();
  196 + // mock 方法(client)
  197 + OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId("demo_client_id").setScopes(ListUtil.toList("read", "write", "all"));
  198 + when(oauth2ClientService.validOAuthClientFromCache(eq(clientId))).thenReturn(client);
  199 + // mock 方法(approve)
  200 + List<OAuth2ApproveDO> approves = asList(
  201 + randomPojo(OAuth2ApproveDO.class).setScope("read").setApproved(true),
  202 + randomPojo(OAuth2ApproveDO.class).setScope("write").setApproved(false));
  203 + when(oauth2ApproveService.getApproveList(isNull(), eq(UserTypeEnum.ADMIN.getValue()), eq(clientId))).thenReturn(approves);
  204 +
  205 + // 调用
  206 + CommonResult<OAuth2OpenAuthorizeInfoRespVO> result = oauth2OpenController.authorize(clientId);
  207 + // 断言
  208 + assertEquals(0, result.getCode());
  209 + assertPojoEquals(client, result.getData().getClient());
  210 + assertEquals(new KeyValue<>("read", true), result.getData().getScopes().get(0));
  211 + assertEquals(new KeyValue<>("write", false), result.getData().getScopes().get(1));
  212 + assertEquals(new KeyValue<>("all", false), result.getData().getScopes().get(2));
  213 + }
  214 +
  215 + @Test
  216 + public void testApproveOrDeny_grantTypeError() {
  217 + // 调用,并断言
  218 + assertServiceException(() -> oauth2OpenController.approveOrDeny(randomString(), null,
  219 + null, null, null, null),
  220 + new ErrorCode(400, "response_type 参数值只允许 code 和 token"));
  221 + }
  222 +
  223 + @Test // autoApprove = true,但是不通过
  224 + public void testApproveOrDeny_autoApproveNo() {
  225 + // 准备参数
  226 + String responseType = "code";
  227 + String clientId = randomString();
  228 + String scope = "{\"read\": true, \"write\": false}";
  229 + String redirectUri = randomString();
  230 + String state = randomString();
  231 + // mock 方法
  232 + OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class);
  233 + when(oauth2ClientService.validOAuthClientFromCache(eq(clientId), isNull(), eq("authorization_code"),
  234 + eq(asSet("read", "write")), eq(redirectUri))).thenReturn(client);
  235 +
  236 + // 调用
  237 + CommonResult<String> result = oauth2OpenController.approveOrDeny(responseType, clientId,
  238 + scope, redirectUri, true, state);
  239 + // 断言
  240 + assertEquals(0, result.getCode());
  241 + assertNull(result.getData());
  242 + }
  243 +
  244 + @Test // autoApprove = false,但是不通过
  245 + public void testApproveOrDeny_ApproveNo() {
  246 + // 准备参数
  247 + String responseType = "token";
  248 + String clientId = randomString();
  249 + String scope = "{\"read\": true, \"write\": false}";
  250 + String redirectUri = "https://www.iocoder.cn";
  251 + String state = "test";
  252 + // mock 方法
  253 + OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class);
  254 + when(oauth2ClientService.validOAuthClientFromCache(eq(clientId), isNull(), eq("implicit"),
  255 + eq(asSet("read", "write")), eq(redirectUri))).thenReturn(client);
  256 +
  257 + // 调用
  258 + CommonResult<String> result = oauth2OpenController.approveOrDeny(responseType, clientId,
  259 + scope, redirectUri, false, state);
  260 + // 断言
  261 + assertEquals(0, result.getCode());
  262 + assertEquals("https://www.iocoder.cn#error=access_denied&error_description=User%20denied%20access&state=test", result.getData());
  263 + }
  264 +
  265 + @Test // autoApprove = true,通过 + token
  266 + public void testApproveOrDeny_autoApproveWithToken() {
  267 + // 准备参数
  268 + String responseType = "token";
  269 + String clientId = randomString();
  270 + String scope = "{\"read\": true, \"write\": false}";
  271 + String redirectUri = "https://www.iocoder.cn";
  272 + String state = "test";
  273 + // mock 方法(client)
  274 + OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId(clientId).setAdditionalInformation(null);
  275 + when(oauth2ClientService.validOAuthClientFromCache(eq(clientId), isNull(), eq("implicit"),
  276 + eq(asSet("read", "write")), eq(redirectUri))).thenReturn(client);
  277 + // mock 方法(场景一)
  278 + when(oauth2ApproveService.checkForPreApproval(isNull(), eq(UserTypeEnum.ADMIN.getValue()),
  279 + eq(clientId), eq(SetUtils.asSet("read", "write")))).thenReturn(true);
  280 + // mock 方法(访问令牌)
  281 + OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class)
  282 + .setAccessToken("test_access_token").setExpiresTime(addTime(Duration.ofMillis(30010L)));
  283 + when(oauth2GrantService.grantImplicit(isNull(), eq(UserTypeEnum.ADMIN.getValue()),
  284 + eq(clientId), eq(ListUtil.toList("read")))).thenReturn(accessTokenDO);
  285 +
  286 + // 调用
  287 + CommonResult<String> result = oauth2OpenController.approveOrDeny(responseType, clientId,
  288 + scope, redirectUri, true, state);
  289 + // 断言
  290 + assertEquals(0, result.getCode());
  291 + assertEquals("https://www.iocoder.cn#access_token=test_access_token&token_type=bearer&state=test&expires_in=30&scope=read", result.getData());
  292 + }
  293 +
  294 + @Test // autoApprove = false,通过 + code
  295 + public void testApproveOrDeny_approveWithCode() {
  296 + // 准备参数
  297 + String responseType = "code";
  298 + String clientId = randomString();
  299 + String scope = "{\"read\": true, \"write\": false}";
  300 + String redirectUri = "https://www.iocoder.cn";
  301 + String state = "test";
  302 + // mock 方法(client)
  303 + OAuth2ClientDO client = randomPojo(OAuth2ClientDO.class).setClientId(clientId).setAdditionalInformation(null);
  304 + when(oauth2ClientService.validOAuthClientFromCache(eq(clientId), isNull(), eq("authorization_code"),
  305 + eq(asSet("read", "write")), eq(redirectUri))).thenReturn(client);
  306 + // mock 方法(场景二)
  307 + when(oauth2ApproveService.updateAfterApproval(isNull(), eq(UserTypeEnum.ADMIN.getValue()), eq(clientId),
  308 + eq(MapUtil.builder(new LinkedHashMap<String, Boolean>()).put("read", true).put("write", false).build())))
  309 + .thenReturn(true);
  310 + // mock 方法(访问令牌)
  311 + String authorizationCode = "test_code";
  312 + when(oauth2GrantService.grantAuthorizationCodeForCode(isNull(), eq(UserTypeEnum.ADMIN.getValue()),
  313 + eq(clientId), eq(ListUtil.toList("read")), eq(redirectUri), eq(state))).thenReturn(authorizationCode);
  314 +
  315 + // 调用
  316 + CommonResult<String> result = oauth2OpenController.approveOrDeny(responseType, clientId,
  317 + scope, redirectUri, false, state);
  318 + // 断言
  319 + assertEquals(0, result.getCode());
  320 + assertEquals("https://www.iocoder.cn?code=test_code&state=test", result.getData());
  321 + }
  322 +
  323 + private HttpServletRequest mockRequest(String clientId, String secret) {
  324 + HttpServletRequest request = mock(HttpServletRequest.class);
  325 + when(request.getParameter(eq("client_id"))).thenReturn(clientId);
  326 + when(request.getParameter(eq("client_secret"))).thenReturn(secret);
  327 + return request;
  328 + }
  329 +
  330 +}
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceTest.java
... ... @@ -3,15 +3,17 @@ package cn.iocoder.yudao.module.system.service.permission;
3 3 import cn.hutool.core.util.RandomUtil;
4 4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6   -import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum;
  6 +import cn.iocoder.yudao.framework.common.util.date.DateUtils;
  7 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
7 8 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleCreateReqVO;
  9 +import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleExportReqVO;
8 10 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RolePageReqVO;
9 11 import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleUpdateReqVO;
10 12 import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
11 13 import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMapper;
  14 +import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum;
12 15 import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum;
13 16 import cn.iocoder.yudao.module.system.mq.producer.permission.RoleProducer;
14   -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
15 17 import org.junit.jupiter.api.Test;
16 18 import org.springframework.boot.test.mock.mockito.MockBean;
17 19 import org.springframework.context.annotation.Import;
... ... @@ -20,6 +22,7 @@ import javax.annotation.Resource;
20 22 import java.util.*;
21 23 import java.util.stream.Collectors;
22 24  
  25 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
23 26 import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.max;
24 27 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
25 28 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
... ... @@ -155,61 +158,66 @@ public class RoleServiceTest extends BaseDbUnitTest {
155 158 }
156 159  
157 160 @Test
158   - public void testGetRoles_success() {
159   - Map<Long, RoleDO> idRoleMap = new HashMap<>();
160   - // 验证查询状态为1的角色
161   - RoleDO roleDO1 = createRoleDO("role1", RoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 1);
162   - roleMapper.insert(roleDO1);
163   - idRoleMap.put(roleDO1.getId(), roleDO1);
164   -
165   - RoleDO roleDO2 = createRoleDO("role2", RoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 1);
166   - roleMapper.insert(roleDO2);
167   - idRoleMap.put(roleDO2.getId(), roleDO2);
168   -
169   - // 以下是排除的角色
170   - RoleDO roleDO3 = createRoleDO("role3", RoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 2);
171   - roleMapper.insert(roleDO3);
172   -
173   - //调用
174   - List<RoleDO> roles = roleService.getRoles(Arrays.asList(1));
175   -
176   - //断言
177   - assertEquals(2, roles.size());
178   - roles.stream().forEach(r -> assertPojoEquals(idRoleMap.get(r.getId()), r));
  161 + public void testGetRoles() {
  162 + // mock 数据
  163 + RoleDO dbRole = randomPojo(RoleDO.class, o -> { // 等会查询到
  164 + o.setName("土豆");
  165 + o.setCode("tudou");
  166 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  167 + o.setCreateTime(DateUtils.buildTime(2022, 2, 8));
  168 + });
  169 + roleMapper.insert(dbRole);
  170 + // 测试 name 不匹配
  171 + roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setName("红薯")));
  172 + // 测试 code 不匹配
  173 + roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setCode("hong")));
  174 + // 测试 createTime 不匹配
  175 + roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setCreateTime(DateUtils.buildTime(2022, 2, 16))));
  176 + // 准备参数
  177 + RoleExportReqVO reqVO = new RoleExportReqVO();
  178 + reqVO.setName("土豆");
  179 + reqVO.setCode("tu");
  180 + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
  181 + reqVO.setBeginTime(DateUtils.buildTime(2022, 2, 1));
  182 + reqVO.setEndTime(DateUtils.buildTime(2022, 2, 12));
179 183  
  184 + // 调用
  185 + List<RoleDO> list = roleService.getRoleList(reqVO);
  186 + // 断言
  187 + assertEquals(1, list.size());
  188 + assertPojoEquals(dbRole, list.get(0));
180 189 }
181 190  
182 191 @Test
183   - public void testGetRolePage_success() {
184   - Map<Long, RoleDO> idRoleMap = new HashMap<>();
185   - // 验证名称包含"role", 状态为1,code为"code"的角色
186   - // 第一页
187   - RoleDO roleDO = createRoleDO("role1", RoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 1, "code");
188   - roleMapper.insert(roleDO);
189   - idRoleMap.put(roleDO.getId(), roleDO);
190   - // 第二页
191   - roleDO = createRoleDO("role2", RoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 1, "code");
192   - roleMapper.insert(roleDO);
193   -
194   - // 以下是排除的角色
195   - roleDO = createRoleDO("role3", RoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 2, "code");
196   - roleMapper.insert(roleDO);
197   - roleDO = createRoleDO("role4", RoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 1, "xxxxx");
198   - roleMapper.insert(roleDO);
199   -
200   - //调用
201   - RolePageReqVO reqVO = randomPojo(RolePageReqVO.class, o -> {
202   - o.setName("role");
203   - o.setCode("code");
204   - o.setStatus(1);
205   - o.setPageNo(1);
206   - o.setPageSize(1);
207   - o.setBeginTime(null);
208   - o.setEndTime(null);
  192 + public void testGetRolePage() {
  193 + // mock 数据
  194 + RoleDO dbRole = randomPojo(RoleDO.class, o -> { // 等会查询到
  195 + o.setName("土豆");
  196 + o.setCode("tudou");
  197 + o.setStatus(CommonStatusEnum.ENABLE.getStatus());
  198 + o.setCreateTime(DateUtils.buildTime(2022, 2, 8));
209 199 });
210   - PageResult<RoleDO> result = roleService.getRolePage(reqVO);
211   - assertEquals(2, result.getTotal());
212   - result.getList().stream().forEach(r -> assertPojoEquals(idRoleMap.get(r.getId()), r));
  200 + roleMapper.insert(dbRole);
  201 + // 测试 name 不匹配
  202 + roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setName("红薯")));
  203 + // 测试 code 不匹配
  204 + roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setCode("hong")));
  205 + // 测试 createTime 不匹配
  206 + roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setCreateTime(DateUtils.buildTime(2022, 2, 16))));
  207 + // 准备参数
  208 + RolePageReqVO reqVO = new RolePageReqVO();
  209 + reqVO.setName("土豆");
  210 + reqVO.setCode("tu");
  211 + reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
  212 + reqVO.setBeginTime(DateUtils.buildTime(2022, 2, 1));
  213 + reqVO.setEndTime(DateUtils.buildTime(2022, 2, 12));
  214 +
  215 + // 调用
  216 + PageResult<RoleDO> pageResult = roleService.getRolePage(reqVO);
  217 + // 断言
  218 + assertEquals(1, pageResult.getTotal());
  219 + assertEquals(1, pageResult.getList().size());
  220 + assertPojoEquals(dbRole, pageResult.getList().get(0));
213 221 }
214 222  
215 223 @Test
... ...