package jnpf.dmsService; import jnpf.dmsEntity.permission.entity.DmsFilePermissionEntity; import jnpf.dmsIntegration.audit.DmsAuditAdapter; import jnpf.dmsMapper.DmsFilePermissionMapper; import jnpf.dmsMapper.DmsPermissionResourceMapper; import jnpf.dmsPermission.DmsCurrentIdentity; import jnpf.dmsPermission.DmsPermissionError; import jnpf.dmsPermission.DmsPermissionException; import jnpf.dmsPermission.DmsPermissionProperties; import jnpf.dmsPermission.DmsPrincipalValidator; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import java.util.Collections; import java.util.Date; import java.util.UUID; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; class DmsPermissionGrantServiceTest { private static final String TENANT_ID = "tenant-1"; private static final String CREATOR_ID = "user-1"; private static final UUID FOLDER_ID = UUID.fromString("018f0000-0000-7000-8000-000000000402"); private static final UUID PERMISSION_ID = UUID.fromString("018f0000-0000-7000-8000-000000000403"); private static final String SOURCE_ID = "folder-creator-create:" + FOLDER_ID; private static final String GRANT_REASON = "目录创建者默认 CREATE 权限"; @Test void grantsSelfCreatePermissionToFolderCreator() { Fixture fixture = new Fixture(); when(fixture.permissionMapper.selectBySource(TENANT_ID, "SYSTEM", SOURCE_ID)) .thenReturn(Collections.emptyList()); when(fixture.permissionMapper.insertReturning(any(DmsFilePermissionEntity.class))) .thenAnswer(invocation -> { DmsFilePermissionEntity entity = invocation.getArgument(0); entity.setId(PERMISSION_ID); return entity; }); DmsFilePermissionEntity result = fixture.service.ensureFolderCreatorCreatePermission( TENANT_ID, FOLDER_ID, CREATOR_ID); assertEquals(PERMISSION_ID, result.getId()); verify(fixture.permissionMapper).lockSource(TENANT_ID, "SYSTEM", SOURCE_ID); ArgumentCaptor captor = ArgumentCaptor.forClass(DmsFilePermissionEntity.class); verify(fixture.permissionMapper).insertReturning(captor.capture()); DmsFilePermissionEntity permission = captor.getValue(); assertEquals(TENANT_ID, permission.getTenantId()); assertEquals("FOLDER", permission.getResourceType()); assertEquals(FOLDER_ID, permission.getResourceId()); assertEquals("SELF", permission.getResourceScope()); assertEquals("USER", permission.getPrincipalType()); assertEquals(CREATOR_ID, permission.getPrincipalId()); assertEquals(Boolean.FALSE, permission.getIncludeChildOrgs()); assertEquals("CREATE", permission.getActionCode()); assertEquals("SYSTEM", permission.getSourceType()); assertEquals(SOURCE_ID, permission.getSourceId()); assertNotNull(permission.getValidFrom()); assertEquals(GRANT_REASON, permission.getGrantReason()); assertEquals("USER", permission.getGrantedByType()); assertEquals(CREATOR_ID, permission.getGrantedById()); verify(fixture.currentIdentity, never()).requirePermissionAdministrator(); verify(fixture.principalValidator, never()).validate(any()); verify(fixture.auditAdapter).dataChange("CREATE", "创建 DMS 目录创建者默认权限", "dms_file_permissions", PERMISSION_ID.toString(), GRANT_REASON, null); } @Test void keepsRevokedPermissionRevokedOnIdempotentRetry() { Fixture fixture = new Fixture(); DmsFilePermissionEntity existing = matchingPermission(); existing.setRevokedAt(new Date()); when(fixture.permissionMapper.selectBySource(TENANT_ID, "SYSTEM", SOURCE_ID)) .thenReturn(Collections.singletonList(existing)); DmsFilePermissionEntity result = fixture.service.ensureFolderCreatorCreatePermission( TENANT_ID, FOLDER_ID, CREATOR_ID); assertSame(existing, result); verify(fixture.permissionMapper, never()).insertReturning(any(DmsFilePermissionEntity.class)); verify(fixture.auditAdapter, never()).dataChange(any(), any(), any(), any(), any(), any()); } @Test void rejectsMismatchedPermissionUsingSameSource() { Fixture fixture = new Fixture(); DmsFilePermissionEntity existing = matchingPermission(); existing.setActionCode("READ"); when(fixture.permissionMapper.selectBySource(TENANT_ID, "SYSTEM", SOURCE_ID)) .thenReturn(Collections.singletonList(existing)); DmsPermissionException exception = assertThrows(DmsPermissionException.class, () -> fixture.service.ensureFolderCreatorCreatePermission(TENANT_ID, FOLDER_ID, CREATOR_ID)); assertEquals(DmsPermissionError.SOURCE_CONFLICT, exception.getError()); verify(fixture.permissionMapper, never()).insertReturning(any(DmsFilePermissionEntity.class)); } private static DmsFilePermissionEntity matchingPermission() { DmsFilePermissionEntity permission = new DmsFilePermissionEntity(); permission.setId(PERMISSION_ID); permission.setTenantId(TENANT_ID); permission.setResourceType("FOLDER"); permission.setResourceId(FOLDER_ID); permission.setResourceScope("SELF"); permission.setPrincipalType("USER"); permission.setPrincipalId(CREATOR_ID); permission.setIncludeChildOrgs(false); permission.setActionCode("CREATE"); permission.setSourceType("SYSTEM"); permission.setSourceId(SOURCE_ID); permission.setValidFrom(new Date()); permission.setGrantReason(GRANT_REASON); permission.setGrantedByType("USER"); permission.setGrantedById(CREATOR_ID); return permission; } private static class Fixture { private final DmsCurrentIdentity currentIdentity = mock(DmsCurrentIdentity.class); private final DmsPermissionProperties properties = new DmsPermissionProperties(); private final DmsPrincipalValidator principalValidator = mock(DmsPrincipalValidator.class); private final DmsPermissionResourceMapper resourceMapper = mock(DmsPermissionResourceMapper.class); private final DmsFilePermissionMapper permissionMapper = mock(DmsFilePermissionMapper.class); private final DmsAuditAdapter auditAdapter = mock(DmsAuditAdapter.class); private final DmsPermissionGrantService service = new DmsPermissionGrantService( currentIdentity, properties, principalValidator, resourceMapper, permissionMapper, auditAdapter); } }