package jnpf.fileStorage.dms;
|
|
import jnpf.base.ActionResult;
|
import jnpf.dmsEntity.download.model.DmsFileDownloadTicket;
|
import jnpf.dmsEntity.preview.model.DmsFilePreviewTicket;
|
import jnpf.dmsEntity.preview.model.DmsWatermarkSnapshot;
|
import jnpf.exception.DataException;
|
import jnpf.onlyoffice.PageWatermarkApi;
|
import jnpf.onlyoffice.PageWatermarkRequest;
|
import org.junit.Test;
|
import java.io.ByteArrayOutputStream;
|
import java.nio.charset.StandardCharsets;
|
import java.util.List;
|
import java.util.UUID;
|
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipOutputStream;
|
import static org.junit.Assert.*;
|
import static org.mockito.Mockito.*;
|
import static org.mockito.ArgumentMatchers.*;
|
|
public class DmsFileWatermarkServiceTest {
|
@Test
|
public void previewPrintAndDownloadDelegateCleanSourceAndKeepAllPagesWatermarksIndependent() throws Exception {
|
for (String scope : List.of(DmsFilePreviewTicket.SCOPE, DmsFilePreviewTicket.PRINT_SCOPE, DmsFileDownloadTicket.SCOPE)) {
|
DmsDocxWatermarkService docx = mock(DmsDocxWatermarkService.class);
|
PageWatermarkApi renderer = mock(PageWatermarkApi.class);
|
AtomicReference<DmsFilePreviewTicket> delegated = new AtomicReference<>();
|
DmsFileWatermarkService service = new DmsFileWatermarkService(docx, renderer, ticket -> {
|
delegated.set(ticket);
|
return "server-only-source-ticket";
|
});
|
byte[] source = {1, 2, 3};
|
DmsWatermarkSnapshot custom = new DmsWatermarkSnapshot();
|
custom.setContent("REC-001");
|
custom.setRenderPages(List.of(1, 3, 5));
|
DmsWatermarkSnapshot everyPage = new DmsWatermarkSnapshot();
|
everyPage.setContent("Original watermark");
|
List<PageWatermarkRequest.Overlay> overlays = List.of(new PageWatermarkRequest.Overlay(List.of(1, 3, 5), List.of()));
|
when(docx.pageOverlays(source, List.of(custom))).thenReturn(overlays);
|
when(renderer.render(any())).thenAnswer(invocation -> {
|
PageWatermarkRequest request = invocation.getArgument(0);
|
assertEquals(overlays, request.getOverlays());
|
assertEquals("server-only-source-ticket", request.getSourceTicket());
|
ActionResult<byte[]> result = new ActionResult<>();
|
result.setCode(200);
|
result.setData(drawings(request.getMarkerPrefix()));
|
return result;
|
});
|
when(docx.apply(any(byte[].class), eq(List.of(everyPage)))).thenReturn(new byte[]{4, 5, 6});
|
DmsFilePreviewTicket ticket = new DmsFilePreviewTicket();
|
ticket.setScope(scope);
|
ticket.setFileVersionId(UUID.randomUUID());
|
ticket.setTenantId("tenant-1");
|
ticket.setUserId("user-1");
|
ticket.setFileName("original.docx");
|
ticket.setObjectName("original.docx");
|
ticket.setWatermarks(List.of(custom, everyPage));
|
byte[] result;
|
if (DmsFileDownloadTicket.SCOPE.equals(scope)) {
|
DmsFileDownloadTicket download = new DmsFileDownloadTicket();
|
org.springframework.beans.BeanUtils.copyProperties(ticket, download);
|
result = service.apply(source, download);
|
} else result = service.apply(source, ticket);
|
assertArrayEquals(new byte[]{4, 5, 6}, result);
|
assertEquals(DmsFilePreviewTicket.SCOPE, delegated.get().getScope());
|
assertEquals(ticket.getFileVersionId(), delegated.get().getFileVersionId());
|
assertEquals("tenant-1", delegated.get().getTenantId());
|
assertEquals("original.docx", delegated.get().getObjectName());
|
assertTrue(delegated.get().getWatermarks().isEmpty());
|
assertTrue(delegated.get().getExpiresAt() > System.currentTimeMillis());
|
assertEquals(List.of(custom, everyPage), ticket.getWatermarks());
|
assertEquals(scope, ticket.getScope());
|
verify(docx).apply(any(byte[].class), eq(List.of(everyPage)));
|
}
|
}
|
|
@Test
|
public void aFailedPageJobNeverFallsBackToEveryPageOrUnwatermarkedSource() throws Exception {
|
DmsDocxWatermarkService docx = mock(DmsDocxWatermarkService.class);
|
PageWatermarkApi renderer = mock(PageWatermarkApi.class);
|
DmsFileWatermarkService service = new DmsFileWatermarkService(docx, renderer, ignored -> "source-ticket");
|
DmsWatermarkSnapshot mark = new DmsWatermarkSnapshot();
|
mark.setRenderPages(List.of(2));
|
DmsFilePreviewTicket ticket = new DmsFilePreviewTicket();
|
ticket.setFileName("original.docx");
|
ticket.setWatermarks(List.of(mark));
|
when(docx.pageOverlays(any(), any())).thenReturn(List.of(new PageWatermarkRequest.Overlay(List.of(2), List.of())));
|
when(renderer.render(any())).thenThrow(new DataException("水印页码 2 超过文档总页数 1"));
|
assertThrows(DataException.class, () -> service.apply(new byte[]{1}, ticket));
|
verify(docx, never()).apply(any(), any());
|
}
|
|
@Test
|
public void previewAndDownloadImagesUseRasterWatermarkWithoutOnlyOffice() {
|
DmsDocxWatermarkService docx = mock(DmsDocxWatermarkService.class);
|
DmsImageWatermarkService image = mock(DmsImageWatermarkService.class);
|
PageWatermarkApi renderer = mock(PageWatermarkApi.class);
|
DmsFileWatermarkService service = new DmsFileWatermarkService(docx, image, renderer,
|
ignored -> "unused-ticket");
|
byte[] source = {1, 2, 3};
|
byte[] watermarked = {4, 5, 6};
|
DmsWatermarkSnapshot mark = new DmsWatermarkSnapshot();
|
List<DmsWatermarkSnapshot> marks = List.of(mark);
|
when(image.apply(source, "photo.PNG", null, marks)).thenReturn(watermarked);
|
|
DmsFilePreviewTicket preview = new DmsFilePreviewTicket();
|
preview.setFileName("photo.PNG");
|
preview.setWatermarks(marks);
|
DmsFileDownloadTicket download = new DmsFileDownloadTicket();
|
download.setFileName("photo.PNG");
|
download.setWatermarks(marks);
|
|
assertArrayEquals(watermarked, service.apply(source, preview));
|
assertArrayEquals(watermarked, service.apply(source, download));
|
verify(image, times(2)).apply(source, "photo.PNG", null, marks);
|
verifyNoInteractions(docx, renderer);
|
}
|
|
@Test
|
public void previewPrintAndDownloadPdfUsePdfWatermark() {
|
DmsDocxWatermarkService docx = mock(DmsDocxWatermarkService.class);
|
DmsPdfWatermarkService pdf = mock(DmsPdfWatermarkService.class);
|
PageWatermarkApi renderer = mock(PageWatermarkApi.class);
|
DmsFileWatermarkService service = new DmsFileWatermarkService(docx, null, pdf, renderer,
|
ignored -> "unused-ticket");
|
byte[] source = {1, 2, 3};
|
byte[] watermarked = {4, 5, 6};
|
DmsWatermarkSnapshot mark = new DmsWatermarkSnapshot();
|
List<DmsWatermarkSnapshot> marks = List.of(mark);
|
when(pdf.apply(source, marks)).thenReturn(watermarked);
|
|
for (String scope : List.of(DmsFilePreviewTicket.SCOPE, DmsFilePreviewTicket.PRINT_SCOPE)) {
|
DmsFilePreviewTicket ticket = new DmsFilePreviewTicket();
|
ticket.setScope(scope);
|
ticket.setFileName("report.pdf");
|
ticket.setWatermarks(marks);
|
assertArrayEquals(watermarked, service.apply(source, ticket));
|
}
|
DmsFileDownloadTicket download = new DmsFileDownloadTicket();
|
download.setFileName("report.pdf");
|
download.setWatermarks(marks);
|
assertArrayEquals(watermarked, service.apply(source, download));
|
verify(pdf, times(3)).apply(source, marks);
|
verifyNoInteractions(docx, renderer);
|
}
|
|
private byte[] drawings(String prefix) throws Exception {
|
StringBuilder xml = new StringBuilder("<w:document xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" "
|
+ "xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\">");
|
for (int page : List.of(1, 3, 5)) {
|
xml.append("<wp:anchor layoutInCell=\"1\" simplePos=\"0\"><wp:simplePos x=\"0\" y=\"0\"/>")
|
.append("<wp:positionH relativeFrom=\"page\"><wp:posOffset>0</wp:posOffset></wp:positionH>")
|
.append("<wp:positionV relativeFrom=\"page\"><wp:posOffset>0</wp:posOffset></wp:positionV>")
|
.append("<wp:docPr name=\"").append(prefix).append("_0_").append(page)
|
.append("\"/></wp:anchor>");
|
}
|
xml.append("</w:document>");
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
try (ZipOutputStream zip = new ZipOutputStream(bytes)) {
|
zip.putNextEntry(new ZipEntry("word/document.xml"));
|
zip.write(xml.toString().getBytes(StandardCharsets.UTF_8));
|
zip.closeEntry();
|
}
|
return bytes.toByteArray();
|
}
|
}
|