package jnpf.fileStorage.dms; import com.fasterxml.jackson.databind.ObjectMapper; import jnpf.base.ActionResult; import jnpf.dms.DmsResourceApi; import jnpf.dmsEntity.storage.approval.*; import jnpf.dmsEntity.storage.form.*; import jnpf.exception.DataException; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.springframework.web.multipart.MultipartFile; import java.util.*; import java.util.function.Function; import static org.junit.Assert.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; public class DmsWorkflowFileCreateServiceTest { DmsResourceApi api = mock(DmsResourceApi.class); DmsFileStorageService storage = mock(DmsFileStorageService.class); DmsCommonFileReader reader = mock(DmsCommonFileReader.class); DmsApprovalPageMergeService approvalPages = mock(DmsApprovalPageMergeService.class); DmsQianpiyeDocxWriter qianpiyeWriter = mock(DmsQianpiyeDocxWriter.class); MultipartFile file = mock(MultipartFile.class); MultipartFile approvalPage = mock(MultipartFile.class); MultipartFile merged = mock(MultipartFile.class); DmsWorkflowFileCreateService service = new DmsWorkflowFileCreateService( api, storage, reader, approvalPages, qianpiyeWriter, new ObjectMapper()); DmsApprovedItem item(String key, String type) { DmsApprovedItem i = new DmsApprovedItem(); i.setSourceKey(key); i.setChangeType(type); i.setDocumentName(key); i.setFileJson("[{\"url\":\"/api/file/Image/annex/" + key + ".docx\"}]"); i.setDocumentId(UUID.randomUUID()); i.setFileVersionId(UUID.randomUUID()); return i; } DmsApprovedBatch batch(DmsApprovedItem... items) { DmsApprovedBatch b = new DmsApprovedBatch(); b.setId(UUID.randomUUID()); b.setFlowId("flow"); b.setTaskId("task"); b.setAuditType("xinzeng_shenhe"); b.setSourceDigest("digest"); b.setItems(Arrays.asList(items)); b.setStatus("WAITING"); return b; } ActionResult success(DmsApprovedBatch batch) { ActionResult r = new ActionResult<>(); r.setCode(200); r.setData(batch); return r; } @SuppressWarnings("unchecked") void storing() { when(reader.withFile(any(), any(), any(), any())).thenAnswer(inv -> { Function operation = inv.getArgument(3); return operation.apply(file); }); when(storage.storeWorkflowContent(any(), any(), eq(file))).thenAnswer(inv -> { DmsFileUploadRegisterForm c = new DmsFileUploadRegisterForm(); c.setDocumentId(inv.getArgument(0)); c.setFileVersionId(inv.getArgument(1)); c.setFileObjectId(UUID.randomUUID()); return c; }); } @Test public void consumesDmsPushedSetAndCallsOnlyRegistrationAfterStoringAllChanges() { DmsApprovedItem main = item("main", "REVISE"), record = item("record", "CREATE"), reuse = item("reuse", "REUSE"); DmsApprovedBatch b = batch(main, record, reuse); storing(); when(api.registerWorkflowUpload(eq("jnpf-file"), eq("sign"), any())).thenReturn(success(b)); assertSame(b, service.process(DmsApprovedRegistrationForm.from(b), "sign")); ArgumentCaptor callback = ArgumentCaptor.forClass(DmsApprovedRegistrationCallback.class); org.mockito.InOrder order = inOrder(api, storage); order.verify(storage).storeWorkflowContent(main.getDocumentId(), main.getFileVersionId(), file); order.verify(storage).storeWorkflowContent(record.getDocumentId(), record.getFileVersionId(), file); order.verify(api).registerWorkflowUpload(eq("jnpf-file"), eq("sign"), callback.capture()); assertEquals(b.getId(), callback.getValue().getBatchId()); assertEquals(2, callback.getValue().getFiles().size()); assertEquals("digest", callback.getValue().getSourceDigest()); verify(api, never()).prepareWorkflowFile(any(), any()); verify(api, never()).activateWorkflowFile(any(), any()); } @Test public void secondStorageFailureNeverCallsRegistrationOrConfirmation() { DmsApprovedBatch b = batch(item("main", "CREATE"), item("record", "CREATE")); storing(); when(storage.storeWorkflowContent(any(), any(), eq(file))).thenReturn(new DmsFileUploadRegisterForm()).thenThrow(new DataException("storage failed")); assertThrows(DataException.class, () -> service.process(DmsApprovedRegistrationForm.from(b), null)); verifyNoInteractions(api); } @Test public void missingProgressIdentityCannotStartFileProcessing() { DmsApprovedRegistrationForm command = DmsApprovedRegistrationForm.from(batch(item("main", "CREATE"))); command.setBatchId(null); assertThrows(DataException.class, () -> service.process(command, null)); verifyNoInteractions(api, reader, storage); } @Test public void allReusedFilesStillConfirmTheBatchWithoutAnySourceRead() { DmsApprovedBatch b = batch(item("main", "REUSE")); when(api.registerWorkflowUpload(eq("jnpf-file"), isNull(), any())).thenReturn(success(b)); assertSame(b, service.process(DmsApprovedRegistrationForm.from(b), null)); verifyNoInteractions(reader, storage); verify(api, never()).prepareWorkflowFile(any(), any()); } @Test public void missingWrongOrIncompleteCallbackCannotReportSuccess() { DmsApprovedBatch b = batch(item("main", "REUSE")); DmsApprovedRegistrationForm form = DmsApprovedRegistrationForm.from(b); assertThrows(DataException.class, () -> service.process(form, null)); when(api.registerWorkflowUpload(eq("jnpf-file"), isNull(), any())).thenReturn(success(b)); b.setTaskId("other"); assertThrows(DataException.class, () -> service.process(form, null)); b.setTaskId("task"); b.setId(UUID.randomUUID()); assertThrows(DataException.class, () -> service.process(form, null)); } @Test public void rejectsChoosingOnlyOneAttachmentFromMultipleFiles() { assertThrows(DataException.class, () -> service.singleFileUrl("[{\"url\":\"a\"},{\"url\":\"b\"}]")); assertEquals("a", service.singleFileUrl("[{\"url\":\"a\"}]")); } @Test public void prependsConfiguredApprovalPageBeforeStoringTheNewMainDocument() { DmsApprovedItem main = item("main", "CREATE"); main.setApprovalPageFileJson("[{\"url\":\"/api/file/Image/annex/approval.pdf\"}]"); DmsApprovedBatch b = batch(main); when(file.getOriginalFilename()).thenReturn("main.docx"); when(reader.withFile(any(), any(), any(), any())).thenAnswer(inv -> { Function operation = inv.getArgument(3); return operation.apply(inv.getArgument(0).contains("approval.pdf") ? approvalPage : file); }); when(approvalPages.replaceOrPrepend(file, approvalPage)).thenReturn(merged); when(storage.storeWorkflowContent(main.getDocumentId(), main.getFileVersionId(), merged)) .thenReturn(new DmsFileUploadRegisterForm()); when(api.registerWorkflowUpload(eq("jnpf-file"), isNull(), any())).thenReturn(success(b)); assertSame(b, service.process(DmsApprovedRegistrationForm.from(b), null)); verify(approvalPages).replaceOrPrepend(file, approvalPage); verify(storage).storeWorkflowContent(main.getDocumentId(), main.getFileVersionId(), merged); verify(storage, never()).storeWorkflowContent(main.getDocumentId(), main.getFileVersionId(), file); } @Test public void configuredApprovalPageDoesNotBlockImageRegistration() { DmsApprovedItem main = item("PIC-SMP100-01000", "CREATE"); main.setApprovalPageFileJson("[{\"url\":\"/api/file/Image/annex/approval.docx\"}]"); DmsApprovedBatch b = batch(main); when(file.getOriginalFilename()).thenReturn("图片测试PIC-SMP100-01000.png"); when(reader.withFile(any(), any(), any(), any())).thenAnswer(inv -> { Function operation = inv.getArgument(3); return operation.apply(file); }); when(storage.storeWorkflowContent(main.getDocumentId(), main.getFileVersionId(), file)) .thenReturn(new DmsFileUploadRegisterForm()); when(api.registerWorkflowUpload(eq("jnpf-file"), isNull(), any())).thenReturn(success(b)); assertSame(b, service.process(DmsApprovedRegistrationForm.from(b), null)); verify(reader, times(1)).withFile(any(), any(), any(), any()); verifyNoInteractions(approvalPages, qianpiyeWriter); verify(storage).storeWorkflowContent(main.getDocumentId(), main.getFileVersionId(), file); } @Test public void originalDocxTagsAreRenderedWithoutAConfiguredApprovalPage() { DmsApprovedItem main = item("main", "CREATE"); main.setApprovalValuesByTag(java.util.Map.of("dms.qianpiye.form.wenjian_bianhao", "DOC-001")); main.setApprovalFlowVersionId("flow-version"); DmsApprovedBatch b = batch(main); when(file.getOriginalFilename()).thenReturn("main.docx"); when(reader.withFile(any(), any(), any(), any())).thenAnswer(inv -> inv.>getArgument(3).apply(file)); when(qianpiyeWriter.render(file, main.getApprovalValuesByTag(), "flow-version")).thenReturn(merged); when(storage.storeWorkflowContent(main.getDocumentId(), main.getFileVersionId(), merged)) .thenReturn(new DmsFileUploadRegisterForm()); when(api.registerWorkflowUpload(eq("jnpf-file"), isNull(), any())).thenReturn(success(b)); assertSame(b, service.process(DmsApprovedRegistrationForm.from(b), null)); verify(qianpiyeWriter).render(file, main.getApprovalValuesByTag(), "flow-version"); verifyNoInteractions(approvalPages); verify(storage).storeWorkflowContent(main.getDocumentId(), main.getFileVersionId(), merged); verify(reader, times(1)).withFile(any(), any(), any(), any()); } @Test public void configuredApprovalPageReadFailureNeverStoresTheOriginalOrCallsBackDms() { DmsApprovedItem main = item("main", "CREATE"); main.setApprovalPageFileJson("[{\"url\":\"/api/file/Image/annex/missing.pdf\"}]"); DmsApprovedRegistrationForm form = DmsApprovedRegistrationForm.from(batch(main)); when(file.getOriginalFilename()).thenReturn("main.docx"); when(reader.withFile(any(), any(), any(), any())).thenAnswer(inv -> { String url = inv.getArgument(0); if (url.contains("missing.pdf")) throw new DataException("file-common文件不存在"); Function operation = inv.getArgument(3); return operation.apply(file); }); assertThrows(DataException.class, () -> service.process(form, null)); verify(approvalPages, never()).replaceOrPrepend(any(), any()); verifyNoInteractions(storage, api); } @Test public void taggedRevisionReplacesTheExistingApprovalPage() { DmsApprovedItem main = item("main", "REVISE"); main.setApprovalPageFileJson("[{\"url\":\"/api/file/Image/annex/approval.docx\"}]"); DmsApprovedBatch b = batch(main); when(file.getOriginalFilename()).thenReturn("main.docx"); when(approvalPage.getOriginalFilename()).thenReturn("approval.docx"); when(reader.withFile(any(), any(), any(), any())).thenAnswer(inv -> { Function operation = inv.getArgument(3); return operation.apply(inv.getArgument(0).contains("approval.docx") ? approvalPage : file); }); main.setApprovalValuesByTag(Collections.singletonMap( "dms.qianpiye.flow.approve-1.approver", "张三")); main.setApprovalFlowVersionId("flow-version"); when(qianpiyeWriter.render(approvalPage, main.getApprovalValuesByTag(), main.getApprovalFlowVersionId())).thenReturn(merged); when(approvalPages.withoutApprovalPages(file)).thenReturn(file); when(qianpiyeWriter.render(file, main.getApprovalValuesByTag(), main.getApprovalFlowVersionId())).thenReturn(file); when(approvalPages.replaceOrPrepend(file, merged)).thenReturn(merged); when(storage.storeWorkflowContent(main.getDocumentId(), main.getFileVersionId(), merged)) .thenReturn(new DmsFileUploadRegisterForm()); when(api.registerWorkflowUpload(eq("jnpf-file"), isNull(), any())).thenReturn(success(b)); assertSame(b, service.process(DmsApprovedRegistrationForm.from(b), null)); verify(qianpiyeWriter).render(approvalPage, main.getApprovalValuesByTag(), main.getApprovalFlowVersionId()); verify(qianpiyeWriter).render(file, main.getApprovalValuesByTag(), main.getApprovalFlowVersionId()); verify(approvalPages).replaceOrPrepend(file, merged); verify(storage).storeWorkflowContent(main.getDocumentId(), main.getFileVersionId(), merged); verify(reader, times(2)).withFile(any(), any(), any(), any()); } }