package jnpf.bizcommon.audit.service; import jnpf.audit.AuditConsts; import jnpf.audit.model.AuditEventDTO; import jnpf.audit.model.AuditRelatedSignDTO; import jnpf.bizcommon.audit.service.sign.AuditSignEvidence; import jnpf.bizcommon.audit.service.sign.AuditSignEvidenceReader; import jnpf.util.JsonUtil; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import java.util.Arrays; import java.util.Date; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; 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.anyList; import static org.mockito.ArgumentMatchers.eq; 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 DataInterfaceSignAuditServiceTest { @Test void createsPrimaryAndReviewEventsForDmsFolder() { AuditSignEvidenceReader reader = mock(AuditSignEvidenceReader.class); AuditEventService eventService = mock(AuditEventService.class); DataInterfaceSignAuditService service = new DataInterfaceSignAuditService(reader, eventService); Map evidences = new LinkedHashMap<>(); evidences.put("sign-primary", evidence("sign-primary", false)); evidences.put("sign-review", evidence("sign-review", true)); when(reader.read(anyList(), eq("tenant-1"))).thenReturn(evidences); AuditEventDTO business = businessEvent(); business.setRelatedSigns(Arrays.asList( new AuditRelatedSignDTO("sign-primary", "PRIMARY"), new AuditRelatedSignDTO("sign-review", "REVIEW"))); service.recordRelatedSign(business); ArgumentCaptor captor = ArgumentCaptor.forClass(AuditEventDTO.class); verify(eventService, org.mockito.Mockito.times(2)).saveIdempotent(captor.capture()); List events = captor.getAllValues(); assertTrue(events.get(0).getClientEventId().startsWith("DFS-")); assertTrue(events.get(1).getClientEventId().startsWith("DFS-")); assertEquals("op-1", events.get(0).getOperationId()); assertEquals("DMS_FOLDER", events.get(0).getBizType()); assertEquals("电子签名", events.get(0).getActionLabel()); assertEquals("复审签名", events.get(1).getActionLabel()); assertEquals("PRIMARY", JsonUtil.stringToMap(events.get(0).getExtra()).get("signatureRole")); assertEquals("REVIEW", JsonUtil.stringToMap(events.get(1).getExtra()).get("signatureRole")); } @Test void rejectsMissingDmsFolderSignatureEvidenceForSpoolRetry() { AuditSignEvidenceReader reader = mock(AuditSignEvidenceReader.class); AuditEventService eventService = mock(AuditEventService.class); DataInterfaceSignAuditService service = new DataInterfaceSignAuditService(reader, eventService); when(reader.read(anyList(), eq("tenant-1"))).thenReturn(java.util.Collections.emptyMap()); AuditEventDTO business = businessEvent(); business.setRelatedSigns(java.util.Collections.singletonList( new AuditRelatedSignDTO("missing", "PRIMARY"))); assertThrows(IllegalStateException.class, () -> service.recordRelatedSign(business)); } @Test void keepsLegacyDataInterfaceIdPrefix() { AuditSignEvidenceReader reader = mock(AuditSignEvidenceReader.class); AuditEventService eventService = mock(AuditEventService.class); DataInterfaceSignAuditService service = new DataInterfaceSignAuditService(reader, eventService); when(reader.read(anyList(), eq("tenant-1"))).thenReturn(java.util.Collections.singletonMap( "legacy-sign", evidence("legacy-sign", false))); AuditEventDTO business = businessEvent(); business.setBizType("DATA_INTERFACE"); business.setRelatedSignId("legacy-sign"); service.recordRelatedSign(business); ArgumentCaptor captor = ArgumentCaptor.forClass(AuditEventDTO.class); verify(eventService).saveIdempotent(captor.capture()); assertTrue(captor.getValue().getClientEventId().startsWith("DIS-")); } @Test void createsValidatedDmsFileSignatureEvent() { AuditSignEvidenceReader reader = mock(AuditSignEvidenceReader.class); AuditEventService eventService = mock(AuditEventService.class); DataInterfaceSignAuditService service = new DataInterfaceSignAuditService(reader, eventService); when(reader.read(anyList(), eq("tenant-1"))).thenReturn(java.util.Collections.singletonMap( "file-sign", evidence("file-sign", false))); AuditEventDTO business = businessEvent(); business.setBizType("DMS_FILE"); business.setBizCode("MM-R02"); business.setTargetTable("dms_documents"); business.setTargetId("document-1"); business.setRelatedSigns(java.util.Collections.singletonList( new AuditRelatedSignDTO("file-sign", null))); service.recordRelatedSign(business); ArgumentCaptor captor = ArgumentCaptor.forClass(AuditEventDTO.class); verify(eventService).saveIdempotent(captor.capture()); AuditEventDTO signEvent = captor.getValue(); assertTrue(signEvent.getClientEventId().startsWith("DFF-")); assertEquals("DMS_FILE", signEvent.getBizType()); assertEquals("电子签名", signEvent.getActionLabel()); assertEquals("dms_documents", JsonUtil.stringToMap(signEvent.getExtra()) .get("businessTargetTable")); } @Test void createsRelatedSignatureForAuditLogBusinessAction() { AuditSignEvidenceReader reader = mock(AuditSignEvidenceReader.class); AuditEventService eventService = mock(AuditEventService.class); DataInterfaceSignAuditService service = new DataInterfaceSignAuditService(reader, eventService); when(reader.read(anyList(), eq("tenant-1"))).thenReturn(java.util.Collections.singletonMap( "loan-sign", evidence("loan-sign", false))); AuditEventDTO business = businessEvent(); business.setEventType(AuditConsts.TYPE_BIZ_ACTION); business.setSourceLayer(2); business.setBizType("DMS_LOAN_COPY"); business.setActionCode("LOAN_COPY_RECEIVE"); business.setRelatedSignId("loan-sign"); service.recordRelatedSign(business); ArgumentCaptor captor = ArgumentCaptor.forClass(AuditEventDTO.class); verify(eventService).saveIdempotent(captor.capture()); AuditEventDTO signEvent = captor.getValue(); assertTrue(signEvent.getClientEventId().startsWith("DLC-")); assertEquals(AuditConsts.TYPE_E_SIGNATURE, signEvent.getEventType()); assertEquals("电子签名", signEvent.getActionLabel()); assertEquals("op-1", signEvent.getOperationId()); assertEquals("loan-sign", signEvent.getTargetId()); } @Test void ignoresSignatureEventsToAvoidGeneratingNestedSignatureFacts() { AuditSignEvidenceReader reader = mock(AuditSignEvidenceReader.class); AuditEventService eventService = mock(AuditEventService.class); DataInterfaceSignAuditService service = new DataInterfaceSignAuditService(reader, eventService); AuditEventDTO signature = businessEvent(); signature.setEventType(AuditConsts.TYPE_E_SIGNATURE); signature.setRelatedSignId("sign-1"); service.recordRelatedSign(signature); verify(reader, never()).read(anyList(), eq("tenant-1")); verify(eventService, never()).saveIdempotent(org.mockito.ArgumentMatchers.any()); } @Test @SuppressWarnings("unchecked") void createsOneDmsPermissionSignatureWithAllBatchTargetIds() { AuditSignEvidenceReader reader = mock(AuditSignEvidenceReader.class); AuditEventService eventService = mock(AuditEventService.class); DataInterfaceSignAuditService service = new DataInterfaceSignAuditService(reader, eventService); when(reader.read(anyList(), eq("tenant-1"))).thenReturn(java.util.Collections.singletonMap( "permission-sign", evidence("permission-sign", false))); AuditEventDTO business = businessEvent(); business.setBizType("DMS_PERMISSION"); business.setBizCode("folder-1"); business.setTargetTable("dms_folders"); business.setTargetId("folder-1"); Map first = new LinkedHashMap<>(); first.put("resourceId", "folder-1"); Map second = new LinkedHashMap<>(); second.put("resourceId", "document-2"); Map extra = new LinkedHashMap<>(); extra.put("affectedTargets", Arrays.asList(first, second)); business.setExtra(JsonUtil.getObjectToString(extra)); business.setRelatedSigns(java.util.Collections.singletonList( new AuditRelatedSignDTO("permission-sign", null))); service.recordRelatedSign(business); ArgumentCaptor captor = ArgumentCaptor.forClass(AuditEventDTO.class); verify(eventService).saveIdempotent(captor.capture()); AuditEventDTO signEvent = captor.getValue(); assertTrue(signEvent.getClientEventId().startsWith("DFP-")); assertEquals("DMS_PERMISSION", signEvent.getBizType()); assertEquals("电子签名", signEvent.getActionLabel()); List targetIds = (List) JsonUtil.stringToMap(signEvent.getExtra()) .get("affectedTargetIds"); assertEquals(Arrays.asList("folder-1", "document-2"), targetIds); } private AuditEventDTO businessEvent() { return AuditEventDTO.builder() .clientEventId("business-1") .operationId("op-1") .eventTime(new Date()) .tenantId("tenant-1") .operatorId("user-1") .operatorName("用户一") .appName("jnpf-dms") .bizModule("DMS") .bizType("DMS_FOLDER") .bizCode("folder-1") .targetTable("dms_folders") .targetId("folder-1") .eventType(AuditConsts.TYPE_DATA_CHANGE) .actionCode("UPDATE") .recordTitle("/质量管理/报告") .build(); } private AuditSignEvidence evidence(String id, boolean review) { return new AuditSignEvidence(id, "account-1", "user-1", "原因", "UPDATE", new Date(), "{\"is_review_button\":" + review + "}"); } }