From 34981c30a78e8bbd7791131059a9210f9928b62c Mon Sep 17 00:00:00 2001
From: 刘光辉 <347230014@qq.com>
Date: 星期四, 17 九月 2026 09:24:09 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master' into master
---
jnpf-dms/jnpf-dms-biz/src/test/java/jnpf/dmsService/DmsPermissionDecisionServiceTest.java | 188 +++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 188 insertions(+), 0 deletions(-)
diff --git a/jnpf-dms/jnpf-dms-biz/src/test/java/jnpf/dmsService/DmsPermissionDecisionServiceTest.java b/jnpf-dms/jnpf-dms-biz/src/test/java/jnpf/dmsService/DmsPermissionDecisionServiceTest.java
new file mode 100644
index 0000000..85cc609
--- /dev/null
+++ b/jnpf-dms/jnpf-dms-biz/src/test/java/jnpf/dmsService/DmsPermissionDecisionServiceTest.java
@@ -0,0 +1,188 @@
+package jnpf.dmsService;
+
+import jnpf.base.UserInfo;
+import jnpf.dmsEntity.permission.entity.DmsFilePermissionEntity;
+import jnpf.dmsEntity.permission.enums.DmsPermissionAction;
+import jnpf.dmsEntity.permission.enums.DmsResourceType;
+import jnpf.dmsEntity.permission.form.PermissionDecisionForm;
+import jnpf.dmsEntity.permission.model.DmsResourcePath;
+import jnpf.dmsEntity.permission.model.DmsSubjectSet;
+import jnpf.dmsEntity.permission.vo.DmsPermissionDecisionVO;
+import jnpf.dmsIntegration.audit.DmsAuditAdapter;
+import jnpf.dmsMapper.DmsFilePermissionMapper;
+import jnpf.dmsPermission.DmsAccessExclusionResolver;
+import jnpf.dmsPermission.DmsCurrentIdentity;
+import jnpf.dmsPermission.DmsPermissionGroupMembershipResolver;
+import jnpf.dmsPermission.DmsPermissionMatcher;
+import jnpf.dmsPermission.DmsPermissionProperties;
+import jnpf.dmsPermission.DmsResourceResolver;
+import jnpf.dmsPermission.DmsSubjectResolver;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.ArgumentMatchers.anySet;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class DmsPermissionDecisionServiceTest {
+ private final DmsCurrentIdentity currentIdentity = mock(DmsCurrentIdentity.class);
+ private final DmsSubjectResolver subjectResolver = mock(DmsSubjectResolver.class);
+ private final DmsResourceResolver resourceResolver = mock(DmsResourceResolver.class);
+ private final DmsFilePermissionMapper permissionMapper = mock(DmsFilePermissionMapper.class);
+ private final DmsPermissionGroupMembershipResolver groupResolver =
+ mock(DmsPermissionGroupMembershipResolver.class);
+ private final DmsPermissionMatcher matcher = mock(DmsPermissionMatcher.class);
+ private final DmsPermissionProperties properties = new DmsPermissionProperties();
+ private final DmsAuditAdapter auditAdapter = mock(DmsAuditAdapter.class);
+ private final DmsAccessExclusionResolver exclusionResolver = mock(DmsAccessExclusionResolver.class);
+ private final DmsPermissionDecisionService service = new DmsPermissionDecisionService(
+ currentIdentity, subjectResolver, resourceResolver, permissionMapper, groupResolver,
+ matcher, properties, auditAdapter, exclusionResolver);
+ private final UserInfo user = new UserInfo();
+
+ @BeforeEach
+ void setUp() {
+ user.setTenantId("tenant-1");
+ user.setUserId("user-1");
+ when(currentIdentity.requireUser()).thenReturn(user);
+ when(currentIdentity.tenantId(user)).thenReturn("tenant-1");
+ when(subjectResolver.resolve(user)).thenReturn(mock(DmsSubjectSet.class));
+ }
+
+ @Test
+ void exclusionWinsWithoutLoadingAllowCandidates() {
+ UUID documentId = UUID.randomUUID();
+ PermissionDecisionForm request = request(DmsResourceType.DOCUMENT, documentId);
+ DmsResourcePath path = document(documentId);
+ when(resourceResolver.resolveAll("tenant-1", Collections.singletonList(request)))
+ .thenReturn(Collections.singletonMap(documentId, path));
+ when(exclusionResolver.resolve(eq("tenant-1"), eq("user-1"), any()))
+ .thenReturn(new DmsAccessExclusionResolver.Snapshot(
+ new HashSet<>(Collections.singletonList(documentId)), Collections.emptySet()));
+
+ DmsPermissionDecisionVO result = service.evaluate(request);
+
+ assertFalse(result.isAllowed());
+ assertEquals("USER_READ_EXCLUDED", result.getReasonCode());
+ verify(permissionMapper, never()).selectCandidates(any(), any(), anyList());
+ verify(subjectResolver, never()).resolve(user);
+ }
+
+ @Test
+ void fileVersionExclusionOnlyDeniesSpecifiedVersionInBatch() {
+ UUID documentId = UUID.randomUUID();
+ UUID excludedVersionId = UUID.randomUUID();
+ UUID visibleVersionId = UUID.randomUUID();
+ PermissionDecisionForm excludedRequest = request(DmsResourceType.FILE_VERSION, excludedVersionId);
+ PermissionDecisionForm visibleRequest = request(DmsResourceType.FILE_VERSION, visibleVersionId);
+ DmsResourcePath excludedPath = version(documentId, excludedVersionId);
+ DmsResourcePath visiblePath = version(documentId, visibleVersionId);
+ Map<UUID, DmsResourcePath> paths = new HashMap<>();
+ paths.put(excludedVersionId, excludedPath);
+ paths.put(visibleVersionId, visiblePath);
+ when(resourceResolver.resolveAll("tenant-1", Arrays.asList(excludedRequest, visibleRequest)))
+ .thenReturn(paths);
+ when(exclusionResolver.resolve(eq("tenant-1"), eq("user-1"), any()))
+ .thenReturn(new DmsAccessExclusionResolver.Snapshot(Collections.emptySet(),
+ new HashSet<>(Collections.singletonList(excludedVersionId))));
+ when(resourceResolver.candidateResourceIds(visiblePath))
+ .thenReturn(Arrays.asList(visibleVersionId, documentId));
+ DmsFilePermissionEntity allow = new DmsFilePermissionEntity();
+ allow.setId(UUID.randomUUID());
+ when(permissionMapper.selectCandidates("tenant-1", Collections.singletonList("READ"),
+ Arrays.asList(visibleVersionId, documentId))).thenReturn(Collections.singletonList(allow));
+ allow.setActionCode("READ");
+ when(matcher.matches(eq(allow), eq(visiblePath), any(DmsSubjectSet.class))).thenReturn(true);
+
+ List<DmsPermissionDecisionVO> result = service.evaluate(Arrays.asList(excludedRequest, visibleRequest));
+
+ assertFalse(result.get(0).isAllowed());
+ assertEquals("USER_READ_EXCLUDED", result.get(0).getReasonCode());
+ assertTrue(result.get(1).isAllowed());
+ assertEquals(allow.getId(), result.get(1).getMatchedPermissionId());
+ verify(permissionMapper).selectCandidates("tenant-1", Collections.singletonList("READ"),
+ Arrays.asList(visibleVersionId, documentId));
+ verify(groupResolver).resolve(anySet(), any(DmsSubjectSet.class));
+ }
+
+ @Test
+ void twoHundredMixedDecisionsUseOneBulkLoadPerDependency() {
+ List<PermissionDecisionForm> requests = new java.util.ArrayList<>();
+ Map<UUID, DmsResourcePath> paths = new HashMap<>();
+ for (int index = 0; index < properties.getMaxDecisionBatchSize(); index++) {
+ UUID resourceId = UUID.randomUUID();
+ DmsPermissionAction action = index % 2 == 0
+ ? DmsPermissionAction.READ : DmsPermissionAction.UPDATE;
+ PermissionDecisionForm request = request(DmsResourceType.DOCUMENT, resourceId, action);
+ DmsResourcePath path = document(resourceId);
+ requests.add(request);
+ paths.put(resourceId, path);
+ when(resourceResolver.candidateResourceIds(path)).thenReturn(Collections.singletonList(resourceId));
+ }
+ when(resourceResolver.resolveAll("tenant-1", requests)).thenReturn(paths);
+ when(exclusionResolver.resolve(eq("tenant-1"), eq("user-1"), any()))
+ .thenReturn(DmsAccessExclusionResolver.Snapshot.empty());
+ when(permissionMapper.selectCandidates(eq("tenant-1"), anyList(), anyList()))
+ .thenReturn(Collections.emptyList());
+
+ List<DmsPermissionDecisionVO> result = service.evaluate(requests);
+
+ assertEquals(properties.getMaxDecisionBatchSize(), result.size());
+ assertTrue(result.stream().noneMatch(DmsPermissionDecisionVO::isAllowed));
+ org.mockito.ArgumentCaptor<List<String>> actions = org.mockito.ArgumentCaptor.forClass(List.class);
+ org.mockito.ArgumentCaptor<List<UUID>> resourceIds = org.mockito.ArgumentCaptor.forClass(List.class);
+ verify(resourceResolver, times(1)).resolveAll("tenant-1", requests);
+ verify(subjectResolver, times(1)).resolve(user);
+ verify(exclusionResolver, times(1)).resolve(eq("tenant-1"), eq("user-1"), any());
+ verify(permissionMapper, times(1)).selectCandidates(eq("tenant-1"), actions.capture(),
+ resourceIds.capture());
+ verify(groupResolver, times(1)).resolve(anySet(), any(DmsSubjectSet.class));
+ assertEquals(Arrays.asList("READ", "UPDATE"), actions.getValue());
+ assertEquals(properties.getMaxDecisionBatchSize(), new HashSet<>(resourceIds.getValue()).size());
+ }
+
+ private PermissionDecisionForm request(DmsResourceType type, UUID id) {
+ return request(type, id, DmsPermissionAction.READ);
+ }
+
+ private PermissionDecisionForm request(DmsResourceType type, UUID id, DmsPermissionAction action) {
+ PermissionDecisionForm result = new PermissionDecisionForm();
+ result.setResourceType(type);
+ result.setResourceId(id);
+ result.setActionCode(action);
+ return result;
+ }
+
+ private DmsResourcePath document(UUID documentId) {
+ DmsResourcePath path = new DmsResourcePath();
+ path.setActualResourceType("DOCUMENT");
+ path.setActualResourceId(documentId);
+ path.setDocumentId(documentId);
+ return path;
+ }
+
+ private DmsResourcePath version(UUID documentId, UUID versionId) {
+ DmsResourcePath path = new DmsResourcePath();
+ path.setActualResourceType("FILE_VERSION");
+ path.setActualResourceId(versionId);
+ path.setDocumentId(documentId);
+ return path;
+ }
+}
--
Gitblit v1.8.0