package jnpf.dmsService; import com.fasterxml.jackson.databind.ObjectMapper; import jnpf.dmsEntity.DmsWenjianBanbenEntity; import jnpf.dmsEntity.DmsWenjianXinzengShenheEntity; import jnpf.dmsEntity.DmsWenjianXiudingShenheEntity; import jnpf.dmsEntity.storage.DmsWorkflowSourceKey; import jnpf.dmsEntity.storage.enums.DmsWorkflowFileType; import jnpf.dmsEntity.storage.form.DmsWorkflowFilePrepareForm; import jnpf.dmsMapper.DmsWenjianBanbenMapper; import jnpf.dmsMapper.DmsWenjianXiudingShenqingZixiangMapper; import jnpf.exception.DataException; import org.junit.jupiter.api.Test; import java.util.UUID; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; class DmsWorkflowApprovalValidatorTest { private final DmsWenjianBanbenMapper versions = mock(DmsWenjianBanbenMapper.class); private final jnpf.dmsMapper.DmsFileObjectMapper objects = mock(jnpf.dmsMapper.DmsFileObjectMapper.class); private final jnpf.dmsMapper.DmsWenjianXinzengShenheMapper newAudits = mock(jnpf.dmsMapper.DmsWenjianXinzengShenheMapper.class); private final DmsWorkflowApprovalValidator validator = new DmsWorkflowApprovalValidator( new ObjectMapper(), versions, mock(DmsWenjianXiudingShenqingZixiangMapper.class), objects, newAudits, mock(jnpf.dmsMapper.DmsWenjianXiudingShenheMapper.class)); private static final String URL = "/api/file/Image/annex/approved.docx"; private static final String FILE = "{\"url\":\"" + URL + "\",\"name\":\"approved.docx\"}"; @Test void sharedFlowIdHasIndependentTaskKeysAndStableRetries() { String first = DmsWorkflowSourceKey.of("flow", "task-1", DmsWorkflowFileType.CREATE); assertNotEquals(first, DmsWorkflowSourceKey.of("flow", "task-2", DmsWorkflowFileType.CREATE)); assertNotEquals(first, DmsWorkflowSourceKey.of("flow", "task-1", DmsWorkflowFileType.REVISE)); assertEquals(first, DmsWorkflowSourceKey.of(" flow ", " task-1 ", DmsWorkflowFileType.CREATE)); assertTrue(DmsWorkflowSourceKey.of("f".repeat(120), "t".repeat(160), DmsWorkflowFileType.CREATE).length() <= 120); } @Test void rejectsReplacementAttachmentEvenWhenAuditHasPassed() { DmsWorkflowFilePrepareForm form = form(); form.setUrl("/api/file/Image/annex/replacement.docx"); assertThrows(DataException.class, () -> validator.validateNew(newAudit(), form)); } @Test void usesApprovedAttachmentMetadataAndAllowsEquivalentAbsoluteUrl() { DmsWorkflowFilePrepareForm form = form(); form.setUrl("https://files.example" + URL); assertEquals(FILE, validator.validateNew(newAudit(), form)); } @Test void rejectsChangedDocumentMetadataAndMalformedApprovalAttachment() { DmsWorkflowFilePrepareForm form = form(); form.setDocumentNo("OTHER"); assertThrows(DataException.class, () -> validator.validateNew(newAudit(), form)); assertThrows(DataException.class, () -> validator.approvedFile("not-json", URL)); assertThrows(DataException.class, () -> validator.approvedFile(FILE, "/api/file/Image/annex/%2e%2e")); } @Test void revisionMustUseTheFileCenterVersionMappedFromTheApprovedBusinessVersion() { DmsWenjianXiudingShenheEntity audit = new DmsWenjianXiudingShenheEntity(); audit.setWenjianId("business-file"); audit.setYuanWenjianBanbenId("business-version"); audit.setWenjianMingcheng("manual"); audit.setWenjianMuluId("00000000-0000-0000-0000-000000000001"); audit.setGuishuBumenId("quality"); audit.setWenjian(FILE); DmsWenjianBanbenEntity version = new DmsWenjianBanbenEntity(); version.setWenjianId("business-file"); UUID approvedId = UUID.randomUUID(); version.setWenjianZhongxinBanbenId(approvedId.toString()); when(versions.selectById("tenant", "business-version")).thenReturn(version); DmsWorkflowFilePrepareForm form = form(); form.setVersionId(UUID.randomUUID()); assertThrows(DataException.class, () -> validator.validateRevision("tenant", audit, form)); form.setVersionId(approvedId); assertEquals(FILE, validator.validateRevision("tenant", audit, form)); version.setWenjianZhongxinBanbenId(null); assertThrows(DataException.class, () -> validator.validateRevision("tenant", audit, form)); version.setLaiyuanDanjuLeixing("xinzeng_shenhe"); version.setLaiyuanDanjuId("original-audit"); DmsWenjianXinzengShenheEntity source = newAudit(); source.setFlowId("shared-flow"); source.setFlowTaskId("original-task"); when(newAudits.selectOne(org.mockito.ArgumentMatchers.any())).thenReturn(source); jnpf.dmsEntity.storage.vo.DmsFileUploadVO registered = new jnpf.dmsEntity.storage.vo.DmsFileUploadVO(); registered.setFileVersionId(approvedId); when(objects.selectUploadBySource("tenant", "jnpf-file", DmsWorkflowSourceKey.of("shared-flow", "original-task", DmsWorkflowFileType.CREATE))) .thenReturn(registered); assertEquals(FILE, validator.validateRevision("tenant", audit, form)); form.setVersionId(UUID.randomUUID()); assertThrows(DataException.class, () -> validator.validateRevision("tenant", audit, form)); } private DmsWenjianXinzengShenheEntity newAudit() { DmsWenjianXinzengShenheEntity audit = new DmsWenjianXinzengShenheEntity(); audit.setFlowState(2); audit.setWenjianBianhao("DOC-1"); audit.setWenjianMingcheng("manual"); audit.setWenjianMuluId("00000000-0000-0000-0000-000000000001"); audit.setGuishuBumenId("quality"); audit.setWenjian(FILE); return audit; } private DmsWorkflowFilePrepareForm form() { DmsWorkflowFilePrepareForm form = new DmsWorkflowFilePrepareForm(); form.setDocumentNo("DOC-1"); form.setFolderId(UUID.fromString("00000000-0000-0000-0000-000000000001")); form.setDocumentName("manual"); form.setResponsibleDeptId("quality"); form.setUrl(URL); return form; } }