DATAGEODE-16 - Add support for Geode JCA ResourceAdapter.

This commit is contained in:
John Blum
2017-06-30 18:38:41 -07:00
parent 0907ecbe44
commit 70eea5f68d
14 changed files with 2604 additions and 7 deletions

View File

@@ -0,0 +1,231 @@
/*
* Copyright 2017 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
*
* 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.springframework.data.gemfire.config.annotation;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.geode.cache.GemFireCache;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.gemfire.config.annotation.support.GemFireAsLastResourceConnectionAcquiringAspect;
import org.springframework.data.gemfire.config.annotation.support.GemFireAsLastResourceConnectionClosingAspect;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* Unit tests for {@link GemFireAsLastResourceConfiguration}.
*
* @author John Blum
* @see org.junit.Test
* @see org.junit.runner.RunWith
* @see org.mockito.Mock
* @see org.mockito.Mockito
* @see org.mockito.junit.MockitoJUnitRunner
* @see org.springframework.data.gemfire.config.annotation.GemFireAsLastResourceConfiguration
* @since 2.0.0
*/
@RunWith(MockitoJUnitRunner.class)
public class GemFireAsLastResourceConfigurationUnitTests {
@Mock
private AnnotationMetadata mockImportMetadata;
private GemFireAsLastResourceConfiguration configuration;
@Before
public void setup() {
configuration = new GemFireAsLastResourceConfiguration();
}
private AnnotationMetadata mockEnableTransactionManagementWithOrder(Integer order) {
Map<String, Object> enableTransactionManagementAttributes = Collections.singletonMap("order", order);
when(mockImportMetadata.getAnnotationAttributes(eq(EnableTransactionManagement.class.getName())))
.thenReturn(enableTransactionManagementAttributes);
return mockImportMetadata;
}
@Test
public void resolveEnableTransactionManagementAttributes() {
Map<String, Object> enableTransactionManagementAttributesMap = new HashMap<>();
enableTransactionManagementAttributesMap.put("mode", AdviceMode.ASPECTJ);
enableTransactionManagementAttributesMap.put("order", 1);
enableTransactionManagementAttributesMap.put("proxyTargetClass", true);
when(mockImportMetadata.getAnnotationAttributes(eq(EnableTransactionManagement.class.getName())))
.thenReturn(enableTransactionManagementAttributesMap);
AnnotationAttributes enableTransactionManagementAttributes =
configuration.resolveEnableTransactionManagementAttributes(mockImportMetadata);
assertThat(enableTransactionManagementAttributes).isNotNull();
assertThat(enableTransactionManagementAttributes.<AdviceMode>getEnum("mode"))
.isEqualTo(AdviceMode.ASPECTJ);
assertThat(enableTransactionManagementAttributes.getBoolean("proxyTargetClass")).isTrue();
verify(mockImportMetadata, times(1))
.getAnnotationAttributes(eq(EnableTransactionManagement.class.getName()));
}
@Test(expected = IllegalStateException.class)
public void resolveEnableTransactionManagementAttributesThrowsIllegalStateException() {
try {
when(mockImportMetadata.getAnnotationAttributes(anyString())).thenReturn(null);
configuration.resolveEnableTransactionManagementAttributes(mockImportMetadata);
}
catch (IllegalStateException expected) {
assertThat(expected).hasMessage(String.format(
"The @%1$s annotation may only be used on a Spring application @%2$s class"
+ " that is also annotated with @%3$s having an explicit [order] set",
EnableGemFireAsLastResource.class.getSimpleName(), Configuration.class.getSimpleName(),
EnableTransactionManagement.class.getSimpleName()));
assertThat(expected).hasNoCause();
throw expected;
}
}
@Test
public void resolveEnableTransactionManagementOrderEqualsOne() {
assertThat(configuration.resolveEnableTransactionManagementOrder(
mockEnableTransactionManagementWithOrder(1))).isEqualTo(1);
}
@Test(expected = IllegalArgumentException.class)
public void resolveEnableTransactionManagementOrderThrowsIllegalArgumentExceptionForIntegerMaxValue() {
try {
configuration.resolveEnableTransactionManagementOrder(
mockEnableTransactionManagementWithOrder(Integer.MAX_VALUE));
}
catch (IllegalArgumentException expected) {
assertThat(expected).hasMessage(String.format(
"The @%1$s(order) attribute value [%2$d] must be explicitly set to a value other than"
+ " Integer.MAX_VALUE or Integer.MIN_VALUE",
EnableTransactionManagement.class.getSimpleName(), Integer.MAX_VALUE));
assertThat(expected).hasNoCause();
throw expected;
}
}
@Test(expected = IllegalArgumentException.class)
public void resolveEnableTransactionManagementOrderThrowsIllegalArgumentExceptionForIntegerMinValue() {
try {
configuration.resolveEnableTransactionManagementOrder(
mockEnableTransactionManagementWithOrder(Integer.MIN_VALUE));
}
catch (IllegalArgumentException expected) {
assertThat(expected).hasMessage(String.format(
"The @%1$s(order) attribute value [%2$d] must be explicitly set to a value other than"
+ " Integer.MAX_VALUE or Integer.MIN_VALUE",
EnableTransactionManagement.class.getSimpleName(), Integer.MIN_VALUE));
assertThat(expected).hasNoCause();
throw expected;
}
}
@Test
public void getEnableTransactionManagementOrderReturnsValue() {
configuration.setImportMetadata(mockEnableTransactionManagementWithOrder(101));
assertThat(configuration.getEnableTransactionManagementOrder()).isEqualTo(101);
}
@Test(expected = IllegalStateException.class)
public void getEnableTransactionManagementOrderThrowsIllegalStateException() {
try {
configuration.getEnableTransactionManagementOrder();
}
catch (IllegalStateException expected) {
assertThat(expected).hasMessage(String.format("The @%1$s(order) attribute was not properly set [null];"
+ " Also, please make your Spring application @%2$s annotated class is annotated with both @%3$s and @%1$s",
EnableTransactionManagement.class.getSimpleName(), Configuration.class.getSimpleName(),
EnableGemFireAsLastResource.class.getSimpleName()));
assertThat(expected).hasNoCause();
throw expected;
}
}
@Test
public void gemfireCachePostProcessorSetsCopyOnReadToTrue() {
GemFireCache mockGemFireCache = mock(GemFireCache.class);
assertThat(configuration.gemfireCachePostProcessor(mockGemFireCache)).isNull();
verify(mockGemFireCache, times(1)).setCopyOnRead(eq(true));
}
@Test
public void gemfireCachePostProcessorHandlesNull() {
assertThat(configuration.gemfireCachePostProcessor(null)).isNull();
}
@Test
public void gemfireJcaConnectionAcquiringAspectIsOrderPlusOne() {
configuration.setImportMetadata(mockEnableTransactionManagementWithOrder(0));
GemFireAsLastResourceConnectionAcquiringAspect aspect = configuration.gemfireJcaConnectionAcquiringAspect();
assertThat(aspect).isNotNull();
assertThat(aspect.getOrder()).isEqualTo(1);
}
@Test
public void gemfireJcaConnectionClosingAspectIsOrderMinusOne() {
configuration.setImportMetadata(mockEnableTransactionManagementWithOrder(0));
GemFireAsLastResourceConnectionClosingAspect aspect = configuration.gemfireJcaConnectionClosingAspect();
assertThat(aspect).isNotNull();
assertThat(aspect.getOrder()).isEqualTo(-1);
}
}

