SGF-516 - Configure Expiration with annotations.
(cherry picked from commit bfb3347056f4f87ab7f218c8a7618ea5c5378d32) Signed-off-by: John Blum <jblum@pivotal.io>
This commit is contained in:
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Copyright 2016 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.Matchers.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.data.gemfire.config.annotation.EnableExpiration.ExpirationPolicy;
|
||||
import static org.springframework.data.gemfire.config.annotation.EnableExpiration.ExpirationType;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.apache.geode.cache.AttributesMutator;
|
||||
import org.apache.geode.cache.CustomExpiry;
|
||||
import org.apache.geode.cache.ExpirationAction;
|
||||
import org.apache.geode.cache.ExpirationAttributes;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.RegionAttributes;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
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.data.gemfire.ExpirationActionType;
|
||||
import org.springframework.data.gemfire.util.ArrayUtils;
|
||||
|
||||
/**
|
||||
* Unit tests for the {@link EnableExpiration} annotation and {@link ExpirationConfiguration} class.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.springframework.context.ConfigurableApplicationContext
|
||||
* @see org.springframework.data.gemfire.config.annotation.EnableExpiration
|
||||
* @see org.springframework.data.gemfire.config.annotation.ExpirationConfiguration
|
||||
* @see org.apache.geode.cache.CustomExpiry
|
||||
* @see org.apache.geode.cache.ExpirationAttributes
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @since 1.9.0
|
||||
*/
|
||||
public class EnableExpirationConfigurationUnitTests {
|
||||
|
||||
private ConfigurableApplicationContext applicationContext;
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (applicationContext != null) {
|
||||
applicationContext.close();
|
||||
}
|
||||
}
|
||||
|
||||
protected <K, V> void assertRegionExpiration(ExpirationAttributes expectedExpirationAttributes,
|
||||
Region<K, V> region, V... applicationDomainObjects) {
|
||||
|
||||
assertIdleTimeoutExpiration(expectedExpirationAttributes, region, applicationDomainObjects);
|
||||
assertTimeToLiveExpiration(expectedExpirationAttributes, region, applicationDomainObjects);
|
||||
}
|
||||
|
||||
protected <K, V> void assertIdleTimeoutExpiration(ExpirationAttributes expectedExpirationAttributes,
|
||||
Region<K, V> region, V... applicationDomainObjects) {
|
||||
|
||||
assertExpiration(expectedExpirationAttributes, region.getAttributes().getCustomEntryIdleTimeout(),
|
||||
applicationDomainObjects);
|
||||
}
|
||||
|
||||
protected <K, V> void assertNoIdleTimeoutExpiration(Region<K, V> region) {
|
||||
assertThat(region.getAttributes().getCustomEntryIdleTimeout()).isNull();
|
||||
}
|
||||
|
||||
protected <K, V> void assertTimeToLiveExpiration(ExpirationAttributes expectedExpirationAttributes,
|
||||
Region<K, V> region, V... applicationDomainObjects) {
|
||||
|
||||
assertExpiration(expectedExpirationAttributes, region.getAttributes().getCustomEntryTimeToLive(),
|
||||
applicationDomainObjects);
|
||||
}
|
||||
|
||||
protected <K, V> void assertNoTimeToLiveExpiration(Region<K, V> region) {
|
||||
assertThat(region.getAttributes().getCustomEntryTimeToLive()).isNull();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <K, V> void assertExpiration(ExpirationAttributes expectedExpirationAttributes,
|
||||
CustomExpiry<K, V> customExpiry, V... applicationDomainObjects) {
|
||||
|
||||
Region.Entry<K, V> regionEntry = mockRegionEntry(ArrayUtils.getFirst(applicationDomainObjects));
|
||||
|
||||
assertExpiration(customExpiry.getExpiry(regionEntry), expectedExpirationAttributes);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "unused" })
|
||||
protected <K, V> void assertExpiration(ExpirationAttributes actualExpirationAttributes,
|
||||
ExpirationAttributes expectedExpirationAttributes) {
|
||||
|
||||
assertThat(actualExpirationAttributes).isEqualTo(expectedExpirationAttributes);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <K, V> Region<K, V> getRegion(String beanName) {
|
||||
return applicationContext.getBean(beanName, Region.class);
|
||||
}
|
||||
|
||||
protected AnnotationConfigApplicationContext newApplicationContext(Class<?>... annotatedClasses) {
|
||||
return new AnnotationConfigApplicationContext(annotatedClasses);
|
||||
}
|
||||
|
||||
protected ExpirationAttributes newExpirationAttributes(int timeout, ExpirationActionType action) {
|
||||
return newExpirationAttributes(timeout, action.getExpirationAction());
|
||||
}
|
||||
|
||||
protected ExpirationAttributes newExpirationAttributes(int timeout, ExpirationAction action) {
|
||||
return new ExpirationAttributes(timeout, action);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usesDefaultExpirationPolicyConfiguration() {
|
||||
applicationContext = newApplicationContext(DefaultExpirationPolicyConfiguration.class);
|
||||
|
||||
ExpirationAttributes expectedExpiration = newExpirationAttributes(0, ExpirationActionType.INVALIDATE);
|
||||
|
||||
Region one = getRegion("One");
|
||||
Region two = getRegion("Two");
|
||||
|
||||
assertIdleTimeoutExpiration(expectedExpiration, one);
|
||||
assertIdleTimeoutExpiration(expectedExpiration, two);
|
||||
|
||||
assertNoTimeToLiveExpiration(one);
|
||||
assertNoTimeToLiveExpiration(two);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usesCustomExpirationPolicyConfiguration() {
|
||||
applicationContext = newApplicationContext(CustomExpirationPolicyConfiguration.class);
|
||||
|
||||
ExpirationAttributes expectedExpiration = newExpirationAttributes(300, ExpirationActionType.LOCAL_DESTROY);
|
||||
|
||||
Region one = getRegion("One");
|
||||
Region two = getRegion("Two");
|
||||
|
||||
assertIdleTimeoutExpiration(expectedExpiration, one);
|
||||
assertIdleTimeoutExpiration(expectedExpiration, two);
|
||||
|
||||
assertNoTimeToLiveExpiration(one);
|
||||
assertNoTimeToLiveExpiration(two);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usesRegionSpecificExpirationPolicyConfiguration() {
|
||||
applicationContext = newApplicationContext(RegionSpecificExpirationPolicyConfiguration.class);
|
||||
|
||||
ExpirationAttributes expectedIdleTimeout = newExpirationAttributes(180, ExpirationActionType.INVALIDATE);
|
||||
ExpirationAttributes expectedTimeToLive = newExpirationAttributes(360, ExpirationActionType.DESTROY);
|
||||
|
||||
Region one = getRegion("One");
|
||||
Region two = getRegion("Two");
|
||||
|
||||
assertIdleTimeoutExpiration(expectedIdleTimeout, one);
|
||||
assertNoIdleTimeoutExpiration(two);
|
||||
|
||||
assertNoTimeToLiveExpiration(one);
|
||||
assertTimeToLiveExpiration(expectedTimeToLive, two);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usesMixedExpirationPolicyConfiguration() {
|
||||
applicationContext = newApplicationContext(MixedExpirationPolicyConfiguration.class);
|
||||
|
||||
ExpirationAttributes expectedIdleTimeout = newExpirationAttributes(120, ExpirationActionType.LOCAL_INVALIDATE);
|
||||
ExpirationAttributes expectedTimeToLive = newExpirationAttributes(600, ExpirationActionType.DESTROY);
|
||||
|
||||
Region one = getRegion("One");
|
||||
Region two = getRegion("Two");
|
||||
|
||||
assertIdleTimeoutExpiration(expectedIdleTimeout, one);
|
||||
assertNoIdleTimeoutExpiration(two);
|
||||
|
||||
assertTimeToLiveExpiration(expectedTimeToLive, one);
|
||||
assertTimeToLiveExpiration(expectedTimeToLive, two);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static <K, V> Region<K, V> mockRegion(String name) {
|
||||
Region<K, V> mockRegion = mock(Region.class);
|
||||
|
||||
when(mockRegion.getName()).thenReturn(name);
|
||||
when(mockRegion.getFullPath()).thenReturn(String.format("%1$s%2$s", Region.SEPARATOR, name));
|
||||
|
||||
final AtomicReference<CustomExpiry<K, V>> entryIdleTimeout = new AtomicReference<CustomExpiry<K, V>>(null);
|
||||
final AtomicReference<CustomExpiry<K, V>> entryTimeToLive = new AtomicReference<CustomExpiry<K, V>>(null);
|
||||
|
||||
AttributesMutator<K, V> mockAttributesMutator = mock(AttributesMutator.class);
|
||||
|
||||
when(mockRegion.getAttributesMutator()).thenReturn(mockAttributesMutator);
|
||||
|
||||
doAnswer(new Answer<CustomExpiry<K, V>>() {
|
||||
@Override
|
||||
public CustomExpiry<K, V> answer(InvocationOnMock invocation) throws Throwable {
|
||||
CustomExpiry<K, V> customExpiry = invocation.getArgumentAt(0, CustomExpiry.class);
|
||||
entryIdleTimeout.set(customExpiry);
|
||||
return customExpiry;
|
||||
}
|
||||
}).when(mockAttributesMutator).setCustomEntryIdleTimeout(any(CustomExpiry.class));
|
||||
|
||||
doAnswer(new Answer<CustomExpiry<K, V>>() {
|
||||
@Override
|
||||
public CustomExpiry<K, V> answer(InvocationOnMock invocation) throws Throwable {
|
||||
CustomExpiry<K, V> customExpiry = invocation.getArgumentAt(0, CustomExpiry.class);
|
||||
entryTimeToLive.set(customExpiry);
|
||||
return customExpiry;
|
||||
}
|
||||
}).when(mockAttributesMutator).setCustomEntryTimeToLive(any(CustomExpiry.class));
|
||||
|
||||
RegionAttributes<K, V> mockRegionAttributes = mock(RegionAttributes.class);
|
||||
|
||||
when(mockRegion.getAttributes()).thenReturn(mockRegionAttributes);
|
||||
|
||||
when(mockRegionAttributes.getCustomEntryIdleTimeout()).thenAnswer(new Answer<CustomExpiry<K, V>>() {
|
||||
@Override public CustomExpiry<K, V> answer(InvocationOnMock invocation) throws Throwable {
|
||||
return entryIdleTimeout.get();
|
||||
}
|
||||
});
|
||||
|
||||
when(mockRegionAttributes.getCustomEntryTimeToLive()).thenAnswer(new Answer<CustomExpiry<K, V>>() {
|
||||
@Override public CustomExpiry<K, V> answer(InvocationOnMock invocation) throws Throwable {
|
||||
return entryTimeToLive.get();
|
||||
}
|
||||
});
|
||||
|
||||
return mockRegion;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static <K, V> Region.Entry<K, V> mockRegionEntry(V applicationDomainObject) {
|
||||
Region.Entry<K, V> mockRegionEntry = mock(Region.Entry.class);
|
||||
when(mockRegionEntry.getValue()).thenReturn(applicationDomainObject);
|
||||
return mockRegionEntry;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@SuppressWarnings("unused")
|
||||
static class RegionConfiguration {
|
||||
|
||||
@Bean("One")
|
||||
Region<Object, Object> regionOne() {
|
||||
return mockRegion("One");
|
||||
}
|
||||
|
||||
@Bean("Two")
|
||||
Region<Object, Object> regionTwo() {
|
||||
return mockRegion("Two");
|
||||
}
|
||||
}
|
||||
|
||||
@EnableExpiration
|
||||
static class DefaultExpirationPolicyConfiguration extends RegionConfiguration {
|
||||
}
|
||||
|
||||
@EnableExpiration(policies = { @ExpirationPolicy(timeout = 300, action = ExpirationActionType.LOCAL_DESTROY) })
|
||||
static class CustomExpirationPolicyConfiguration extends RegionConfiguration {
|
||||
}
|
||||
|
||||
@EnableExpiration(policies = {
|
||||
@ExpirationPolicy(timeout = 180, action = ExpirationActionType.INVALIDATE, regionNames = "One"),
|
||||
@ExpirationPolicy(timeout = 360, action = ExpirationActionType.DESTROY, regionNames = "Two", types = ExpirationType.TIME_TO_LIVE)
|
||||
})
|
||||
static class RegionSpecificExpirationPolicyConfiguration extends RegionConfiguration {
|
||||
}
|
||||
|
||||
@EnableExpiration(policies = {
|
||||
@ExpirationPolicy(timeout = 120, action = ExpirationActionType.LOCAL_INVALIDATE, regionNames = "One", types = ExpirationType.IDLE_TIMEOUT),
|
||||
@ExpirationPolicy(timeout = 600, action = ExpirationActionType.DESTROY, types = ExpirationType.TIME_TO_LIVE)
|
||||
})
|
||||
static class MixedExpirationPolicyConfiguration extends RegionConfiguration {
|
||||
}
|
||||
}
|
||||
@@ -184,7 +184,7 @@ public class AnnotationBasedExpirationConfigurationIntegrationTest {
|
||||
public void invalidExpirationAction() {
|
||||
expectedException.expect(EvaluationException.class);
|
||||
expectedException.expectCause(isA(IllegalArgumentException.class));
|
||||
expectedException.expectMessage(String.format("'%1$s' is not resolvable as a valid ExpirationAction(Type)",
|
||||
expectedException.expectMessage(String.format("[%s] is not resolvable as an ExpirationAction(Type)",
|
||||
"@expirationProperties['gemfire.region.entry.expiration.invalid.action.string']"));
|
||||
genericExpiration.getExpiry(mockRegionEntry(new RegionEntryWithInvalidExpirationAction()));
|
||||
}
|
||||
@@ -236,5 +236,4 @@ public class AnnotationBasedExpirationConfigurationIntegrationTest {
|
||||
action = "@expirationProperties['gemfire.region.entry.expiration.action.spring.type']")
|
||||
protected static class RegionEntryWithInvalidExpirationTimeout {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user