package jnpf.dmsIntegration.audit; import jnpf.audit.model.AuditEventDTO; import jnpf.audit.sdk.*; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.ObjectProvider; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import java.util.Date; import java.util.UUID; import static jnpf.dmsIntegration.audit.DmsBusinessChangeAudit.values; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; class DmsBusinessChangeAuditTest { final AuditEventPublisher publisher = mock(AuditEventPublisher.class); final DmsSystemAudit system = mock(DmsSystemAudit.class); final ObjectProvider clients = mock(ObjectProvider.class); final AuditClient client = new AuditClient(new AuditContextCollector("jnpf-dms") { @Override public AuditEventDTO fill(AuditEventDTO event) { event.setClientEventId(UUID.randomUUID().toString()); event.setEventTime(new Date()); return event; } }, publisher, true); final DmsBusinessChangeAudit audit = new DmsBusinessChangeAudit(clients, system); void request() { RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(new MockHttpServletRequest())); doAnswer(call -> { ((java.util.function.Consumer)call.getArgument(0)).accept(client); return null; }) .when(clients).ifAvailable(any()); } void record() { audit.record("tenant", "CHANGE", "状态变更", "dms_version_states", "version", values("lifecycle_status", "PENDING_EFFECTIVE"), values("lifecycle_status", "EFFECTIVE"), "批准文件按日期生效", values("document_id", "document", "biz_sign", "signature")); } @AfterEach void clear() { if (TransactionSynchronizationManager.isSynchronizationActive()) { for (var sync : TransactionSynchronizationManager.getSynchronizations()) sync.afterCompletion(TransactionSynchronization.STATUS_ROLLED_BACK); TransactionSynchronizationManager.clearSynchronization(); } TransactionSynchronizationManager.setActualTransactionActive(false); RequestContextHolder.resetRequestAttributes(); org.slf4j.MDC.clear(); } @Test void successfulCommitPublishesFrozenDiffAndSignatureOnlyAfterCommit() { request(); TransactionSynchronizationManager.setActualTransactionActive(true); TransactionSynchronizationManager.initSynchronization(); record(); verifyNoInteractions(publisher); for (var sync : TransactionSynchronizationManager.getSynchronizations()) sync.afterCommit(); org.mockito.ArgumentCaptor> captor = org.mockito.ArgumentCaptor.forClass(java.util.List.class); verify(publisher).publishAsync(captor.capture()); assertEquals(1, captor.getValue().size()); var event = captor.getValue().getFirst(); assertEquals("tenant", event.getTenantId()); assertEquals("dms_version_states", event.getTargetTable()); assertTrue(event.getFieldDiffs().contains("PENDING_EFFECTIVE")); assertTrue(event.getFieldDiffs().contains("EFFECTIVE")); assertEquals("signature", event.getRelatedSigns().getFirst().getSignId()); verifyNoInteractions(system); } @Test void rollbackDoesNotPublish() { request(); TransactionSynchronizationManager.setActualTransactionActive(true); TransactionSynchronizationManager.initSynchronization(); record(); clear(); verifyNoInteractions(publisher, system); } @Test void noChangeDoesNotCreateAnEvent() { audit.record("tenant", "CHANGE", "状态变更", "dms_documents", "record", values("main_document_id", "main"), values("main_document_id", "main"), null, values()); verifyNoInteractions(clients, publisher, system); } @Test void backgroundExecutionUsesSystemIdentityAndExplicitTenant() { record(); verify(system).record(argThat(event -> "0".equals(event.getOperatorId()) && "tenant".equals(event.getTenantId()) && event.getReason() != null)); verifyNoInteractions(clients, publisher); } }