package jnpf.dmsService; import jnpf.dmsEntity.wenjianbianhao.DmsFlowEventType; import jnpf.dmsService.impl.DmsWenjianBianhaoApplicationServiceImpl; import org.junit.jupiter.api.Test; import org.springframework.aop.framework.ProxyFactory; import org.springframework.dao.DuplicateKeyException; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource; import org.springframework.transaction.interceptor.TransactionInterceptor; import org.springframework.transaction.support.SimpleTransactionStatus; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; class DmsWenjianBianhaoFlowServiceTest { private final DmsWenjianBianhaoApplicationService applications = mock(DmsWenjianBianhaoApplicationService.class); private final DmsWenjianBianhaoFlowService service = new DmsWenjianBianhaoFlowService(applications); @Test void successDoesNotMarkFailure() { service.sync("flow", "task", 2, DmsFlowEventType.END); verify(applications, never()).markIssuanceFailed(any(), any()); } @Test void failureIsMarkedAndOriginalErrorIsRethrown() { var failure = new DuplicateKeyException("number already issued"); doThrow(failure).when(applications).syncApplicationFlow("flow", "task", 2, DmsFlowEventType.END); assertSame(failure, assertThrows(DuplicateKeyException.class, () -> service.sync("flow", "task", 2, DmsFlowEventType.END))); var order = inOrder(applications); order.verify(applications).syncApplicationFlow("flow", "task", 2, DmsFlowEventType.END); order.verify(applications).markIssuanceFailed("flow", "task"); } @Test void nonIssuanceFailureDoesNotChangeRequestNumber() { for (var event : DmsFlowEventType.values()) { if (event == DmsFlowEventType.END) continue; doThrow(new IllegalStateException("failed")).when(applications) .syncApplicationFlow("flow", "task", 2, event); assertThrows(IllegalStateException.class, () -> service.sync("flow", "task", 2, event)); } doThrow(new IllegalStateException("failed")).when(applications) .syncApplicationFlow("flow", "task", 1, DmsFlowEventType.END); assertThrows(IllegalStateException.class, () -> service.sync("flow", "task", 1, DmsFlowEventType.END)); verify(applications, never()).markIssuanceFailed(any(), any()); } @Test void markingFailureDoesNotHideOriginalError() { var original = new DuplicateKeyException("duplicate"); var marking = new IllegalStateException("database unavailable"); doThrow(original).when(applications).syncApplicationFlow("flow", "task", 2, DmsFlowEventType.END); doThrow(marking).when(applications).markIssuanceFailed("flow", "task"); assertSame(original, assertThrows(DuplicateKeyException.class, () -> service.sync("flow", "task", 2, DmsFlowEventType.END))); assertArrayEquals(new Throwable[]{marking}, original.getSuppressed()); } @Test void springProxyRollsBackIssuanceBeforeStartingAndCommittingFailureMarker() { var target = mock(DmsWenjianBianhaoApplicationServiceImpl.class); var transactions = mock(PlatformTransactionManager.class); var issuance = new SimpleTransactionStatus(); var marker = new SimpleTransactionStatus(); when(transactions.getTransaction(any())).thenReturn(issuance, marker); var proxy = new ProxyFactory(target); proxy.setInterfaces(DmsWenjianBianhaoApplicationService.class); proxy.addAdvice(new TransactionInterceptor(transactions, new AnnotationTransactionAttributeSource())); var flow = new DmsWenjianBianhaoFlowService((DmsWenjianBianhaoApplicationService) proxy.getProxy()); doThrow(new DuplicateKeyException("duplicate")).when(target) .syncApplicationFlow("flow", "task", 2, DmsFlowEventType.END); assertThrows(DuplicateKeyException.class, () -> flow.sync("flow", "task", 2, DmsFlowEventType.END)); var order = inOrder(transactions, target); order.verify(transactions).getTransaction(argThat(d -> d.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED)); order.verify(target).syncApplicationFlow("flow", "task", 2, DmsFlowEventType.END); order.verify(transactions).rollback(issuance); order.verify(transactions).getTransaction(argThat(d -> d.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW)); order.verify(target).markIssuanceFailed("flow", "task"); order.verify(transactions).commit(marker); } }