View File

@@ -0,0 +1,449 @@
/*
* Copyright 2017 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
*
* 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.springframework.data.gemfire.config.annotation.support;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
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 static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
import java.util.Optional;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.apache.geode.cache.GemFireCache;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.internal.matchers.VarargMatcher;
import org.mockito.junit.MockitoJUnitRunner;
import org.slf4j.Logger;
/**
* Unit tests for {@link AbstractGemFireAsLastResourceAspectSupport}.
*
* @author John Blum
* @see javax.naming.Context
* @see javax.naming.InitialContext
* @see org.junit.Test
* @see org.junit.runner.RunWith
* @see org.mockito.Mock
* @see org.mockito.Mockito
* @see org.mockito.Spy
* @see org.mockito.junit.MockitoJUnitRunner
* @see org.apache.geode.cache.GemFireCache
* @see org.springframework.data.gemfire.config.annotation.support.AbstractGemFireAsLastResourceAspectSupport
* @since 2.0.0
*/
@RunWith(MockitoJUnitRunner.class)
public class AbstractGemFireAsLastResourceAspectSupportUnitTests {
@Mock
private Logger mockLogger;
@Spy
private AbstractGemFireAsLastResourceAspectSupport aspectSupport;
@Before
@SuppressWarnings("all")
public void setup() {
doReturn(mockLogger).when(aspectSupport).getLogger();
}
@Test
public void setAndGetOrder() {
assertThat(aspectSupport.getOrder()).isEqualTo(AbstractGemFireAsLastResourceAspectSupport.DEFAULT_ORDER);
aspectSupport.setOrder(1);
assertThat(aspectSupport.getOrder()).isEqualTo(1);
aspectSupport.setOrder(-2);
assertThat(aspectSupport.getOrder()).isEqualTo(-2);
aspectSupport.setOrder(Integer.MAX_VALUE);
assertThat(aspectSupport.getOrder()).isEqualTo(AbstractGemFireAsLastResourceAspectSupport.DEFAULT_ORDER);
aspectSupport.setOrder(Integer.MIN_VALUE);
assertThat(aspectSupport.getOrder()).isEqualTo(AbstractGemFireAsLastResourceAspectSupport.DEFAULT_ORDER);
}
@Test
public void logDebugInfoWhenDebuggingIsDisabled() {
when(mockLogger.isDebugEnabled()).thenReturn(false);
assertThat(aspectSupport.<AbstractGemFireAsLastResourceAspectSupport>logDebugInfo("message", "arg"))
.isSameAs(aspectSupport);
verify(mockLogger, times(1)).isDebugEnabled();
verify(mockLogger, never()).debug(anyString());
verify(mockLogger, never()).debug(anyString(), any(Object.class));
verify(mockLogger, never()).debug(anyString(), any(Object.class), any(Object.class));
verify(mockLogger, never()).debug(anyString(), any(Object[].class));
}
@Test
public void logDebugInfoWhenDebuggingIsEnabled() {
when(mockLogger.isDebugEnabled()).thenReturn(true);
assertThat(aspectSupport.<AbstractGemFireAsLastResourceAspectSupport>logDebugInfo("test %s message",
"debug", "test")) .isSameAs(aspectSupport);
verify(mockLogger, times(1)).isDebugEnabled();
// TODO why the f#&k does this not work Mockito?!
//verify(mockLogger, times(1))
// .debug(eq("test debug message"), eq("debug"), eq("test"));
// TODO this ridiculous sh!t works
//verify(mockLogger, times(1)).debug(eq("test debug message"),
// ArgumentMatchers.<Object[]>any());
// TODO and so does this, but what a hack!
verify(mockLogger, times(1)).debug(eq("test debug message"),
VariableArgumentMatcher.varArgThat("debug", "test"));
}
@Test
public void logInfoWhenInfoIsDisabled() {
when(mockLogger.isInfoEnabled()).thenReturn(false);
assertThat(aspectSupport.<AbstractGemFireAsLastResourceAspectSupport>logInfo("message", "arg"))
.isSameAs(aspectSupport);
verify(mockLogger, times(1)).isInfoEnabled();
verify(mockLogger, never()).info(anyString(), any(Object.class));
verify(mockLogger, never()).info(anyString(), any(Object.class), any(Object.class));
verify(mockLogger, never()).info(anyString(), any(Object[].class));
}
@Test
public void logInfoWhenInfoIsEnabled() {
when(mockLogger.isInfoEnabled()).thenReturn(true);
assertThat(aspectSupport.<AbstractGemFireAsLastResourceAspectSupport>logInfo("test %s message", "info"))
.isSameAs(aspectSupport);
verify(mockLogger, times(1)).isInfoEnabled();
verify(mockLogger, times(1)).info(eq("test info message"),
VariableArgumentMatcher.varArgThat("info"));
}
@Test
public void logTraceInfoWhenTracingIsDisabled() {
when(mockLogger.isTraceEnabled()).thenReturn(false);
assertThat(aspectSupport.<AbstractGemFireAsLastResourceAspectSupport>logTraceInfo("message", "arg"))
.isSameAs(aspectSupport);
verify(mockLogger, times(1)).isTraceEnabled();
verify(mockLogger, never()).trace(anyString());
verify(mockLogger, never()).trace(anyString(), any(Object.class));
verify(mockLogger, never()).trace(anyString(), any(Object.class), any(Object.class));
verify(mockLogger, never()).trace(anyString(), any(Object[].class));
}
@Test
public void logTraceInfoWhenTracingIsEnabled() {
when(mockLogger.isTraceEnabled()).thenReturn(true);
assertThat(aspectSupport.<AbstractGemFireAsLastResourceAspectSupport>logTraceInfo("test %s message", "trace"))
.isSameAs(aspectSupport);
verify(mockLogger, times(1)).isTraceEnabled();
verify(mockLogger, times(1)).trace(eq("test trace message"));
}
@Test
public void logTraceInfoUsingMessageSupplierWhenTracingIsEnabled() {
when(mockLogger.isTraceEnabled()).thenReturn(true);
assertThat(aspectSupport.<AbstractGemFireAsLastResourceAspectSupport>logTraceInfo(
() -> "trace test message with Supplier")).isSameAs(aspectSupport);
verify(mockLogger, times(1)).isTraceEnabled();
verify(mockLogger, times(1)).trace(eq("trace test message with Supplier"));
}
@Test
public void logWarningWhenWarningsAreDisabled() {
when(mockLogger.isWarnEnabled()).thenReturn(false);
assertThat(aspectSupport.<AbstractGemFireAsLastResourceAspectSupport>logWarning("message", "arg"))
.isSameAs(aspectSupport);
verify(mockLogger, times(1)).isWarnEnabled();
verify(mockLogger, never()).warn(anyString());
verify(mockLogger, never()).warn(anyString(), any(Object.class));
verify(mockLogger, never()).warn(anyString(), any(Object.class), any(Object.class));
verify(mockLogger, never()).warn(anyString(), any(Object[].class));
}
@Test
public void logWarningWhenWarningsAreEnabled() {
when(mockLogger.isWarnEnabled()).thenReturn(true);
assertThat(aspectSupport.<AbstractGemFireAsLastResourceAspectSupport>logWarning("test %s message", "warning"))
.isSameAs(aspectSupport);
verify(mockLogger, times(1)).isWarnEnabled();
verify(mockLogger, times(1)).warn(eq("test warning message"),
VariableArgumentMatcher.varArgThat("warning"));
}
@Test
public void logErrorWhenErrorsAreDisabled() {
when(mockLogger.isErrorEnabled()).thenReturn(false);
assertThat(aspectSupport.<AbstractGemFireAsLastResourceAspectSupport>logError("message", "arg"))
.isSameAs(aspectSupport);
verify(mockLogger, times(1)).isErrorEnabled();
verify(mockLogger, never()).error(anyString());
verify(mockLogger, never()).error(anyString(), any(Object.class));
verify(mockLogger, never()).error(anyString(), any(Object.class), any(Object.class));
verify(mockLogger, never()).error(anyString(), any(Object[].class));
}
@Test
public void logErrorWhenErrorsAreEnabled() {
when(mockLogger.isErrorEnabled()).thenReturn(true);
assertThat(aspectSupport.<AbstractGemFireAsLastResourceAspectSupport>logError("test %s message", "error"))
.isSameAs(aspectSupport);
verify(mockLogger, times(1)).isErrorEnabled();
verify(mockLogger, times(1)).error(eq("test error message"),
VariableArgumentMatcher.varArgThat("error"));
}
@Test
public void resolveContextReturnsConfiguredContext() throws NamingException {
Context mockContext = mock(Context.class);
doReturn(mockContext).when(aspectSupport).getContext();
assertThat(aspectSupport.resolveContext()).isSameAs(mockContext);
verify(aspectSupport, never()).newInitialContext(any(Hashtable.class));
verifyZeroInteractions(mockContext);
}
@Test
@SuppressWarnings("all")
public void resolveContextReturnsNewInitialContext() throws NamingException {
Hashtable<String, Object> mockEnvironment = new Hashtable<>();
InitialContext mockContext = mock(InitialContext.class);
doReturn(mockContext).when(aspectSupport).newInitialContext(any(Hashtable.class));
doReturn(mockEnvironment).when(aspectSupport).resolveEnvironment();
assertThat(aspectSupport.resolveContext()).isEqualTo(mockContext);
verify(aspectSupport, times(1)).getContext();
verify(aspectSupport, times(1)).newInitialContext(eq(mockEnvironment));
verifyZeroInteractions(mockContext);
}
@Test
public void resolveContextHandlesNamingExceptionAndReturnsGemFireJndiContext() throws NamingException {
Context mockContext = mock(Context.class);
GemFireCache mockGemFireCache = mock(GemFireCache.class);
Hashtable<String, Object> mockEnvironment = new Hashtable<>();
doThrow(new NamingException("TEST")).when(aspectSupport).newInitialContext(any(Hashtable.class));
doReturn(mockEnvironment).when(aspectSupport).resolveEnvironment();
doReturn(mockGemFireCache).when(aspectSupport).resolveGemFireCache();
doReturn(mockContext).when(mockGemFireCache).getJNDIContext();
assertThat(aspectSupport.resolveContext()).isEqualTo(mockContext);
verify(aspectSupport, times(1)).getContext();
verify(aspectSupport, times(1)).resolveEnvironment();
verify(aspectSupport, times(1)).newInitialContext(eq(mockEnvironment));
verify(aspectSupport, times(1)).resolveGemFireCache();
verify(mockGemFireCache, times(1)).getJNDIContext();
}
@Test(expected = IllegalStateException.class)
public void resolveContextHandlesNamingExceptionAndThrowsIllegalStateException() throws NamingException {
Hashtable<String, Object> testEnvironment = new Hashtable<>();
testEnvironment.put("key", "test");
doThrow(new NamingException("TEST")).when(aspectSupport).newInitialContext(any(Hashtable.class));
doReturn(testEnvironment).when(aspectSupport).resolveEnvironment();
doReturn(null).when(aspectSupport).resolveGemFireCache();
try {
aspectSupport.resolveContext();
}
catch (IllegalStateException expected) {
assertThat(expected).hasMessage(
"Failed to initialize an %1$s with the provided Environment configuration [%2$s]",
InitialContext.class.getName(), testEnvironment.toString());
assertThat(expected).hasCauseInstanceOf(NamingException.class);
assertThat(expected.getCause()).hasMessage("TEST");
assertThat(expected.getCause()).hasNoCause();
throw expected;
}
finally {
verify(aspectSupport, times(1)).getContext();
verify(aspectSupport, times(1)).resolveEnvironment();
verify(aspectSupport, times(1)).newInitialContext(eq(testEnvironment));
verify(aspectSupport, times(1)).resolveGemFireCache();
}
}
@Test
public void resolveEnvironmentContainsInitialContextFactoryAndProviderUrl() {
doReturn("org.example.test.naming.AppServerContextFactory").when(aspectSupport)
.getInitialContextFactory();
doReturn("jndi:rmi://java/comp:jndi/context").when(aspectSupport).getProviderUrl();
Hashtable<?, ?> resolvedEnvironment = aspectSupport.resolveEnvironment();
assertThat(resolvedEnvironment).isNotNull();
assertThat(resolvedEnvironment).hasSize(2);
assertThat(resolvedEnvironment.containsKey(Context.INITIAL_CONTEXT_FACTORY)).isTrue();
assertThat(resolvedEnvironment.get(Context.INITIAL_CONTEXT_FACTORY))
.isEqualTo("org.example.test.naming.AppServerContextFactory");
assertThat(resolvedEnvironment.containsKey(Context.PROVIDER_URL)).isTrue();
assertThat(resolvedEnvironment.get(Context.PROVIDER_URL)).isEqualTo("jndi:rmi://java/comp:jndi/context");
}
@Test
public void resolveGemFireCacheReturnsConfiguredGemFireCache() {
GemFireCache mockGemFireCache = mock(GemFireCache.class);
doReturn(mockGemFireCache).when(aspectSupport).getGemFireCache();
assertThat(aspectSupport.resolveGemFireCache()).isSameAs(mockGemFireCache);
verify(aspectSupport, times(1)).getGemFireCache();
}
@Test
public void resolveGemFireCacheReturnsNull() {
assertThat(aspectSupport.resolveGemFireCache()).isNull();
verify(aspectSupport, times(1)).getGemFireCache();
}
@Test
@SuppressWarnings("all")
public void resolveGemFireJcaResourceAdapterJndiNameReturnsConfiguredJndiName() {
doReturn("java/comp:gemfire/jca/resourceAdapter").when(aspectSupport)
.getGemFireJcaResourceAdapterJndiName();
assertThat(aspectSupport.resolveGemFireJcaResourceAdapterJndiName())
.isEqualTo("java/comp:gemfire/jca/resourceAdapter");
verify(aspectSupport, times(1)).getGemFireJcaResourceAdapterJndiName();
}
@Test
public void resolveGemFireJcaResourceAdapterJndiNameReturnsDefaultJndiName() {
assertThat(aspectSupport.getGemFireJcaResourceAdapterJndiName()).isNull();
assertThat(aspectSupport.resolveGemFireJcaResourceAdapterJndiName())
.isEqualTo(AbstractGemFireAsLastResourceAspectSupport.DEFAULT_GEMFIRE_JCA_RESOURCE_ADAPTER_JNDI_NAME);
}
@Test
public void withThrowOnErrorAndIsThrowOnError() {
assertThat(aspectSupport.isThrowOnError()).isFalse();
assertThat(aspectSupport.<AbstractGemFireAsLastResourceAspectSupport>withThrowOnError(true)).isSameAs(aspectSupport);
assertThat(aspectSupport.isThrowOnError()).isTrue();
assertThat(aspectSupport.<AbstractGemFireAsLastResourceAspectSupport>withThrowOnError(false)).isSameAs(aspectSupport);
assertThat(aspectSupport.isThrowOnError()).isFalse();
}
// TODO refactor this BS; damn you Mockito for your inability to match Varargs completely/reliably; WTF!
protected static final class VariableArgumentMatcher<T> implements ArgumentMatcher<T>, VarargMatcher {
protected static Object[] varArgThat(Object... expectedArguments) {
return argThat(new VariableArgumentMatcher<>(expectedArguments));
}
private Object[] expectedArguments;
@SuppressWarnings("unchecked")
protected VariableArgumentMatcher(Object... expectedArguments) {
this.expectedArguments = Optional.ofNullable(expectedArguments)
.orElseThrow(() -> newIllegalArgumentException("Expected arguments must not be null"));
}
@Override
@SuppressWarnings("unchecked")
public boolean matches(T actualArgument) {
return asList(this.expectedArguments).containsAll(asList(actualArgument));
}
private List<Object> asList(Object argument) {
return Arrays.asList(toArray(argument));
}
private Object[] toArray(Object argument) {
return (argument instanceof Object[] ? (Object[]) argument : new Object[] { argument });
}
}
}

