diff --git a/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java b/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java index 935929e8d..d2703a0e7 100644 --- a/yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/util/RandomUtils.java +++ b/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 { } // 如果是 type、status 结尾的字段,返回 tinyint 范围 if (StrUtil.endWithAnyIgnoreCase(attributeMetadata.getAttributeName(), - "type", "status", "category")) { + "type", "status", "category", "scope")) { return RandomUtil.randomInt(0, TINYINT_MAX + 1); } return RandomUtil.randomInt(); diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.java index 2e7408aa1..96021f6e2 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.java +++ b/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 * 考虑到【本系统】暂时不想做的过于复杂,默认只有获取到 access token 之后,可以访问【本系统】管理后台的 /system-api/* 所有接口,除非手动添加 scope 控制。 * scope 的使用示例,可见 {@link OAuth2UserController} 类 * - * - * * @author 芋道源码 */ @Api(tags = "管理后台 - OAuth2.0 授权") @@ -185,8 +183,7 @@ public class OAuth2OpenController { // 0. 校验用户已经登录。通过 Spring Security 实现 // 1. 获得 Client 客户端的信息 - OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientId, null, - null, null, null); + OAuth2ClientDO client = oauth2ClientService.validOAuthClientFromCache(clientId); // 2. 获得用户已经授权的信息 List approves = oauth2ApproveService.getApproveList(getLoginUserId(), getUserType(), clientId); // 拼接返回 @@ -223,7 +220,6 @@ public class OAuth2OpenController { @SuppressWarnings("unchecked") Map scopes = JsonUtils.parseObject(scope, Map.class); scopes = ObjectUtil.defaultIfNull(scopes, Collections.emptyMap()); - // TODO 芋艿:针对 approved + scopes 在看看 spring security 的实现 // 0. 校验用户已经登录。通过 Spring Security 实现 // 1.1 校验 responseType 是否满足 code 或者 token 值 @@ -262,7 +258,7 @@ public class OAuth2OpenController { if (StrUtil.equalsAny(responseType, "token")) { 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, @@ -279,7 +275,7 @@ public class OAuth2OpenController { private String getAuthorizationCodeRedirect(Long userId, OAuth2ClientDO client, List scopes, String redirectUri, String state) { // 1. 创建 code 授权码 - String authorizationCode = oauth2GrantService.grantAuthorizationCodeForCode(userId,getUserType(), client.getClientId(), scopes, + String authorizationCode = oauth2GrantService.grantAuthorizationCodeForCode(userId, getUserType(), client.getClientId(), scopes, redirectUri, state); // 2. 拼接重定向的 URL return OAuth2Utils.buildAuthorizationCodeRedirectUri(redirectUri, authorizationCode, state); diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenCheckTokenRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenCheckTokenRespVO.java index b905e302b..f23838718 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/vo/open/OAuth2OpenCheckTokenRespVO.java +++ b/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; import lombok.Data; import lombok.NoArgsConstructor; -import java.util.Set; +import java.util.List; @ApiModel("管理后台 - 【开放接口】校验令牌 Response VO") @Data @@ -28,13 +28,13 @@ public class OAuth2OpenCheckTokenRespVO { @ApiModelProperty(value = "客户端编号", required = true, example = "car") private String clientId; @ApiModelProperty(value = "授权范围", required = true, example = "user_info") - private Set scopes; + private List scopes; @ApiModelProperty(value = "访问令牌", required = true, example = "tudou") @JsonProperty("access_token") private String accessToken; @ApiModelProperty(value = "过期时间", required = true, example = "1593092157", notes = "时间戳 / 1000,即单位:秒") - @JsonProperty("exp") private Long exp; + } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/util/oauth2/OAuth2Utils.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/util/oauth2/OAuth2Utils.java index 43617ddbe..815bb2c31 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/util/oauth2/OAuth2Utils.java +++ b/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 { if (CollUtil.isNotEmpty(scopes)) { vars.put("scope", buildScopeStr(scopes)); } - for (String key : additionalInformation.keySet()) { - Object value = additionalInformation.get(key); - if (value != null) { - keys.put("extra_" + key, key); - vars.put("extra_" + key, value); + if (CollUtil.isNotEmpty(additionalInformation)) { + for (String key : additionalInformation.keySet()) { + Object value = additionalInformation.get(key); + if (value != null) { + keys.put("extra_" + key, key); + vars.put("extra_" + key, value); + } } } // Do not include the refresh token (even if there is one) diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenControllerTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenControllerTest.java new file mode 100644 index 000000000..7720327e0 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenControllerTest.java @@ -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 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 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 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 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 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 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 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 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 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 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()).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 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; + } + +} diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceTest.java index 74ef697e3..b81777fb6 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceTest.java +++ b/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; import cn.hutool.core.util.RandomUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 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.RoleExportReqVO; 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.dal.dataobject.permission.RoleDO; 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.mq.producer.permission.RoleProducer; -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import org.junit.jupiter.api.Test; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; @@ -20,6 +22,7 @@ import javax.annotation.Resource; import java.util.*; 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.test.core.util.AssertUtils.assertPojoEquals; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; @@ -155,61 +158,66 @@ public class RoleServiceTest extends BaseDbUnitTest { } @Test - public void testGetRoles_success() { - Map idRoleMap = new HashMap<>(); - // 验证查询状态为1的角色 - RoleDO roleDO1 = createRoleDO("role1", RoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 1); - roleMapper.insert(roleDO1); - idRoleMap.put(roleDO1.getId(), roleDO1); - - RoleDO roleDO2 = createRoleDO("role2", RoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 1); - roleMapper.insert(roleDO2); - idRoleMap.put(roleDO2.getId(), roleDO2); - - // 以下是排除的角色 - RoleDO roleDO3 = createRoleDO("role3", RoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 2); - roleMapper.insert(roleDO3); - - //调用 - List roles = roleService.getRoles(Arrays.asList(1)); - - //断言 - assertEquals(2, roles.size()); - roles.stream().forEach(r -> assertPojoEquals(idRoleMap.get(r.getId()), r)); + public void testGetRoles() { + // mock 数据 + RoleDO dbRole = randomPojo(RoleDO.class, o -> { // 等会查询到 + o.setName("土豆"); + o.setCode("tudou"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setCreateTime(DateUtils.buildTime(2022, 2, 8)); + }); + roleMapper.insert(dbRole); + // 测试 name 不匹配 + roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setName("红薯"))); + // 测试 code 不匹配 + roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setCode("hong"))); + // 测试 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 list = roleService.getRoleList(reqVO); + // 断言 + assertEquals(1, list.size()); + assertPojoEquals(dbRole, list.get(0)); } @Test - public void testGetRolePage_success() { - Map idRoleMap = new HashMap<>(); - // 验证名称包含"role", 状态为1,code为"code"的角色 - // 第一页 - RoleDO roleDO = createRoleDO("role1", RoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 1, "code"); - roleMapper.insert(roleDO); - idRoleMap.put(roleDO.getId(), roleDO); - // 第二页 - roleDO = createRoleDO("role2", RoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 1, "code"); - roleMapper.insert(roleDO); - - // 以下是排除的角色 - roleDO = createRoleDO("role3", RoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 2, "code"); - roleMapper.insert(roleDO); - roleDO = createRoleDO("role4", RoleTypeEnum.CUSTOM, DataScopeEnum.ALL, 1, "xxxxx"); - roleMapper.insert(roleDO); - - //调用 - RolePageReqVO reqVO = randomPojo(RolePageReqVO.class, o -> { - o.setName("role"); - o.setCode("code"); - o.setStatus(1); - o.setPageNo(1); - o.setPageSize(1); - o.setBeginTime(null); - o.setEndTime(null); + public void testGetRolePage() { + // mock 数据 + RoleDO dbRole = randomPojo(RoleDO.class, o -> { // 等会查询到 + o.setName("土豆"); + o.setCode("tudou"); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setCreateTime(DateUtils.buildTime(2022, 2, 8)); }); - PageResult result = roleService.getRolePage(reqVO); - assertEquals(2, result.getTotal()); - result.getList().stream().forEach(r -> assertPojoEquals(idRoleMap.get(r.getId()), r)); + roleMapper.insert(dbRole); + // 测试 name 不匹配 + roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setName("红薯"))); + // 测试 code 不匹配 + roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setCode("hong"))); + // 测试 createTime 不匹配 + roleMapper.insert(cloneIgnoreId(dbRole, o -> o.setCreateTime(DateUtils.buildTime(2022, 2, 16)))); + // 准备参数 + 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)); + + // 调用 + PageResult pageResult = roleService.getRolePage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbRole, pageResult.getList().get(0)); } @Test