SGF-897 - Write Unit Tests for transaction event handler framework code.
This commit is contained in:
@@ -22,6 +22,8 @@ import org.apache.geode.cache.TransactionEvent;
|
||||
import org.apache.geode.cache.TransactionWriter;
|
||||
import org.apache.geode.cache.TransactionWriterException;
|
||||
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -45,8 +47,8 @@ public class ComposableTransactionWriter implements TransactionWriter {
|
||||
* the composition of both {@link TransactionWriter} one and {@link TransactionWriter} two.
|
||||
* @see org.apache.geode.cache.TransactionWriter
|
||||
*/
|
||||
public static TransactionWriter compose(TransactionWriter transactionWriterOne,
|
||||
TransactionWriter transactionWriterTwo) {
|
||||
public static @Nullable TransactionWriter compose(@Nullable TransactionWriter transactionWriterOne,
|
||||
@Nullable TransactionWriter transactionWriterTwo) {
|
||||
|
||||
return transactionWriterOne == null ? transactionWriterTwo
|
||||
: transactionWriterTwo == null ? transactionWriterOne
|
||||
@@ -56,7 +58,8 @@ public class ComposableTransactionWriter implements TransactionWriter {
|
||||
private final TransactionWriter transactionWriterOne;
|
||||
private final TransactionWriter transactionWriterTwo;
|
||||
|
||||
private ComposableTransactionWriter(TransactionWriter transactionWriterOne, TransactionWriter transactionWriterTwo) {
|
||||
private ComposableTransactionWriter(@NonNull TransactionWriter transactionWriterOne,
|
||||
@NonNull TransactionWriter transactionWriterTwo) {
|
||||
|
||||
Assert.notNull(transactionWriterOne, "TransactionWriter one must not be null");
|
||||
Assert.notNull(transactionWriterTwo, "TransactionWriter two must not be null");
|
||||
@@ -65,14 +68,34 @@ public class ComposableTransactionWriter implements TransactionWriter {
|
||||
this.transactionWriterTwo = transactionWriterTwo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the first {@link TransactionWriter} in the composition.
|
||||
*
|
||||
* @return a reference to the first {@link TransactionWriter} in the composition.
|
||||
* @see org.apache.geode.cache.TransactionWriter
|
||||
*/
|
||||
protected TransactionWriter getTransactionWriterOne() {
|
||||
return this.transactionWriterOne;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the second {@link TransactionWriter} in the composition.
|
||||
*
|
||||
* @return a reference to the second {@link TransactionWriter} in the composition.
|
||||
* @see org.apache.geode.cache.TransactionWriter
|
||||
*/
|
||||
protected TransactionWriter getTransactionWriterTwo() {
|
||||
return this.transactionWriterTwo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public void beforeCommit(TransactionEvent event) throws TransactionWriterException {
|
||||
|
||||
this.transactionWriterOne.beforeCommit(event);
|
||||
this.transactionWriterTwo.beforeCommit(event);
|
||||
getTransactionWriterOne().beforeCommit(event);
|
||||
getTransactionWriterTwo().beforeCommit(event);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,8 +104,8 @@ public class ComposableTransactionWriter implements TransactionWriter {
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
this.transactionWriterOne.close();
|
||||
this.transactionWriterTwo.close();
|
||||
getTransactionWriterOne().close();
|
||||
getTransactionWriterTwo().close();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,8 +114,8 @@ public class ComposableTransactionWriter implements TransactionWriter {
|
||||
@Override
|
||||
public void init(Properties properties) {
|
||||
|
||||
this.transactionWriterOne.init(properties);
|
||||
this.transactionWriterTwo.init(properties);
|
||||
getTransactionWriterOne().init(properties);
|
||||
getTransactionWriterTwo().init(properties);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,7 +124,7 @@ public class ComposableTransactionWriter implements TransactionWriter {
|
||||
@Override
|
||||
public void initialize(Cache cache, Properties properties) {
|
||||
|
||||
this.transactionWriterOne.initialize(cache, properties);
|
||||
this.transactionWriterTwo.initialize(cache, properties);
|
||||
getTransactionWriterOne().initialize(cache, properties);
|
||||
getTransactionWriterTwo().initialize(cache, properties);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.apache.geode.cache.TransactionWriter;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -57,6 +58,16 @@ public class TransactionListenerAdapter implements TransactionListener, Transact
|
||||
this.applicationEventPublisher = applicationEventPublisher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the configured {@link ApplicationEventPublisher}.
|
||||
*
|
||||
* @return a reference to the configured {@link ApplicationEventPublisher}.
|
||||
* @see org.springframework.context.ApplicationEventPublisher
|
||||
*/
|
||||
protected @NonNull ApplicationEventPublisher getApplicationEventPublisher() {
|
||||
return this.applicationEventPublisher;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@@ -68,7 +79,7 @@ public class TransactionListenerAdapter implements TransactionListener, Transact
|
||||
// all application @TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT) annotated transaction
|
||||
// event handler methods are invoked.
|
||||
|
||||
//this.applicationEventPublisher.publishEvent(TransactionApplicationEvent.of(event));
|
||||
//getApplicationEventPublisher().publishEvent(TransactionApplicationEvent.of(event));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,7 +87,7 @@ public class TransactionListenerAdapter implements TransactionListener, Transact
|
||||
*/
|
||||
@Override
|
||||
public void afterCommit(TransactionEvent event) {
|
||||
this.applicationEventPublisher.publishEvent(TransactionApplicationEvent.of(event));
|
||||
getApplicationEventPublisher().publishEvent(TransactionApplicationEvent.of(event));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,6 +101,6 @@ public class TransactionListenerAdapter implements TransactionListener, Transact
|
||||
*/
|
||||
@Override
|
||||
public void afterRollback(TransactionEvent event) {
|
||||
this.applicationEventPublisher.publishEvent(TransactionApplicationEvent.of(event));
|
||||
getApplicationEventPublisher().publishEvent(TransactionApplicationEvent.of(event));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.data.gemfire.transaction.event;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.apache.geode.cache.Cache;
|
||||
import org.apache.geode.cache.TransactionEvent;
|
||||
import org.apache.geode.cache.TransactionWriter;
|
||||
import org.apache.geode.cache.TransactionWriterException;
|
||||
|
||||
/**
|
||||
* Unit Tests for {@link ComposableTransactionWriter}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.mockito.junit.MockitoJUnitRunner
|
||||
* @see org.apache.geode.cache.TransactionWriter
|
||||
* @see org.springframework.data.gemfire.transaction.event.ComposableTransactionWriter
|
||||
* @since 2.3.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ComposableTransactionWriterUnitTests {
|
||||
|
||||
@Mock
|
||||
private TransactionEvent mockTransactionEvent;
|
||||
|
||||
@Mock
|
||||
private TransactionWriter mockTransactionWriterOne;
|
||||
|
||||
@Mock
|
||||
private TransactionWriter mockTransactionWriterTwo;
|
||||
|
||||
@Test
|
||||
public void composeWithNullIsNullSafeAndReturnsNull() {
|
||||
assertThat(ComposableTransactionWriter.compose(null, null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeWithSingleNonNullTransactionWriterReturnsTransactionWriter() {
|
||||
|
||||
assertThat(ComposableTransactionWriter.compose(this.mockTransactionWriterOne, null))
|
||||
.isEqualTo(this.mockTransactionWriterOne);
|
||||
|
||||
assertThat(ComposableTransactionWriter.compose(null, this.mockTransactionWriterTwo))
|
||||
.isEqualTo(this.mockTransactionWriterTwo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void composeWithTwoTransactionWritersReturnsComposite() {
|
||||
|
||||
TransactionWriter compositeTransactionWriter =
|
||||
ComposableTransactionWriter.compose(this.mockTransactionWriterOne, this.mockTransactionWriterTwo);
|
||||
|
||||
assertThat(compositeTransactionWriter).isInstanceOf(ComposableTransactionWriter.class);
|
||||
|
||||
assertThat(((ComposableTransactionWriter) compositeTransactionWriter).getTransactionWriterOne())
|
||||
.isEqualTo(this.mockTransactionWriterOne);
|
||||
|
||||
assertThat(((ComposableTransactionWriter) compositeTransactionWriter).getTransactionWriterTwo())
|
||||
.isEqualTo(this.mockTransactionWriterTwo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beforeCommitInvokesComposedTransactionWriters() throws Exception {
|
||||
|
||||
ComposableTransactionWriter.compose(this.mockTransactionWriterOne, this.mockTransactionWriterTwo)
|
||||
.beforeCommit(this.mockTransactionEvent);
|
||||
|
||||
verify(this.mockTransactionWriterOne, times(1))
|
||||
.beforeCommit(eq(this.mockTransactionEvent));
|
||||
|
||||
verify(this.mockTransactionWriterTwo, times(1))
|
||||
.beforeCommit(eq(this.mockTransactionEvent));
|
||||
}
|
||||
|
||||
@Test(expected = TransactionWriterException.class)
|
||||
public void beforeCommitWhenFirstTransactionWriterThrowsException()
|
||||
throws Exception {
|
||||
|
||||
doThrow(new TransactionWriterException("TEST"))
|
||||
.when(this.mockTransactionWriterOne).beforeCommit(any(TransactionEvent.class));
|
||||
|
||||
try {
|
||||
ComposableTransactionWriter.compose(this.mockTransactionWriterOne, this.mockTransactionWriterTwo)
|
||||
.beforeCommit(this.mockTransactionEvent);
|
||||
}
|
||||
catch (TransactionWriterException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("TEST");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
finally {
|
||||
|
||||
verify(this.mockTransactionWriterOne, times(1))
|
||||
.beforeCommit(eq(this.mockTransactionEvent));
|
||||
|
||||
verify(this.mockTransactionWriterTwo, never()).beforeCommit(any(TransactionEvent.class));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void closeCallsComposedTransactionWritersCloseMethod() {
|
||||
|
||||
ComposableTransactionWriter.compose(this.mockTransactionWriterOne, this.mockTransactionWriterTwo).close();
|
||||
|
||||
verify(this.mockTransactionWriterOne, times(1)).close();
|
||||
verify(this.mockTransactionWriterTwo, times(1)).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initCallsComposedTransactionWritersInitMethod() {
|
||||
|
||||
Properties testProperties = new Properties();
|
||||
|
||||
ComposableTransactionWriter.compose(this.mockTransactionWriterOne, this.mockTransactionWriterTwo)
|
||||
.init(testProperties);
|
||||
|
||||
verify(this.mockTransactionWriterOne, times(1)).init(eq(testProperties));
|
||||
verify(this.mockTransactionWriterTwo, times(1)).init(eq(testProperties));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initializeCallsComposedTransactionWritersInitializeMethod() {
|
||||
|
||||
Cache mockCache = mock(Cache.class);
|
||||
|
||||
Properties testProperties = new Properties();
|
||||
|
||||
ComposableTransactionWriter.compose(this.mockTransactionWriterOne, this.mockTransactionWriterTwo)
|
||||
.initialize(mockCache, testProperties);
|
||||
|
||||
verify(this.mockTransactionWriterOne, times(1))
|
||||
.initialize(eq(mockCache), eq(testProperties));
|
||||
|
||||
verify(this.mockTransactionWriterTwo, times(1))
|
||||
.initialize(eq(mockCache), eq(testProperties));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 2019 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.data.gemfire.transaction.event;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.isA;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.apache.geode.cache.TransactionEvent;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
|
||||
/**
|
||||
* Unit Tests for {@link TransactionListenerAdapter}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mock
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.mockito.junit.MockitoJUnitRunner
|
||||
* @see org.springframework.context.ApplicationEventPublisher
|
||||
* @see org.springframework.data.gemfire.transaction.event.TransactionListenerAdapter
|
||||
* @since 2.3.0
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class TransactionListenerAdapterUnitTests {
|
||||
|
||||
@Mock
|
||||
private ApplicationEventPublisher mockApplicationEventPublisher;
|
||||
|
||||
@Mock
|
||||
private TransactionEvent mockTransactionEvent;
|
||||
|
||||
@Test
|
||||
public void constructTransactionListenerAdapterIsCorrect() {
|
||||
|
||||
TransactionListenerAdapter listener = new TransactionListenerAdapter(this.mockApplicationEventPublisher);
|
||||
|
||||
assertThat(listener).isNotNull();
|
||||
assertThat(listener.getApplicationEventPublisher()).isEqualTo(this.mockApplicationEventPublisher);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructTransactionListenerAdapterWithNullApplicationEventPublisherThrowsIllegalArgumentException() {
|
||||
|
||||
try {
|
||||
new TransactionListenerAdapter(null);
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
|
||||
assertThat(expected).hasMessage("ApplicationEventPublisher must not be null");
|
||||
assertThat(expected).hasNoCause();
|
||||
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
|
||||
private void invokingApplicationEventPublisherTest(Consumer<TransactionListenerAdapter> listenerConsumer) {
|
||||
|
||||
doAnswer(invocation -> {
|
||||
|
||||
ApplicationEvent applicationEvent = invocation.getArgument(0, ApplicationEvent.class);
|
||||
|
||||
assertThat(applicationEvent).isInstanceOf(TransactionApplicationEvent.class);
|
||||
assertThat(applicationEvent.getSource()).isEqualTo(this.mockTransactionEvent);
|
||||
|
||||
return null;
|
||||
|
||||
}).when(this.mockApplicationEventPublisher).publishEvent(any(ApplicationEvent.class));
|
||||
|
||||
TransactionListenerAdapter listener = new TransactionListenerAdapter(this.mockApplicationEventPublisher);
|
||||
|
||||
listenerConsumer.accept(listener);
|
||||
|
||||
verify(this.mockApplicationEventPublisher, times(1))
|
||||
.publishEvent(isA(TransactionApplicationEvent.class));
|
||||
}
|
||||
|
||||
private void nonInvokingApplicationEventPublisherTest(Consumer<TransactionListenerAdapter> listenerConsumer) {
|
||||
|
||||
TransactionListenerAdapter listener = new TransactionListenerAdapter(this.mockApplicationEventPublisher);
|
||||
|
||||
listenerConsumer.accept(listener);
|
||||
|
||||
verify(this.mockApplicationEventPublisher, never()).publishEvent(any(ApplicationEvent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beforeCommitDoesNotInvokeApplicationEventPublisher() {
|
||||
nonInvokingApplicationEventPublisherTest(listener -> listener.beforeCommit(this.mockTransactionEvent));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterCommitInvokesApplicationEventPublisher() {
|
||||
invokingApplicationEventPublisherTest(listener -> listener.afterCommit(this.mockTransactionEvent));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterFailedCommitDoesNotInvokeApplicationEventPublisher() {
|
||||
nonInvokingApplicationEventPublisherTest(listener -> listener.afterFailedCommit(this.mockTransactionEvent));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void afterRollbackInvokesApplicationEventPublisher() {
|
||||
invokingApplicationEventPublisherTest(listener -> listener.afterRollback(this.mockTransactionEvent));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user