View File

@@ -0,0 +1,359 @@
/*
* Copyright 2017 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
*
* 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.springframework.data.gemfire.config.annotation.support;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.resource.ResourceException;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.ra.GFConnection;
import org.apache.geode.ra.GFConnectionFactory;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.gemfire.config.annotation.EnableGemFireAsLastResource;
import org.springframework.data.gemfire.config.annotation.GemFireAsLastResourceConfiguration;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Transactional;
/**
* Integration tests for {@link EnableGemFireAsLastResource}.
*
* @author John Blum
* @see org.junit.Test
* @see org.mockito.Mock
* @see org.mockito.Mockito
* @see org.apache.geode.ra.GFConnection
* @see org.apache.geode.ra.GFConnectionFactory
* @see org.springframework.data.gemfire.config.annotation.EnableGemFireAsLastResource
* @see org.springframework.data.gemfire.config.annotation.GemFireAsLastResourceConfiguration
* @see org.springframework.transaction.PlatformTransactionManager
* @see org.springframework.transaction.annotation.EnableTransactionManagement
* @see org.springframework.transaction.annotation.Transactional
* @since 2.0.0
*/
public class EnableGemFireAsLastResourceIntegrationTests {
private static List<SpringGemFireTransactionEvents> transactionEvents = new ArrayList<>();
@Before
public void setup() {
transactionEvents.clear();
}
private ConfigurableApplicationContext newApplicationContext(Class<?>... annotatedClasses) {
ConfigurableApplicationContext applicationContext = new AnnotationConfigApplicationContext(annotatedClasses);
applicationContext.registerShutdownHook();
return applicationContext;
}
@Test
public void configurationIsCorrect() {
ConfigurableApplicationContext applicationContext =
newApplicationContext(TestGemFireAsLastResourceConfiguration.class);
assertThat(applicationContext).isNotNull();
GemFireCache gemfireCache = applicationContext.getBean("gemfireCache", GemFireCache.class);
assertThat(gemfireCache).isNotNull();
assertThat(gemfireCache.getCopyOnRead()).isTrue();
GemFireAsLastResourceConnectionAcquiringAspect connectionAcquiringAspect =
applicationContext.getBean(GemFireAsLastResourceConnectionAcquiringAspect.class);
assertThat(connectionAcquiringAspect).isNotNull();
assertThat(connectionAcquiringAspect.getOrder()).isEqualTo(3);
GemFireAsLastResourceConnectionClosingAspect connectionClosingAspect =
applicationContext.getBean(GemFireAsLastResourceConnectionClosingAspect.class);
assertThat(connectionClosingAspect).isNotNull();
assertThat(connectionClosingAspect.getOrder()).isEqualTo(1);
}
private void transactionEventsForTransactionalServiceAreCorrect(
Class<? extends TestTransactionalService> transactionalServiceType) {
ConfigurableApplicationContext applicationContext =
newApplicationContext(TestSpringApplicationConfiguration.class);
assertThat(applicationContext).isNotNull();
assertThat(applicationContext.containsBean(transactionalServiceType.getSimpleName())).isTrue();
assertThat(transactionEvents).isEmpty();
GFConnectionFactory gemfireConnectionFactory = applicationContext.getBean(GFConnectionFactory.class);
assertThat(gemfireConnectionFactory).isNotNull();
GemFireAsLastResourceConnectionAcquiringAspect connectionAcquiringAspect =
applicationContext.getBean(GemFireAsLastResourceConnectionAcquiringAspect.class);
assertThat(connectionAcquiringAspect).isNotNull();
assertThat(connectionAcquiringAspect.getGemFireConnectionFactory()).isSameAs(gemfireConnectionFactory);
TestTransactionalService service =
applicationContext.getBean(transactionalServiceType.getSimpleName(), transactionalServiceType);
assertThat(service).isNotNull();
service.doInTransactionCommits();
assertThat(transactionEvents).containsExactly(SpringGemFireTransactionEvents.BEGIN,
SpringGemFireTransactionEvents.GET_CONNECTION,
SpringGemFireTransactionEvents.TRANSACTION,
SpringGemFireTransactionEvents.COMMIT,
SpringGemFireTransactionEvents.CLOSE_CONNECTION);
transactionEvents.clear();
assertThat(transactionEvents).isEmpty();
try {
service.doInTransactionRollsback();
}
catch (RuntimeException expected) {
assertThat(expected).hasMessage("TEST");
assertThat(expected).hasNoCause();
throw expected;
}
finally {
assertThat(transactionEvents).containsExactly(SpringGemFireTransactionEvents.BEGIN,
SpringGemFireTransactionEvents.GET_CONNECTION,
SpringGemFireTransactionEvents.TRANSACTION,
SpringGemFireTransactionEvents.ROLLBACK,
SpringGemFireTransactionEvents.CLOSE_CONNECTION);
}
}
@Test(expected = RuntimeException.class)
public void transactionEventsForTransactionalServiceClassAreCorrect() {
transactionEventsForTransactionalServiceAreCorrect(TestTransactionalServiceClass.class);
}
@Test(expected = RuntimeException.class)
public void transactionEventsForTransactionalServiceMethodsAreCorrect() {
transactionEventsForTransactionalServiceAreCorrect(TestTransactionalServiceMethods.class);
}
@Test(expected = IllegalStateException.class)
public void missingEnableTransactionManagerAnnotationThrowsIllegalStateException() {
try {
newApplicationContext(TestMissingEnableTransactionManagementAnnotationConfiguration.class);
}
catch (BeanCreationException expected) {
assertThat(expected).hasMessageStartingWith(String.format("Error creating bean with name '%s'",
GemFireAsLastResourceConfiguration.class.getName()));
assertThat(expected).hasCauseInstanceOf(IllegalStateException.class);
assertThat(expected.getCause()).hasMessage("The @EnableGemFireAsLastResource annotation may only be used"
+ " on a Spring application @Configuration class that is also annotated with"
+ " @EnableTransactionManagement having an explicit [order] set");
assertThat(expected.getCause()).hasNoCause();
throw (IllegalStateException) expected.getCause();
}
}
@Test(expected = IllegalArgumentException.class)
public void missingEnableTransactionManagementOrderAttributeConfigurationThrowsIllegalArgumentException() {
try {
newApplicationContext(TestMissingEnableTransactionManagementOrderAttributeConfiguration.class);
}
catch (BeanCreationException expected) {
assertThat(expected).hasMessageStartingWith(String.format("Error creating bean with name '%s'",
GemFireAsLastResourceConfiguration.class.getName()));
assertThat(expected).hasCauseInstanceOf(IllegalArgumentException.class);
assertThat(expected.getCause()).hasMessage("The @EnableTransactionManagement(order) attribute value"
+ " [2147483647] must be explicitly set to a value other than Integer.MAX_VALUE or Integer.MIN_VALUE");
assertThat(expected.getCause()).hasNoCause();
throw (IllegalArgumentException) expected.getCause();
}
}
@Configuration
@EnableGemFireAsLastResource
@EnableTransactionManagement(order = 2)
static class TestGemFireAsLastResourceConfiguration {
@Bean("gemfireCache")
GemFireCache mockGemFireCache() {
AtomicBoolean copyOnRead = new AtomicBoolean(false);
GemFireCache mockGemFireCache = mock(GemFireCache.class);
doAnswer(invocation -> {
copyOnRead.set(invocation.getArgument(0));
return null;
}).when(mockGemFireCache).setCopyOnRead(anyBoolean());
when(mockGemFireCache.getCopyOnRead()).thenAnswer(invocation -> copyOnRead.get());
return mockGemFireCache;
}
@Bean
GFConnectionFactory mockGemFireConnectionFactory() throws ResourceException {
GFConnectionFactory mockGemFireConnectionFactory = mock(GFConnectionFactory.class);
GFConnection mockGemFireConnection = mock(GFConnection.class);
when(mockGemFireConnectionFactory.getConnection()).thenAnswer(invocation -> {
transactionEvents.add(SpringGemFireTransactionEvents.GET_CONNECTION);
return mockGemFireConnection;
});
doAnswer(invocation -> transactionEvents.add(SpringGemFireTransactionEvents.CLOSE_CONNECTION))
.when(mockGemFireConnection).close();
return mockGemFireConnectionFactory;
}
@Bean("transactionManager")
PlatformTransactionManager mockTransactionManager() {
PlatformTransactionManager mockTransactionManager = mock(PlatformTransactionManager.class);
when(mockTransactionManager.getTransaction(any(TransactionDefinition.class))).thenAnswer(invocation -> {
TransactionStatus mockTransactionStatus = mock(TransactionStatus.class);
transactionEvents.add(SpringGemFireTransactionEvents.BEGIN);
return mockTransactionStatus;
});
doAnswer(invocation -> transactionEvents.add(SpringGemFireTransactionEvents.COMMIT))
.when(mockTransactionManager).commit(any(TransactionStatus.class));
doAnswer(invocation -> transactionEvents.add(SpringGemFireTransactionEvents.ROLLBACK))
.when(mockTransactionManager).rollback(any(TransactionStatus.class));
return mockTransactionManager;
}
}
@Configuration
@EnableGemFireAsLastResource
static class TestMissingEnableTransactionManagementAnnotationConfiguration {
}
@Configuration
@EnableGemFireAsLastResource
@EnableTransactionManagement
static class TestMissingEnableTransactionManagementOrderAttributeConfiguration {
@Bean("transactionManager")
PlatformTransactionManager mockTransactionManager() {
return mock(PlatformTransactionManager.class);
}
}
@Configuration
@Import(TestGemFireAsLastResourceConfiguration.class)
static class TestSpringApplicationConfiguration {
@Bean("TestTransactionalServiceClass")
TestTransactionalServiceClass testTransactionalServiceClass() {
return new TestTransactionalServiceClass();
}
@Bean("TestTransactionalServiceMethods")
TestTransactionalServiceMethods testTransactionalServiceMethods() {
return new TestTransactionalServiceMethods();
}
}
enum SpringGemFireTransactionEvents {
BEGIN,
CLOSE_CONNECTION,
COMMIT,
GET_CONNECTION,
ROLLBACK,
TRANSACTION,
}
interface TestTransactionalService {
void doInTransactionCommits();
void doInTransactionRollsback();
}
@Service("TestTransactionalServiceClass")
@Transactional
static class TestTransactionalServiceClass implements TestTransactionalService {
public void doInTransactionCommits() {
transactionEvents.add(SpringGemFireTransactionEvents.TRANSACTION);
}
public void doInTransactionRollsback() {
transactionEvents.add(SpringGemFireTransactionEvents.TRANSACTION);
throw new RuntimeException("TEST");
}
}
@Service("TestTransactionalServiceMethods")
static class TestTransactionalServiceMethods implements TestTransactionalService {
@Transactional
public void doInTransactionCommits() {
transactionEvents.add(SpringGemFireTransactionEvents.TRANSACTION);
}
@Transactional
public void doInTransactionRollsback() {
transactionEvents.add(SpringGemFireTransactionEvents.TRANSACTION);
throw new RuntimeException("TEST");
}
}
}

