This is an automated email from the ASF dual-hosted git repository. ningjiang pushed a commit to branch SCB-817 in repository https://gitbox.apache.org/repos/asf/incubator-servicecomb-saga.git
commit 5e5aadef15cbd69f6c04dcb575f12ef6fce6f697 Author: Willem Jiang <[email protected]> AuthorDate: Thu Aug 23 16:42:40 2018 +0800 SCB-817 Added the unit tests of TCC related Aspect --- .../omega/transaction/tcc/TccEventService.java | 2 - .../transaction/tcc/TccParticipatorAspect.java | 8 +- .../tcc/TccStartAnnotationProcessor.java | 14 +- .../saga/omega/transaction/tcc/TccStartAspect.java | 4 +- .../transaction/tcc/events/ParticipatedEvent.java | 24 +++ .../transaction/tcc/events/TccEndedEvent.java | 14 +- .../transaction/tcc/events/TccStartedEvent.java | 4 - .../transaction/tcc/TccParticipatorAspectTest.java | 169 +++++++++++++++++++++ .../tcc/TccStartAnnotationProcessorTest.java | 155 +++++++++++++++++++ .../omega/transaction/tcc/TccStartAspectTest.java | 164 ++++++++++++++++++++ 10 files changed, 534 insertions(+), 24 deletions(-) diff --git a/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/TccEventService.java b/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/TccEventService.java index a722f49..48ad743 100644 --- a/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/TccEventService.java +++ b/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/TccEventService.java @@ -38,7 +38,5 @@ public interface TccEventService { AlphaResponse TccTransactionStart(TccStartedEvent tccStartEvent); AlphaResponse TccTransactionStop(TccEndedEvent tccEndEvent); - - AlphaResponse send(TxEvent event); } diff --git a/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/TccParticipatorAspect.java b/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/TccParticipatorAspect.java index e64bc2a..a78d819 100644 --- a/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/TccParticipatorAspect.java +++ b/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/TccParticipatorAspect.java @@ -61,14 +61,14 @@ public class TccParticipatorAspect { try { Object result = joinPoint.proceed(); // Send the participate message back - tccEventService.participate(new ParticipatedEvent(context.globalTxId(), context.localTxId(), localTxId, cancelMethod, confirmMethod, - TransactionStatus.Succeed)); + tccEventService.participate(new ParticipatedEvent(context.globalTxId(), context.localTxId(), localTxId, confirmMethod, + cancelMethod, TransactionStatus.Succeed)); LOG.debug("Participate Transaction with context {} has finished.", context); return result; } catch (Throwable throwable) { // Now we don't handle the error message - tccEventService.participate(new ParticipatedEvent(context.globalTxId(), context.localTxId(), localTxId, cancelMethod, - confirmMethod, TransactionStatus.Failed)); + tccEventService.participate(new ParticipatedEvent(context.globalTxId(), context.localTxId(), localTxId, confirmMethod, + cancelMethod, TransactionStatus.Failed)); LOG.error("Participate Transaction with context {} failed.", context, throwable); throw throwable; } finally { diff --git a/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/TccStartAnnotationProcessor.java b/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/TccStartAnnotationProcessor.java index 26621d1..55198dd 100644 --- a/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/TccStartAnnotationProcessor.java +++ b/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/TccStartAnnotationProcessor.java @@ -21,13 +21,11 @@ import javax.transaction.TransactionalException; import org.apache.servicecomb.saga.common.TransactionStatus; import org.apache.servicecomb.saga.omega.context.OmegaContext; import org.apache.servicecomb.saga.omega.transaction.AlphaResponse; -import org.apache.servicecomb.saga.omega.transaction.EventAwareInterceptor; import org.apache.servicecomb.saga.omega.transaction.OmegaException; -import org.apache.servicecomb.saga.omega.transaction.TxAbortedEvent; import org.apache.servicecomb.saga.omega.transaction.tcc.events.TccEndedEvent; import org.apache.servicecomb.saga.omega.transaction.tcc.events.TccStartedEvent; -public class TccStartAnnotationProcessor implements EventAwareInterceptor { +public class TccStartAnnotationProcessor { private final OmegaContext omegaContext; private final TccEventService eventService; @@ -37,9 +35,7 @@ public class TccStartAnnotationProcessor implements EventAwareInterceptor { this.eventService = eventService; } - @Override - public AlphaResponse preIntercept(String parentTxId, String compensationMethod, int timeout, String retriesMethod, - int retries, Object... message) { + public AlphaResponse preIntercept(String parentTxId, String methodName, int timeout) { try { return eventService.TccTransactionStart(new TccStartedEvent(omegaContext.globalTxId(), omegaContext.localTxId())); } catch (OmegaException e) { @@ -47,14 +43,12 @@ public class TccStartAnnotationProcessor implements EventAwareInterceptor { } } - @Override - public void postIntercept(String parentTxId, String compensationMethod) { + public void postIntercept(String parentTxId, String methodName) { eventService.TccTransactionStop(new TccEndedEvent(omegaContext.globalTxId(), omegaContext.localTxId(), TransactionStatus.Succeed)); } - @Override - public void onError(String parentTxId, String compensationMethod, Throwable throwable) { + public void onError(String parentTxId, String methodName, Throwable throwable) { // Send the cancel event // Do we need to wait for the alpha finish all the transaction eventService.TccTransactionStop(new TccEndedEvent(omegaContext.globalTxId(), omegaContext.localTxId(), diff --git a/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/TccStartAspect.java b/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/TccStartAspect.java index f6d1d77..62a2873 100644 --- a/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/TccStartAspect.java +++ b/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/TccStartAspect.java @@ -20,9 +20,7 @@ import java.lang.invoke.MethodHandles; import java.lang.reflect.Method; import org.apache.servicecomb.saga.omega.context.OmegaContext; -import org.apache.servicecomb.saga.omega.context.annotations.SagaStart; import org.apache.servicecomb.saga.omega.context.annotations.TccStart; -import org.apache.servicecomb.saga.omega.transaction.MessageSender; import org.apache.servicecomb.saga.omega.transaction.OmegaException; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; @@ -49,7 +47,7 @@ public class TccStartAspect { initializeOmegaContext(); Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); - tccStartAnnotationProcessor.preIntercept(context.globalTxId(), method.toString(), tccStart.timeout(), "", 0); + tccStartAnnotationProcessor.preIntercept(context.globalTxId(), method.toString(), tccStart.timeout()); LOG.debug("Initialized context {} before execution of method {}", context, method.toString()); try { diff --git a/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/events/ParticipatedEvent.java b/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/events/ParticipatedEvent.java index 3372f8e..ac2dcb9 100644 --- a/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/events/ParticipatedEvent.java +++ b/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/events/ParticipatedEvent.java @@ -38,4 +38,28 @@ public class ParticipatedEvent { this.cancelMethod = cancelMethod; this.status = status; } + + public String getGlobalTxId() { + return globalTxId; + } + + public String getLocalTxId() { + return localTxId; + } + + public String getParentTxId() { + return parentTxId; + } + + public String getConfirmMethod() { + return confirmMethod; + } + + public String getCancelMethod() { + return cancelMethod; + } + + public TransactionStatus getStatus() { + return status; + } } diff --git a/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/events/TccEndedEvent.java b/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/events/TccEndedEvent.java index 7c666b2..31a187f 100644 --- a/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/events/TccEndedEvent.java +++ b/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/events/TccEndedEvent.java @@ -22,7 +22,19 @@ public class TccEndedEvent { private final String globalTxId; private final String localTxId; private final TransactionStatus status; - + + + public String getGlobalTxId() { + return globalTxId; + } + + public String getLocalTxId() { + return localTxId; + } + + public TransactionStatus getStatus() { + return status; + } public TccEndedEvent(String globalTxId, String localTxId, TransactionStatus status) { diff --git a/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/events/TccStartedEvent.java b/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/events/TccStartedEvent.java index edd0333..8449cb4 100644 --- a/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/events/TccStartedEvent.java +++ b/omega/omega-transaction/src/main/java/org/apache/servicecomb/saga/omega/transaction/tcc/events/TccStartedEvent.java @@ -20,17 +20,13 @@ public class TccStartedEvent { private final String globalTxId; private final String localTxId; - public String getGlobalTxId() { return globalTxId; } - public String getLocalTxId() { return localTxId; } - - public TccStartedEvent(String globalTxId, String localTxId) { this.globalTxId = globalTxId; this.localTxId = localTxId; diff --git a/omega/omega-transaction/src/test/java/org/apache/servicecomb/saga/omega/transaction/tcc/TccParticipatorAspectTest.java b/omega/omega-transaction/src/test/java/org/apache/servicecomb/saga/omega/transaction/tcc/TccParticipatorAspectTest.java new file mode 100644 index 0000000..8e6b36e --- /dev/null +++ b/omega/omega-transaction/src/test/java/org/apache/servicecomb/saga/omega/transaction/tcc/TccParticipatorAspectTest.java @@ -0,0 +1,169 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.saga.omega.transaction.tcc; + +import static com.seanyinx.github.unit.scaffolding.AssertUtils.expectFailing; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import org.apache.servicecomb.saga.common.TransactionStatus; +import org.apache.servicecomb.saga.omega.context.IdGenerator; +import org.apache.servicecomb.saga.omega.context.OmegaContext; +import org.apache.servicecomb.saga.omega.context.annotations.TccStart; +import org.apache.servicecomb.saga.omega.transaction.AlphaResponse; +import org.apache.servicecomb.saga.omega.transaction.annotations.Compensable; +import org.apache.servicecomb.saga.omega.transaction.annotations.Participate; +import org.apache.servicecomb.saga.omega.transaction.tcc.events.ParticipatedEvent; +import org.apache.servicecomb.saga.omega.transaction.tcc.events.TccEndedEvent; +import org.apache.servicecomb.saga.omega.transaction.tcc.events.TccStartedEvent; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.reflect.MethodSignature; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +public class TccParticipatorAspectTest { + private final ProceedingJoinPoint joinPoint = Mockito.mock(ProceedingJoinPoint.class); + private final MethodSignature methodSignature = Mockito.mock(MethodSignature.class); + private final String globalTxId = UUID.randomUUID().toString(); + private final String localTxId = UUID.randomUUID().toString(); + private final String newLocalTxId = UUID.randomUUID().toString(); + + private final List<ParticipatedEvent> participatedEvents = new ArrayList<>(); + private final AlphaResponse response = new AlphaResponse(false); + private final TccEventService eventService = new TccEventService() { + @Override + public void onConnected() { + + } + + @Override + public void onDisconnected() { + + } + + @Override + public void close() { + + } + + @Override + public String target() { + return null; + } + + @Override + public AlphaResponse participate(ParticipatedEvent participateEvent) { + participatedEvents.add(participateEvent); + return response; + } + + @Override + public AlphaResponse TccTransactionStart(TccStartedEvent tccStartEvent) { + return null; + } + + @Override + public AlphaResponse TccTransactionStop(TccEndedEvent tccEndEvent) { + return null; + } + + }; + + + @SuppressWarnings("unchecked") + private final IdGenerator<String> idGenerator = Mockito.mock(IdGenerator.class); + + private final OmegaContext omegaContext = new OmegaContext(idGenerator); + private final Participate participate = mock(Participate.class); + + private final TccParticipatorAspect aspect = new TccParticipatorAspect(eventService, omegaContext); + + + @Before + public void setUp() throws Exception { + when(idGenerator.nextId()).thenReturn(newLocalTxId); + when(joinPoint.getSignature()).thenReturn(methodSignature); + when(joinPoint.getTarget()).thenReturn(this); + + when(methodSignature.getMethod()).thenReturn(this.getClass().getDeclaredMethod("doNothing")); + when(participate.cancelMethod()).thenReturn("cancelMethod"); + when(participate.confirmMethod()).thenReturn("confirmMethod"); + + omegaContext.setGlobalTxId(globalTxId); + omegaContext.setLocalTxId(localTxId); + } + + @Test + public void participateMethodIsCalledSuccessed() throws Throwable { + aspect.advise(joinPoint, participate); + + assertThat(participatedEvents.size(), is(1)); + ParticipatedEvent participatedEvent = participatedEvents.get(0); + + assertThat(participatedEvent.getGlobalTxId(), is(globalTxId)); + assertThat(participatedEvent.getParentTxId(), is(localTxId)); + assertThat(participatedEvent.getLocalTxId(), is(newLocalTxId)); + assertThat(participatedEvent.getStatus(), is(TransactionStatus.Succeed)); + assertThat(participatedEvent.getCancelMethod(), is("cancelMethod")); + assertThat(participatedEvent.getConfirmMethod(), is("confirmMethod")); + + assertThat(omegaContext.globalTxId(), is(globalTxId)); + assertThat(omegaContext.localTxId(), is(localTxId)); + } + + @Test + public void participateMethodIsCalledFailed() throws Throwable { + RuntimeException oops = new RuntimeException("oops"); + + when(joinPoint.proceed()).thenThrow(oops); + + try { + aspect.advise(joinPoint, participate); + expectFailing(RuntimeException.class); + } catch (RuntimeException e) { + assertThat(e, is(oops)); + } + + assertThat(participatedEvents.size(), is(1)); + ParticipatedEvent participatedEvent = participatedEvents.get(0); + + assertThat(participatedEvent.getGlobalTxId(), is(globalTxId)); + assertThat(participatedEvent.getParentTxId(), is(localTxId)); + assertThat(participatedEvent.getLocalTxId(), is(newLocalTxId)); + assertThat(participatedEvent.getStatus(), is(TransactionStatus.Failed)); + assertThat(participatedEvent.getCancelMethod(), is("cancelMethod")); + assertThat(participatedEvent.getConfirmMethod(), is("confirmMethod")); + + + assertThat(omegaContext.globalTxId(), is(globalTxId)); + assertThat(omegaContext.localTxId(), is(localTxId)); + } + + private String doNothing() { + return "doNothing"; + } + +} diff --git a/omega/omega-transaction/src/test/java/org/apache/servicecomb/saga/omega/transaction/tcc/TccStartAnnotationProcessorTest.java b/omega/omega-transaction/src/test/java/org/apache/servicecomb/saga/omega/transaction/tcc/TccStartAnnotationProcessorTest.java new file mode 100644 index 0000000..95f8137 --- /dev/null +++ b/omega/omega-transaction/src/test/java/org/apache/servicecomb/saga/omega/transaction/tcc/TccStartAnnotationProcessorTest.java @@ -0,0 +1,155 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.servicecomb.saga.omega.transaction.tcc; + +import static com.seanyinx.github.unit.scaffolding.AssertUtils.expectFailing; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.mockito.Mockito.mock; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import javax.transaction.TransactionalException; + +import org.apache.servicecomb.saga.common.TransactionStatus; +import org.apache.servicecomb.saga.omega.context.IdGenerator; +import org.apache.servicecomb.saga.omega.context.OmegaContext; +import org.apache.servicecomb.saga.omega.transaction.AlphaResponse; +import org.apache.servicecomb.saga.omega.transaction.OmegaException; +import org.apache.servicecomb.saga.omega.transaction.tcc.events.ParticipatedEvent; +import org.apache.servicecomb.saga.omega.transaction.tcc.events.TccEndedEvent; +import org.apache.servicecomb.saga.omega.transaction.tcc.events.TccStartedEvent; +import org.hamcrest.core.Is; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class TccStartAnnotationProcessorTest { + private final String globalTxId = UUID.randomUUID().toString(); + private final AlphaResponse response = new AlphaResponse(false); + private final AlphaResponse abortResponse = new AlphaResponse(true); + private final List<TccStartedEvent> startedEvents = new ArrayList<>(); + private final List<TccEndedEvent> endedEvents = new ArrayList<>(); + private boolean throwException = false; + + private final IdGenerator<String> generator = mock(IdGenerator.class); + private final OmegaContext context = new OmegaContext(generator); + private final OmegaException exception = new OmegaException("exception", new RuntimeException("runtime exception")); + private final TccEventService eventService = new TccEventService() { + @Override + public void onConnected() { + + } + + @Override + public void onDisconnected() { + + } + + @Override + public void close() { + + } + + @Override + public String target() { + return null; + } + + @Override + public AlphaResponse participate(ParticipatedEvent participateEvent) { + return null; + } + + @Override + public AlphaResponse TccTransactionStart(TccStartedEvent tccStartEvent) { + if (throwException) { + throw exception; + } + startedEvents.add(tccStartEvent); + return response; + } + + @Override + public AlphaResponse TccTransactionStop(TccEndedEvent tccEndEvent) { + endedEvents.add(tccEndEvent); + return response; + } + + + }; + private final TccStartAnnotationProcessor tccStartAnnotationProcessor = new TccStartAnnotationProcessor(context, + eventService); + + @Before + public void setUp() throws Exception { + context.setGlobalTxId(globalTxId); + context.setLocalTxId(globalTxId); + } + + @Test + public void testSendTccStartEvent() { + AlphaResponse result = tccStartAnnotationProcessor + .preIntercept(null, "TccStartMethod", 0); + + TccStartedEvent event = startedEvents.get(0); + + assertThat(event.getGlobalTxId(), is(globalTxId)); + assertThat(event.getLocalTxId(), is(globalTxId)); + assertThat(result, is(response)); + + } + + @Test + public void testSendTccStartEventFailed() { + throwException = true; + try { + tccStartAnnotationProcessor + .preIntercept(null, "TccStartMethod", 0); + expectFailing(TransactionalException.class); + } catch (TransactionalException e) { + Assert.assertThat(e.getMessage(), Is.is("exception")); + Assert.assertThat(e.getCause(), instanceOf(RuntimeException.class)); + Assert.assertThat(e.getCause().getMessage(), Is.is("runtime exception")); + } + + } + + @Test + public void testSendTccEndEventWithoutError() { + tccStartAnnotationProcessor.postIntercept(null, "TccStartMethod"); + + TccEndedEvent event = endedEvents.get(0); + + assertThat(event.getGlobalTxId(), is(globalTxId)); + assertThat(event.getLocalTxId(), is(globalTxId)); + assertThat(event.getStatus(), is(TransactionStatus.Succeed)); + + } + + @Test + public void testSendTccEndEventWithError() { + tccStartAnnotationProcessor.onError(null, "TccStartMethod", null); + TccEndedEvent event = endedEvents.get(0); + assertThat(event.getGlobalTxId(), is(globalTxId)); + assertThat(event.getLocalTxId(), is(globalTxId)); + assertThat(event.getStatus(), is(TransactionStatus.Failed)); + } +} diff --git a/omega/omega-transaction/src/test/java/org/apache/servicecomb/saga/omega/transaction/tcc/TccStartAspectTest.java b/omega/omega-transaction/src/test/java/org/apache/servicecomb/saga/omega/transaction/tcc/TccStartAspectTest.java new file mode 100644 index 0000000..005af67 --- /dev/null +++ b/omega/omega-transaction/src/test/java/org/apache/servicecomb/saga/omega/transaction/tcc/TccStartAspectTest.java @@ -0,0 +1,164 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.saga.omega.transaction.tcc; + +import static com.seanyinx.github.unit.scaffolding.AssertUtils.expectFailing; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import org.apache.servicecomb.saga.common.TransactionStatus; +import org.apache.servicecomb.saga.omega.context.IdGenerator; +import org.apache.servicecomb.saga.omega.context.OmegaContext; +import org.apache.servicecomb.saga.omega.context.annotations.TccStart; +import org.apache.servicecomb.saga.omega.transaction.AlphaResponse; +import org.apache.servicecomb.saga.omega.transaction.tcc.events.ParticipatedEvent; +import org.apache.servicecomb.saga.omega.transaction.tcc.events.TccEndedEvent; +import org.apache.servicecomb.saga.omega.transaction.tcc.events.TccStartedEvent; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.reflect.MethodSignature; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +public class TccStartAspectTest { + private final ProceedingJoinPoint joinPoint = Mockito.mock(ProceedingJoinPoint.class); + private final MethodSignature methodSignature = Mockito.mock(MethodSignature.class); + private final String globalTxId = UUID.randomUUID().toString(); + private final List<TccStartedEvent> startedEvents = new ArrayList<>(); + private final List<TccEndedEvent> endedEvents = new ArrayList<>(); + private final AlphaResponse response = new AlphaResponse(false); + private final TccEventService eventService = new TccEventService() { + @Override + public void onConnected() { + + } + + @Override + public void onDisconnected() { + + } + + @Override + public void close() { + + } + + @Override + public String target() { + return null; + } + + @Override + public AlphaResponse participate(ParticipatedEvent participateEvent) { + return null; + } + + @Override + public AlphaResponse TccTransactionStart(TccStartedEvent tccStartEvent) { + startedEvents.add(tccStartEvent); + return response; + } + + @Override + public AlphaResponse TccTransactionStop(TccEndedEvent tccEndEvent) { + endedEvents.add(tccEndEvent); + return response; + } + + }; + + + @SuppressWarnings("unchecked") + private final IdGenerator<String> idGenerator = Mockito.mock(IdGenerator.class); + private final TccStart tccStart = Mockito.mock(TccStart.class); + + private final OmegaContext omegaContext = new OmegaContext(idGenerator); + private final TccStartAspect aspect = new TccStartAspect(eventService, omegaContext); + + @Before + public void setUp() throws Exception { + when(idGenerator.nextId()).thenReturn(globalTxId); + when(joinPoint.getSignature()).thenReturn(methodSignature); + + when(methodSignature.getMethod()).thenReturn(this.getClass().getDeclaredMethod("doNothing")); + omegaContext.clear(); + } + + @Test + public void newGlobalTxIdInTccStart() throws Throwable { + aspect.advise(joinPoint, tccStart); + + assertThat(startedEvents.size(), is(1)); + TccStartedEvent startedEvent = startedEvents.get(0); + + assertThat(startedEvent.getGlobalTxId(), is(globalTxId)); + assertThat(startedEvent.getLocalTxId(), is(globalTxId)); + + assertThat(endedEvents.size(), is(1)); + TccEndedEvent endedEvent = endedEvents.get(0); + + assertThat(endedEvent.getGlobalTxId(), is(globalTxId)); + assertThat(endedEvent.getLocalTxId(), is(globalTxId)); + assertThat(endedEvent.getStatus(), is(TransactionStatus.Succeed)); + + + assertThat(omegaContext.globalTxId(), is(nullValue())); + assertThat(omegaContext.localTxId(), is(nullValue())); + } + + @Test + public void clearContextOnTccStartError() throws Throwable { + RuntimeException oops = new RuntimeException("oops"); + + when(joinPoint.proceed()).thenThrow(oops); + + try { + aspect.advise(joinPoint, tccStart); + expectFailing(RuntimeException.class); + } catch (RuntimeException e) { + assertThat(e, is(oops)); + } + + assertThat(startedEvents.size(), is(1)); + TccStartedEvent event = startedEvents.get(0); + + assertThat(event.getGlobalTxId(), is(globalTxId)); + assertThat(event.getLocalTxId(), is(globalTxId)); + + TccEndedEvent endedEvent = endedEvents.get(0); + + assertThat(endedEvent.getGlobalTxId(), is(globalTxId)); + assertThat(endedEvent.getLocalTxId(), is(globalTxId)); + assertThat(endedEvent.getStatus(), is(TransactionStatus.Failed)); + + assertThat(omegaContext.globalTxId(), is(nullValue())); + assertThat(omegaContext.localTxId(), is(nullValue())); + } + + private String doNothing() { + return "doNothing"; + } + + +}
