刘光辉
119 分钟以前 06f314545ac3514d7ce28939920866ae8188d31c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
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);
    }
}