package jnpf.dmsService; import jnpf.dmsEntity.permission.entity.DmsFilePermissionEntity; import jnpf.dmsEntity.permission.enums.DmsResourceType; import jnpf.dmsEntity.permission.model.DmsResourcePath; import jnpf.dmsEntity.permission.vo.DmsCursorPageVO; import jnpf.dmsEntity.permission.vo.DmsPermissionGrantVO; import jnpf.dmsMapper.DmsFilePermissionMapper; import jnpf.dmsMapper.DmsPermissionGroupMapper; import jnpf.dmsMapper.DmsPermissionUsageMapper; import jnpf.dmsPermission.DmsCurrentIdentity; import jnpf.dmsPermission.DmsCursorCodec; import jnpf.dmsPermission.DmsPermissionMatcher; import jnpf.dmsPermission.DmsPermissionProperties; import jnpf.dmsPermission.DmsResourceResolver; import jnpf.dmsPermission.DmsUserDisplayNameResolver; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; import jnpf.dmsEntity.permission.enums.DmsPrincipalType; import jnpf.permission.PositionApi; import jnpf.permission.RoleApi; import jnpf.permission.entity.PositionEntity; import jnpf.permission.entity.RoleEntity; import jnpf.permission.entity.PermissionGroupEntity; import java.util.ArrayList; import java.util.function.Function; import jnpf.permission.OrganizeApi; import jnpf.permission.entity.OrganizeEntity; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.UUID; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; class DmsPermissionAdminQueryServiceTest { private static final String TENANT_ID = "tenant-1"; private static final String USER_ID = "user-1"; @Test void enrichesGrantPageUserNames() { Fixture fixture = new Fixture(); DmsFilePermissionEntity permission = permission(UUID.randomUUID()); when(fixture.permissionMapper.selectPage(TENANT_ID, null, null, null, null, null, 11)) .thenReturn(Collections.singletonList(permission)); when(fixture.grantService.toVO(permission)).thenReturn(toVO(permission)); when(fixture.userDisplayNameResolver.resolve(any())) .thenReturn(Collections.singletonMap(USER_ID, "运营用户(yunying1)")); DmsCursorPageVO result = fixture.service.grants( null, null, null, null, 10); assertEquals(1, result.getList().size()); assertEquals("运营用户(yunying1)", result.getList().get(0).getPrincipalName()); verify(fixture.userDisplayNameResolver).resolve(any()); verifyNoInteractions(fixture.organizeApi, fixture.positionApi, fixture.roleApi, fixture.permissionGroupMapper); } @Test void enrichesGrantDetailUserName() { Fixture fixture = new Fixture(); DmsFilePermissionEntity permission = permission(UUID.randomUUID()); when(fixture.permissionMapper.selectByTenantAndId(TENANT_ID, permission.getId())) .thenReturn(permission); when(fixture.grantService.toVO(permission)).thenReturn(toVO(permission)); when(fixture.userDisplayNameResolver.resolve(any())) .thenReturn(Collections.singletonMap(USER_ID, "运营用户(yunying1)")); DmsPermissionGrantVO result = fixture.service.grant(permission.getId()); assertEquals("运营用户(yunying1)", result.getPrincipalName()); verify(fixture.userDisplayNameResolver).resolve(any()); verifyNoInteractions(fixture.organizeApi, fixture.positionApi, fixture.roleApi, fixture.permissionGroupMapper); } @Test void enrichesDirectAndInheritedUserGrantsWithOneResolverCall() { Fixture fixture = new Fixture(); UUID selectedResourceId = UUID.randomUUID(); UUID ancestorResourceId = UUID.randomUUID(); DmsResourcePath path = new DmsResourcePath(); path.setActualResourceId(selectedResourceId); path.setActualResourceType("FOLDER"); List candidateIds = Arrays.asList(selectedResourceId, ancestorResourceId); DmsFilePermissionEntity direct = permission(selectedResourceId); DmsFilePermissionEntity inherited = permission(ancestorResourceId); when(fixture.resourceResolver.resolve(TENANT_ID, DmsResourceType.FOLDER, selectedResourceId)) .thenReturn(path); when(fixture.resourceResolver.candidateResourceIds(path)).thenReturn(candidateIds); when(fixture.permissionMapper.selectForResourceIds(TENANT_ID, candidateIds, 1000)) .thenReturn(Arrays.asList(direct, inherited)); when(fixture.matcher.coversResource(any(), any())).thenReturn(true); when(fixture.grantService.toVO(any())).thenAnswer(invocation -> toVO(invocation.getArgument(0))); when(fixture.userDisplayNameResolver.resolve(any())) .thenReturn(Collections.singletonMap(USER_ID, "运营用户(yunying1)")); List result = fixture.service.resourceGrants( DmsResourceType.FOLDER, selectedResourceId); assertEquals(2, result.size()); assertFalse(result.get(0).isInherited()); assertTrue(result.get(1).isInherited()); assertEquals("运营用户(yunying1)", result.get(0).getPrincipalName()); assertEquals("运营用户(yunying1)", result.get(1).getPrincipalName()); verify(fixture.userDisplayNameResolver).resolve(any()); verifyNoInteractions(fixture.organizeApi, fixture.positionApi, fixture.roleApi, fixture.permissionGroupMapper); } @Test void enrichesOrganizationPageAndDetail() { Fixture fixture = new Fixture(); DmsFilePermissionEntity permission = organizationPermission(UUID.randomUUID()); when(fixture.permissionMapper.selectPage(TENANT_ID, null, null, null, null, null, 11)) .thenReturn(Collections.singletonList(permission)); when(fixture.permissionMapper.selectByTenantAndId(TENANT_ID, permission.getId())).thenReturn(permission); when(fixture.grantService.toVO(permission)).thenAnswer(invocation -> toVO(permission)); when(fixture.organizeApi.getListByIds(Collections.singletonList("org-1"))) .thenReturn(Collections.singletonList(organization("org-1", "质量部"))); assertEquals("质量部", fixture.service.grants(null, null, null, null, 10) .getList().get(0).getPrincipalName()); assertEquals("质量部", fixture.service.grant(permission.getId()).getPrincipalName()); } @Test void batchesDirectAndInheritedOrganizationsWithoutOverwritingUserWithSameId() { Fixture fixture = new Fixture(); UUID selectedId = UUID.randomUUID(); UUID parentId = UUID.randomUUID(); DmsResourcePath path = new DmsResourcePath(); List resourceIds = Arrays.asList(selectedId, parentId); DmsFilePermissionEntity user = permission(selectedId); user.setPrincipalId("org-1"); when(fixture.resourceResolver.resolve(TENANT_ID, DmsResourceType.FOLDER, selectedId)).thenReturn(path); when(fixture.resourceResolver.candidateResourceIds(path)).thenReturn(resourceIds); when(fixture.permissionMapper.selectForResourceIds(TENANT_ID, resourceIds, 1000)) .thenReturn(Arrays.asList(organizationPermission(selectedId), organizationPermission(parentId), user)); when(fixture.matcher.coversResource(any(), any())).thenReturn(true); when(fixture.grantService.toVO(any())).thenAnswer(invocation -> toVO(invocation.getArgument(0))); when(fixture.organizeApi.getListByIds(Collections.singletonList("org-1"))) .thenReturn(Collections.singletonList(organization("org-1", "质量部"))); when(fixture.userDisplayNameResolver.resolve(any())).thenReturn(Collections.singletonMap("org-1", "测试用户")); List result = fixture.service.resourceGrants(DmsResourceType.FOLDER, selectedId); assertEquals("质量部", result.get(0).getPrincipalName()); assertEquals("质量部", result.get(1).getPrincipalName()); assertFalse(result.get(0).isInherited()); assertTrue(result.get(1).isInherited()); assertEquals("测试用户", result.get(2).getPrincipalName()); verify(fixture.organizeApi).getListByIds(Collections.singletonList("org-1")); } @Test void preservesOrganizationIdWhenLookupMissingOrUnavailable() { Fixture fixture = new Fixture(); DmsFilePermissionEntity permission = organizationPermission(UUID.randomUUID()); when(fixture.permissionMapper.selectByTenantAndId(TENANT_ID, permission.getId())).thenReturn(permission); when(fixture.grantService.toVO(permission)).thenAnswer(invocation -> toVO(permission)); when(fixture.organizeApi.getListByIds(Collections.singletonList("org-1"))) .thenReturn(Collections.emptyList()) .thenReturn(null) .thenReturn(Arrays.asList(null, organization("org-1", " "))) .thenThrow(new IllegalStateException("organization service unavailable")); for (int i = 0; i < 4; i++) { DmsPermissionGrantVO result = fixture.service.grant(permission.getId()); assertNull(result.getPrincipalName()); assertEquals("org-1", result.getPrincipalId()); } } @ParameterizedTest @EnumSource(value = DmsPrincipalType.class, names = "USER", mode = EnumSource.Mode.EXCLUDE) void enrichesEveryNonUserTypeInPageDetailAndInheritedList(DmsPrincipalType type) { Fixture fixture = new Fixture(); UUID selectedId = UUID.randomUUID(); UUID parentId = UUID.randomUUID(); DmsFilePermissionEntity direct = principalPermission(type, selectedId); DmsFilePermissionEntity inherited = principalPermission(type, parentId); List rows = Arrays.asList(direct, inherited); when(fixture.grantService.toVO(any())).thenAnswer(invocation -> toVO(invocation.getArgument(0))); when(fixture.permissionMapper.selectPage(TENANT_ID, null, null, null, null, null, 11)).thenReturn(rows); when(fixture.permissionMapper.selectByTenantAndId(TENANT_ID, direct.getId())).thenReturn(direct); DmsResourcePath path = new DmsResourcePath(); when(fixture.resourceResolver.resolve(TENANT_ID, DmsResourceType.FOLDER, selectedId)).thenReturn(path); when(fixture.resourceResolver.candidateResourceIds(path)).thenReturn(Arrays.asList(selectedId, parentId)); when(fixture.permissionMapper.selectForResourceIds(TENANT_ID, Arrays.asList(selectedId, parentId), 1000)).thenReturn(rows); when(fixture.matcher.coversResource(any(), any())).thenReturn(true); when(lookup(fixture, type).apply(Collections.singletonList("shared-id"))) .thenAnswer(invocation -> Collections.singletonList(namedPrincipal(type, " " + type.name() + "名称 "))); assertEquals(type.name() + "名称", fixture.service.grants(null, null, null, null, 10).getList().get(0).getPrincipalName()); assertEquals(type.name() + "名称", fixture.service.grant(direct.getId()).getPrincipalName()); List result = fixture.service.resourceGrants(DmsResourceType.FOLDER, selectedId); assertEquals(type.name() + "名称", result.get(0).getPrincipalName()); assertEquals(type.name() + "名称", result.get(1).getPrincipalName()); assertFalse(result.get(0).isInherited()); assertTrue(result.get(1).isInherited()); } @ParameterizedTest @EnumSource(value = DmsPrincipalType.class, names = "USER", mode = EnumSource.Mode.EXCLUDE) void missingAndFailedLookupKeepIdsAndOtherTypesAvailable(DmsPrincipalType type) { Fixture fixture = new Fixture(); List rows = new ArrayList<>(); for (DmsPrincipalType principalType : DmsPrincipalType.values()) { rows.add(principalPermission(principalType, UUID.randomUUID())); if (principalType != DmsPrincipalType.USER) { when(lookup(fixture, principalType).apply(Collections.singletonList("shared-id"))) .thenAnswer(invocation -> Collections.singletonList(namedPrincipal(principalType, principalType.name()))); } } when(fixture.userDisplayNameResolver.resolve(any())).thenReturn(Collections.singletonMap("shared-id", "USER")); when(fixture.grantService.toVO(any())).thenAnswer(invocation -> toVO(invocation.getArgument(0))); when(fixture.permissionMapper.selectPage(TENANT_ID, null, null, null, null, null, 11)).thenReturn(rows); when(lookup(fixture, type).apply(Collections.singletonList("shared-id"))) .thenAnswer(invocation -> Collections.emptyList()) .thenAnswer(invocation -> null) .thenAnswer(invocation -> Arrays.asList(null, namedPrincipal(type, " "))) .thenThrow(new IllegalStateException("principal lookup unavailable")); for (int i = 0; i < 4; i++) { List result = fixture.service.grants(null, null, null, null, 10).getList(); assertEquals(DmsPrincipalType.values().length, result.size()); for (DmsPermissionGrantVO grant : result) { assertEquals("shared-id", grant.getPrincipalId()); if (type.name().equals(grant.getPrincipalType())) { assertNull(grant.getPrincipalName()); } else { assertEquals(grant.getPrincipalType(), grant.getPrincipalName()); } } } } @Test void batchesAndIsolatesAllFiveTypesWithSameId() { Fixture fixture = new Fixture(); List rows = new ArrayList<>(); for (DmsPrincipalType type : DmsPrincipalType.values()) { rows.add(principalPermission(type, UUID.randomUUID())); rows.add(principalPermission(type, UUID.randomUUID())); if (type != DmsPrincipalType.USER) { when(lookup(fixture, type).apply(Collections.singletonList("shared-id"))) .thenAnswer(invocation -> Collections.singletonList(namedPrincipal(type, type.name()))); } } when(fixture.userDisplayNameResolver.resolve(any())).thenReturn(Collections.singletonMap("shared-id", "USER")); when(fixture.grantService.toVO(any())).thenAnswer(invocation -> toVO(invocation.getArgument(0))); when(fixture.permissionMapper.selectPage(TENANT_ID, null, null, null, null, null, 11)).thenReturn(rows); List result = fixture.service.grants(null, null, null, null, 10).getList(); assertEquals(10, result.size()); result.forEach(grant -> assertEquals(grant.getPrincipalType(), grant.getPrincipalName())); verify(fixture.organizeApi).getListByIds(Collections.singletonList("shared-id")); verify(fixture.positionApi).getListByIds(Collections.singletonList("shared-id")); verify(fixture.roleApi).getListByIds(Collections.singletonList("shared-id")); verify(fixture.permissionGroupMapper).selectDisplayByIds(Collections.singletonList("shared-id")); } private static DmsFilePermissionEntity principalPermission(DmsPrincipalType type, UUID resourceId) { DmsFilePermissionEntity result = permission(resourceId); result.setPrincipalType(type.name()); result.setPrincipalId("shared-id"); return result; } private static Function, List> lookup(Fixture fixture, DmsPrincipalType type) { switch (type) { case ORG: return fixture.organizeApi::getListByIds; case POSITION: return fixture.positionApi::getListByIds; case ROLE: return fixture.roleApi::getListByIds; case GROUP: return fixture.permissionGroupMapper::selectDisplayByIds; default: throw new IllegalArgumentException(type.name()); } } private static Object namedPrincipal(DmsPrincipalType type, String name) { switch (type) { case ORG: return organization("shared-id", name); case POSITION: PositionEntity position = new PositionEntity(); position.setId("shared-id"); position.setFullName(name); return position; case ROLE: RoleEntity role = new RoleEntity(); role.setId("shared-id"); role.setFullName(name); return role; case GROUP: PermissionGroupEntity group = new PermissionGroupEntity(); group.setId("shared-id"); group.setFullName(name); group.setEnabledMark(0); return group; default: throw new IllegalArgumentException(type.name()); } } private static DmsFilePermissionEntity organizationPermission(UUID resourceId) { DmsFilePermissionEntity result = permission(resourceId); result.setPrincipalType("ORG"); result.setPrincipalId("org-1"); return result; } private static OrganizeEntity organization(String id, String name) { OrganizeEntity result = new OrganizeEntity(); result.setId(id); result.setFullName(name); return result; } private static DmsFilePermissionEntity permission(UUID resourceId) { DmsFilePermissionEntity result = new DmsFilePermissionEntity(); result.setId(UUID.randomUUID()); result.setResourceId(resourceId); result.setPrincipalType("USER"); result.setPrincipalId(USER_ID); result.setValidFrom(new Date(System.currentTimeMillis() - 60_000)); result.setUsedCount(0L); result.setCreatedAt(new Date()); return result; } private static DmsPermissionGrantVO toVO(DmsFilePermissionEntity permission) { DmsPermissionGrantVO result = new DmsPermissionGrantVO(); result.setId(permission.getId()); result.setResourceId(permission.getResourceId()); result.setPrincipalType(permission.getPrincipalType()); result.setPrincipalId(permission.getPrincipalId()); return result; } private static class Fixture { private final DmsCurrentIdentity currentIdentity = mock(DmsCurrentIdentity.class); private final DmsPermissionProperties properties = new DmsPermissionProperties(); private final DmsCursorCodec cursorCodec = new DmsCursorCodec(); private final DmsFilePermissionMapper permissionMapper = mock(DmsFilePermissionMapper.class); private final DmsPermissionGroupMapper permissionGroupMapper = mock(DmsPermissionGroupMapper.class); private final DmsPermissionUsageMapper usageMapper = mock(DmsPermissionUsageMapper.class); private final DmsPermissionGrantService grantService = mock(DmsPermissionGrantService.class); private final DmsResourceResolver resourceResolver = mock(DmsResourceResolver.class); private final DmsPermissionMatcher matcher = mock(DmsPermissionMatcher.class); private final DmsUserDisplayNameResolver userDisplayNameResolver = mock(DmsUserDisplayNameResolver.class); private final OrganizeApi organizeApi = mock(OrganizeApi.class); private final PositionApi positionApi = mock(PositionApi.class); private final RoleApi roleApi = mock(RoleApi.class); private final DmsPermissionAdminQueryService service = new DmsPermissionAdminQueryService( currentIdentity, properties, cursorCodec, permissionMapper, permissionGroupMapper, usageMapper, grantService, resourceResolver, matcher, userDisplayNameResolver, organizeApi, positionApi, roleApi); private Fixture() { when(currentIdentity.tenantId()).thenReturn(TENANT_ID); } } }