This commit is contained in:
2026-08-04 13:32:24 +08:00
parent 434715b938
commit 694425690c
9 changed files with 197 additions and 138 deletions
@@ -37,6 +37,7 @@ class PlatformInternalUserContractTest {
@Test
void unifiedPlatformUserEndpointsKeepIndependentPermissions() throws Exception {
Method list = PlatformUserManagementController.class.getMethod("list",
long.class, long.class, String.class, String.class,
com.baiyue.common.security.AuthenticatedUser.class);
Method create = PlatformUserManagementController.class.getMethod("create",
com.baiyue.iam.dto.PlatformUserManagementDtos.CreateUserRequest.class,
@@ -1,19 +1,17 @@
package com.baiyue.iam.service;
import com.baiyue.common.core.api.ApiResponse;
import com.baiyue.common.core.api.PageResult;
import com.baiyue.common.core.exception.BizException;
import com.baiyue.iam.client.AuthAccountClient;
import com.baiyue.iam.dto.PlatformUserManagementDtos.*;
import com.baiyue.iam.entity.IamMembership;
import com.baiyue.iam.entity.IamRole;
import com.baiyue.iam.entity.IamTenant;
import com.baiyue.iam.entity.IamUser;
import com.baiyue.iam.mapper.IamRoleMapper;
import com.baiyue.iam.repository.MemberRepository;
import com.baiyue.iam.repository.TenantRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import java.time.LocalDateTime;
import java.util.List;
@@ -25,110 +23,89 @@ import static org.mockito.Mockito.*;
class PlatformUserManagementServiceTest {
private final MemberRepository members = mock(MemberRepository.class);
private final TenantRepository tenants = mock(TenantRepository.class);
private final IamRoleMapper roles = mock(IamRoleMapper.class);
private final AuthAccountClient auth = mock(AuthAccountClient.class);
private final PlatformUserManagementService service =
new PlatformUserManagementService(members, tenants, roles, auth, "internal-token");
private IamTenant merchant;
private IamRole merchantRole;
new PlatformUserManagementService(members, roles, auth, "internal-token");
private IamRole platformRole;
private IamMembership membership;
private IamUser user;
@BeforeEach
void setUp() {
merchant = new IamTenant();
merchant.setId(10001L); merchant.setTenantType("MERCHANT"); merchant.setTenantName("华远贸易");
merchant.setStatus("ACTIVE");
merchantRole = new IamRole();
merchantRole.setId(40001L); merchantRole.setTenantId(10001L); merchantRole.setAppCode("MERCHANT");
merchantRole.setRoleName("租户管理员"); merchantRole.setStatus("ACTIVE");
platformRole = new IamRole();
platformRole.setId(40001L); platformRole.setTenantId(0L); platformRole.setAppCode("PLATFORM");
platformRole.setRoleName("平台运营"); platformRole.setStatus("ACTIVE");
membership = new IamMembership();
membership.setId(30L); membership.setTenantId(10001L); membership.setUserId(20L);
membership.setMemberType("EMPLOYEE"); membership.setMemberNo("MEMBER-30"); membership.setStatus("ACTIVE");
membership.setId(30L); membership.setTenantId(0L); membership.setUserId(20L);
membership.setMemberType("EMPLOYEE"); membership.setMemberNo("PLATFORM-30"); membership.setStatus("ACTIVE");
user = new IamUser();
user.setId(20L); user.setAuthUserId(10L); user.setUserType("ENTERPRISE");
user.setId(20L); user.setAuthUserId(10L); user.setUserType("INTERNAL");
user.setDisplayName("张伟"); user.setPhone("13800138000"); user.setStatus("ACTIVE");
when(tenants.findTenant(10001L)).thenReturn(merchant);
when(tenants.listMerchants()).thenReturn(List.of(merchant));
when(roles.selectById(40001L)).thenReturn(merchantRole);
when(roles.selectList(any())).thenReturn(List.of(merchantRole));
when(roles.selectById(40001L)).thenReturn(platformRole);
when(roles.selectList(any())).thenReturn(List.of(platformRole));
when(members.findById(30L)).thenReturn(membership);
when(members.findUser(20L)).thenReturn(user);
when(members.findRoleIds(10001L, 30L)).thenReturn(List.of(40001L));
when(members.findRoleIds(0L, 30L)).thenReturn(List.of(40001L));
when(auth.summary("internal-token", 10L)).thenReturn(ApiResponse.success(
new AuthAccountClient.AccountSummary(10L, "zhangwei", "张伟", "ACTIVE",
LocalDateTime.of(2026, 6, 1, 10, 30), 10001L, 30L, "MERCHANT")));
LocalDateTime.of(2026, 6, 1, 10, 30), 0L, 30L, "PLATFORM")));
}
@Test
void listReturnsTenantRoleAndLastLoginForMerchantUser() {
when(members.findAll()).thenReturn(List.of(membership));
void pageReturnsOnlyRepositoryScopedPlatformUsersWithMetadata() {
when(members.pageByTenant(0L, 2, 10, "张", "ACTIVE"))
.thenReturn(new PageResult<>(List.of(membership), 2, 10, 21, 3));
UserResponse response = service.list().get(0);
PageResult<UserResponse> result = service.page(2, 10, "张", "ACTIVE");
UserResponse response = result.records().get(0);
assertEquals("zhangwei", response.username());
assertEquals("华远贸易", response.tenantName());
assertEquals(List.of("租户管理员"), response.roleNames());
assertEquals("平台", response.tenantName());
assertEquals(List.of("平台运营"), response.roleNames());
assertEquals(LocalDateTime.of(2026, 6, 1, 10, 30), response.lastLoginAt());
assertEquals(21, result.total());
verify(members).pageByTenant(0L, 2, 10, "张", "ACTIVE");
}
@Test
void createMerchantUserCreatesDisabledMerchantAccountAndMembership() {
when(auth.create(anyString(), any())).thenReturn(ApiResponse.success(
new AuthAccountClient.AccountSummary(99L, "newuser", "新用户", "DISABLED")));
when(auth.summary(anyString(), anyLong())).thenReturn(ApiResponse.success(
new AuthAccountClient.AccountSummary(99L, "newuser", "新用户", "DISABLED")));
when(members.findUser(anyLong())).thenReturn(user);
void createRejectsMerchantTenantBeforeCreatingAuthAccount() {
CreateUserRequest request = new CreateUserRequest("newuser", "新用户", "13900139000",
"new@example.com", 10001L, List.of(40001L), "Password1", "DISABLED");
service.create(request);
ArgumentCaptor<AuthAccountClient.CreateAccountRequest> account =
ArgumentCaptor.forClass(AuthAccountClient.CreateAccountRequest.class);
verify(auth).create(eq("internal-token"), account.capture());
assertEquals("MERCHANT", account.getValue().appCode());
assertEquals("DISABLED", account.getValue().accountStatus());
verify(members).insertUser(argThat(value -> "ENTERPRISE".equals(value.getUserType())));
verify(members).insert(argThat(value -> value.getTenantId() == 10001L
&& "DISABLED".equals(value.getStatus())));
assertThrows(BizException.class, () -> service.create(request));
verify(auth, never()).create(anyString(), any());
}
@Test
void tenantMoveUpdatesAuthScopeAndRolesWhenOperatorCanGrantRoles() {
IamTenant target = new IamTenant();
target.setId(10002L); target.setTenantType("MERCHANT"); target.setTenantName("深圳速达"); target.setStatus("ACTIVE");
IamRole targetRole = new IamRole();
targetRole.setId(40002L); targetRole.setTenantId(10002L); targetRole.setAppCode("MERCHANT");
targetRole.setRoleName("操作员"); targetRole.setStatus("ACTIVE");
when(tenants.findTenant(10002L)).thenReturn(target);
when(tenants.listMerchants()).thenReturn(List.of(merchant, target));
when(roles.selectById(40002L)).thenReturn(targetRole);
when(roles.selectList(any())).thenReturn(List.of(merchantRole, targetRole));
when(auth.scope(anyString(), anyLong(), any())).thenReturn(ApiResponse.success(null));
when(auth.profile(anyString(), anyLong(), any())).thenReturn(ApiResponse.success(null));
void optionsContainOnlyPlatformTenantAndPlatformRoles() {
UserOptions result = service.options();
assertEquals(List.of(new TenantOption(0L, "平台", "ACTIVE")), result.tenants());
assertEquals(1, result.roles().size());
assertEquals(0L, result.roles().get(0).tenantId());
verifyNoInteractions(members);
}
@Test
void updateRejectsMovingPlatformUserToMerchantTenant() {
UpdateUserRequest request = new UpdateUserRequest("张伟新", "13800138000", null,
10002L, List.of(40002L));
10002L, List.of(40001L));
UserResponse response = service.update(30L, request, Set.of("platform:user:grant-role"));
verify(auth).scope(eq("internal-token"), eq(10L),
argThat(value -> value.tenantId() == 10002L && "MERCHANT".equals(value.appCode())));
verify(members).replaceRoles(10001L, 30L, List.of());
verify(members).replaceRoles(10002L, 30L, List.of(40002L));
assertEquals(10002L, response.tenantId());
assertThrows(BizException.class,
() -> service.update(30L, request, Set.of("platform:user:grant-role")));
verify(auth, never()).scope(anyString(), anyLong(), any());
}
@Test
void tenantOrRoleChangeRequiresGrantRolePermission() {
IamRole otherRole = new IamRole();
otherRole.setId(40003L); otherRole.setTenantId(10001L); otherRole.setAppCode("MERCHANT");
otherRole.setId(40003L); otherRole.setTenantId(0L); otherRole.setAppCode("PLATFORM");
otherRole.setRoleName("操作员"); otherRole.setStatus("ACTIVE");
when(roles.selectById(40003L)).thenReturn(otherRole);
UpdateUserRequest request = new UpdateUserRequest("张伟", "13800138000", null,
10001L, List.of(40003L));
0L, List.of(40003L));
assertThrows(BizException.class, () -> service.update(30L, request, Set.of()));
verify(auth, never()).scope(anyString(), anyLong(), any());
@@ -143,7 +120,6 @@ class PlatformUserManagementServiceTest {
@Test
void builtInPlatformAdministratorCannotBeDisabled() {
membership.setTenantId(0L);
IamRole platformAdmin = new IamRole();
platformAdmin.setId(40000L); platformAdmin.setTenantId(0L); platformAdmin.setAppCode("PLATFORM");
platformAdmin.setRoleCode("PLATFORM_ADMIN"); platformAdmin.setRoleName("平台超级管理员");
@@ -155,4 +131,16 @@ class PlatformUserManagementServiceTest {
() -> service.changeStatus(30L, new ChangeStatusRequest("DISABLED"), 99L));
verify(auth, never()).status(anyString(), anyLong(), any());
}
@Test
void merchantMembershipCannotBeChangedThroughInternalUserEndpoints() {
membership.setTenantId(10001L);
assertThrows(BizException.class,
() -> service.changeStatus(30L, new ChangeStatusRequest("ACTIVE"), 99L));
assertThrows(BizException.class,
() -> service.resetPassword(30L, new ResetPasswordRequest("Password2")));
verify(auth, never()).status(anyString(), anyLong(), any());
verify(auth, never()).reset(anyString(), anyLong(), any());
}
}