View File

@@ -0,0 +1,160 @@
/*
* Copyright 2017 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
*
* 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.springframework.data.gemfire.config.annotation.support;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.resource.ResourceException;
import org.apache.geode.ra.GFConnection;
import org.apache.geode.ra.GFConnectionFactory;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.slf4j.Logger;
/**
* Unit tests for {@link GemFireAsLastResourceConnectionAcquiringAspect}.
*
* @author John Blum
* @see org.junit.Test
* @see org.junit.runner.RunWith
* @see org.mockito.Mock
* @see org.mockito.Mockito
* @see org.mockito.Spy
* @see org.mockito.junit.MockitoJUnitRunner
* @see org.springframework.data.gemfire.config.annotation.support.GemFireAsLastResourceConnectionAcquiringAspect
* @since 2.0.0
*/
@RunWith(MockitoJUnitRunner.class)
public class GemFireAsLastResourceConnectionAcquiringAspectUnitTests {
@Mock
private Context mockContext;
@Mock
private GFConnection mockGemFireConnection;
@Mock
private GFConnectionFactory mockGemFireConnectionFactory;
@Mock
private Logger mockLogger;
private GemFireAsLastResourceConnectionAcquiringAspect aspect;
@Before
public void setup() {
aspect = spy(new GemFireAsLastResourceConnectionAcquiringAspect());
when(aspect.getLogger()).thenReturn(mockLogger);
}
@Test
public void connectionAcquiringAspectHasLowerPriorityThanConnectionClosingAspect() {
assertThat(aspect.getOrder()).isGreaterThan(new GemFireAsLastResourceConnectionClosingAspect().getOrder());
}
@Test
public void doConnectionFactoryGetConnectionReturnsConnection() throws ResourceException {
when(mockLogger.isTraceEnabled()).thenReturn(true);
doReturn(mockGemFireConnectionFactory).when(aspect).resolveGemFireConnectionFactory();
when(mockGemFireConnectionFactory.getConnection()).thenReturn(mockGemFireConnection);
aspect.doGemFireConnectionFactoryGetConnection();
assertThat(AbstractGemFireAsLastResourceAspectSupport.GemFireConnectionHolder.get().orElse(null))
.isEqualTo(mockGemFireConnection);
verify(aspect, times(1)).resolveGemFireConnectionFactory();
verify(aspect, times(1)).resolveGemFireJcaResourceAdapterJndiName();
verify(mockGemFireConnectionFactory, times(1)).getConnection();
verify(mockLogger, times(1))
.trace(eq(String.format("Acquiring GemFire Connection from GemFire JCA ResourceAdapter registered at [%s]...",
GemFireAsLastResourceConnectionAcquiringAspect.DEFAULT_GEMFIRE_JCA_RESOURCE_ADAPTER_JNDI_NAME)));
}
@Test
public void resolveGemFireConnectionFactoryFromAutowiring() {
when(aspect.getGemFireConnectionFactory()).thenReturn(mockGemFireConnectionFactory);
assertThat(aspect.resolveGemFireConnectionFactory()).isSameAs(mockGemFireConnectionFactory);
verify(aspect, times(1)).getGemFireConnectionFactory();
verify(aspect, never()).resolveGemFireJcaResourceAdapterJndiName();
verify(aspect, never()).resolveContext();
}
@Test
public void resolveGemFireConnectionFactoryFromJndiContext() throws NamingException {
when(aspect.getGemFireConnectionFactory()).thenReturn(null);
doReturn(mockContext).when(aspect).resolveContext();
when(mockContext.lookup(anyString())).thenReturn(mockGemFireConnectionFactory);
assertThat(aspect.resolveGemFireConnectionFactory()).isEqualTo(mockGemFireConnectionFactory);
verify(aspect, times(1)).getGemFireConnectionFactory();
verify(aspect, times(1)).resolveGemFireJcaResourceAdapterJndiName();
verify(aspect, times(1)).resolveContext();
verify(mockContext, times(1))
.lookup(eq(GemFireAsLastResourceConnectionAcquiringAspect.DEFAULT_GEMFIRE_JCA_RESOURCE_ADAPTER_JNDI_NAME));
}
@Test(expected = RuntimeException.class)
public void resolveGemFireConnectionFactoryFromJndiContextThrowsNamingException() throws NamingException {
when(aspect.getGemFireConnectionFactory()).thenReturn(null);
when(aspect.getGemFireJcaResourceAdapterJndiName()).thenReturn("java:comp/gemfire/jca");
doReturn(mockContext).when(aspect).resolveContext();
when(mockContext.lookup(anyString())).thenThrow(new NamingException("TEST"));
try {
aspect.resolveGemFireConnectionFactory();
}
catch (RuntimeException expected) {
assertThat(expected).hasMessage(
"Failed to resolve a GFConnectionFactory from the configured JNDI context name [java:comp/gemfire/jca]");
assertThat(expected).hasCauseInstanceOf(NamingException.class);
assertThat(expected.getCause()).hasMessage("TEST");
assertThat(expected.getCause()).hasNoCause();
throw expected;
}
finally {
verify(aspect, times(1)).getGemFireConnectionFactory();
verify(aspect, times(1)).resolveGemFireJcaResourceAdapterJndiName();
verify(aspect, times(1)).resolveContext();
verify(mockContext, times(1)).lookup(eq("java:comp/gemfire/jca"));
}
}
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright 2017 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
*
* 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.springframework.data.gemfire.config.annotation.support;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import javax.resource.ResourceException;
import org.apache.geode.ra.GFConnection;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.slf4j.Logger;
/**
* Unit tests for {@link GemFireAsLastResourceConnectionClosingAspect}.
*
* @author John Blum
* @see org.junit.Test
* @see org.junit.runner.RunWith
* @see org.mockito.Mock
* @see org.mockito.Mockito
* @see org.mockito.Spy
* @see org.mockito.junit.MockitoJUnitRunner
* @see org.springframework.data.gemfire.config.annotation.support.GemFireAsLastResourceConnectionClosingAspect
* @since 2.0.0
*/
@RunWith(MockitoJUnitRunner.class)
public class GemFireAsLastResourceConnectionClosingAspectUnitTests {
private GemFireAsLastResourceConnectionClosingAspect aspect;
@Mock
private GFConnection mockGemFireConnection;
@Mock
private Logger mockLogger;
@Before
public void setup() {
aspect = spy(new GemFireAsLastResourceConnectionClosingAspect());
when(aspect.getLogger()).thenReturn(mockLogger);
}
@Test
public void connectionClosingAspectHasHigherPriorityThanConnectionAcquiringAspect() {
assertThat(aspect.getOrder()).isLessThan(new GemFireAsLastResourceConnectionAcquiringAspect().getOrder());
}
@Test
public void doGemFireConnectionCloseIsSuccessful() throws ResourceException {
AbstractGemFireAsLastResourceAspectSupport.GemFireConnectionHolder.of(mockGemFireConnection);
when(mockLogger.isTraceEnabled()).thenReturn(true);
aspect.doGemFireConnectionClose();;
verify(mockGemFireConnection, times(1)).close();
verify(mockLogger, times(1)).trace(eq("Closing GemFire Connection..."));
}
}