package jnpf.dmsService;
|
|
import jnpf.base.UserInfo;
|
import jnpf.dmsEntity.download.form.DmsFileDownloadTicketRequest;
|
import jnpf.dmsEntity.download.model.DmsFileDownloadTicket;
|
import jnpf.dmsEntity.download.vo.DmsFileDownloadTicketVO;
|
import jnpf.dmsEntity.permission.entity.DmsFileVersionEntity;
|
import jnpf.dmsEntity.permission.enums.DmsPermissionAction;
|
import jnpf.dmsEntity.permission.enums.DmsResourceType;
|
import jnpf.dmsEntity.preview.model.DmsWatermarkSnapshot;
|
import jnpf.dmsEntity.storage.entity.DmsFileObjectEntity;
|
import jnpf.dmsMapper.DmsFileObjectMapper;
|
import jnpf.dmsMapper.DmsFileVersionMapper;
|
import jnpf.dmsPermission.DmsCurrentIdentity;
|
import jnpf.dmsPermission.DmsPermissionError;
|
import jnpf.dmsPermission.DmsPermissionException;
|
import jnpf.dmsPermission.DmsPermissionExecutionContext;
|
import jnpf.dmsPermission.DmsPermissionGuard;
|
import jnpf.dmsPermission.DmsPermissionOperation;
|
import jnpf.dmsService.pdf.DmsPdfGenerationTaskService;
|
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.Test;
|
import org.mockito.ArgumentCaptor;
|
|
import java.util.Collections;
|
import java.util.UUID;
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.anyLong;
|
import static org.mockito.Mockito.doThrow;
|
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 DmsFileDownloadServiceTest {
|
private final DmsCurrentIdentity currentIdentity = mock(DmsCurrentIdentity.class);
|
private final DmsPermissionGuard permissionGuard = mock(DmsPermissionGuard.class);
|
private final DmsFileVersionMapper versionMapper = mock(DmsFileVersionMapper.class);
|
private final DmsFileObjectMapper objectMapper = mock(DmsFileObjectMapper.class);
|
private final DmsFileDownloadTicketIssuer ticketIssuer = mock(DmsFileDownloadTicketIssuer.class);
|
private final DmsFileOperationLogService operationLogService = mock(DmsFileOperationLogService.class);
|
private final DmsWatermarkPreviewResolver watermarkResolver = mock(DmsWatermarkPreviewResolver.class);
|
private final DmsPdfGenerationTaskService pdfGenerationTaskService = mock(DmsPdfGenerationTaskService.class);
|
private final DmsFileDownloadService service = new DmsFileDownloadService(currentIdentity,
|
permissionGuard, versionMapper, objectMapper, ticketIssuer, operationLogService,
|
watermarkResolver, pdfGenerationTaskService);
|
private final UUID documentId = UUID.fromString("018f0000-0000-7000-8000-000000000701");
|
private final UUID versionId = UUID.fromString("018f0000-0000-7000-8000-000000000702");
|
private final UUID operationId = UUID.fromString("018f0000-0000-7000-8000-000000000703");
|
private UserInfo user;
|
|
@BeforeEach
|
void setUp() {
|
user = new UserInfo();
|
user.setTenantId("tenant-1");
|
user.setUserId("user-1");
|
when(currentIdentity.requireUser()).thenReturn(user);
|
when(currentIdentity.tenantId(user)).thenReturn("tenant-1");
|
when(permissionGuard.execute(any(), any())).thenAnswer(invocation -> {
|
DmsPermissionOperation<?> operation = invocation.getArgument(1);
|
return operation.execute();
|
});
|
when(ticketIssuer.issue(any(DmsFileDownloadTicket.class),
|
org.mockito.ArgumentMatchers.eq(DmsFileDownloadService.TICKET_TTL_SECONDS)))
|
.thenReturn("download-ticket");
|
}
|
|
@Test
|
void uncontrolledVersionStillRequiresDownloadPermissionCheck() {
|
DmsFileVersionEntity version = version();
|
version.setShifouShoukong("no");
|
DmsWatermarkSnapshot watermark = new DmsWatermarkSnapshot();
|
when(versionMapper.selectCurrentEffective("tenant-1", documentId)).thenReturn(version);
|
when(versionMapper.selectReadableByTenantAndId("tenant-1", versionId)).thenReturn(version);
|
when(objectMapper.selectByTenantAndFileVersionId("tenant-1", versionId)).thenReturn(fileObject());
|
when(watermarkResolver.resolveDownload(org.mockito.ArgumentMatchers.eq(user),
|
org.mockito.ArgumentMatchers.eq("tenant-1"), org.mockito.ArgumentMatchers.eq(version), any()))
|
.thenReturn(Collections.singletonList(watermark));
|
|
DmsFileDownloadTicketVO result = service.createTicket(
|
request(DmsResourceType.DOCUMENT, documentId));
|
|
assertEquals(versionId, result.getFileVersionId());
|
assertEquals("download-ticket", result.getAccessTicket());
|
assertTrue(result.getExpiresAt().getTime() > System.currentTimeMillis());
|
|
ArgumentCaptor<DmsPermissionExecutionContext> contextCaptor =
|
ArgumentCaptor.forClass(DmsPermissionExecutionContext.class);
|
verify(permissionGuard).execute(contextCaptor.capture(), any());
|
assertEquals(DmsPermissionAction.DOWNLOAD, contextCaptor.getValue().getActionCode());
|
assertEquals(DmsResourceType.FILE_VERSION, contextCaptor.getValue().getResourceType());
|
assertEquals(versionId, contextCaptor.getValue().getResourceId());
|
assertEquals(operationId, contextCaptor.getValue().getOperationId());
|
|
ArgumentCaptor<DmsFileDownloadTicket> payloadCaptor =
|
ArgumentCaptor.forClass(DmsFileDownloadTicket.class);
|
verify(ticketIssuer).issue(payloadCaptor.capture(),
|
org.mockito.ArgumentMatchers.eq(DmsFileDownloadService.TICKET_TTL_SECONDS));
|
DmsFileDownloadTicket payload = payloadCaptor.getValue();
|
assertEquals(DmsFileDownloadTicket.SCOPE, payload.getScope());
|
assertEquals(Collections.singletonList(watermark), payload.getWatermarks());
|
verify(operationLogService).recordDownload(user, "tenant-1", documentId, versionId,
|
"quality-manual.docx", operationId);
|
verify(pdfGenerationTaskService).enqueueMissingEligible("tenant-1", versionId,
|
"quality-manual.docx", "a".repeat(64));
|
}
|
|
@Test
|
void uncontrolledVersionWithoutDownloadPermissionIsRejected() {
|
DmsFileVersionEntity version = version();
|
version.setShifouShoukong("no");
|
when(versionMapper.selectReadableByTenantAndId("tenant-1", versionId)).thenReturn(version);
|
doThrow(DmsPermissionException.of(DmsPermissionError.PERMISSION_DENIED,
|
"no download permission")).when(permissionGuard).execute(any(), any());
|
|
DmsPermissionException error = assertThrows(DmsPermissionException.class,
|
() -> service.createTicket(request(DmsResourceType.FILE_VERSION, versionId)));
|
|
assertEquals(DmsPermissionError.PERMISSION_DENIED, error.getError());
|
verify(ticketIssuer, never()).issue(any(), anyLong());
|
}
|
|
@Test
|
void rejectsUnreadableHistoricalVersionBeforePermissionCheck() {
|
DmsPermissionException error = assertThrows(DmsPermissionException.class,
|
() -> service.createTicket(request(DmsResourceType.FILE_VERSION, versionId)));
|
|
assertEquals(DmsPermissionError.RESOURCE_NOT_FOUND, error.getError());
|
verify(permissionGuard, never()).execute(any(), any());
|
verify(ticketIssuer, never()).issue(any(), anyLong());
|
}
|
|
private DmsFileDownloadTicketRequest request(DmsResourceType type, UUID id) {
|
DmsFileDownloadTicketRequest request = new DmsFileDownloadTicketRequest();
|
request.setResourceType(type);
|
request.setResourceId(id);
|
request.setOperationId(operationId);
|
return request;
|
}
|
|
private DmsFileVersionEntity version() {
|
DmsFileVersionEntity version = new DmsFileVersionEntity();
|
version.setId(versionId);
|
version.setDocumentId(documentId);
|
version.setFileName("quality-manual.docx");
|
version.setMimeType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
|
version.setSizeBytes(2048L);
|
version.setChecksumSha256("a".repeat(64));
|
return version;
|
}
|
|
private DmsFileObjectEntity fileObject() {
|
DmsFileObjectEntity object = new DmsFileObjectEntity();
|
object.setFileVersionId(versionId);
|
object.setStoragePlatform("seaweedfs-1");
|
object.setBucketName("jnpf-dms");
|
object.setBasePath("dms/");
|
object.setObjectPath("2026/08/24/document/");
|
object.setObjectName("quality-manual-v1.docx");
|
return object;
|
}
|
}
|