Adapt to API changes in Spring Session core 2.0.0.RC2.

This commit is contained in:
John Blum
2017-11-28 20:58:27 -08:00
parent 318ed685d0
commit 2561d036ee
7 changed files with 1053 additions and 446 deletions

View File

@@ -17,6 +17,7 @@
package org.springframework.session.data.gemfire;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException;
import java.io.DataInput;
import java.io.DataOutput;
@@ -59,6 +60,7 @@ import org.springframework.session.Session;
import org.springframework.session.SessionRepository;
import org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration;
import org.springframework.session.data.gemfire.support.GemFireUtils;
import org.springframework.session.data.gemfire.support.SessionIdHolder;
import org.springframework.session.events.SessionCreatedEvent;
import org.springframework.session.events.SessionDeletedEvent;
import org.springframework.session.events.SessionDestroyedEvent;
@@ -79,9 +81,11 @@ import org.apache.commons.logging.LogFactory;
* @see org.apache.geode.DataSerializer
* @see org.apache.geode.Delta
* @see org.apache.geode.Instantiator
* @see org.apache.geode.cache.EntryEvent
* @see org.apache.geode.cache.Operation
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.util.CacheListenerAdapter
* @see org.springframework.beans.factory.InitializingBean
* @see org.springframework.context.ApplicationEvent
* @see org.springframework.context.ApplicationEventPublisher
* @see org.springframework.context.ApplicationEventPublisherAware
* @see org.springframework.data.gemfire.GemfireOperations
@@ -91,6 +95,10 @@ import org.apache.commons.logging.LogFactory;
* @see org.springframework.session.SessionRepository
* @see org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration
* @see org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession
* @see org.springframework.session.events.SessionCreatedEvent
* @see org.springframework.session.events.SessionDeletedEvent
* @see org.springframework.session.events.SessionDestroyedEvent
* @see org.springframework.session.events.SessionExpiredEvent
* @since 1.1.0
*/
public abstract class AbstractGemFireOperationsSessionRepository extends CacheListenerAdapter<Object, Session>
@@ -130,13 +138,11 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
/**
* Constructs a new instance of {@link Log} using Apache Commons {@link LogFactory}.
*
* Used in testing to override the {@link Log} implementation with a mock.
*
* @return an instance of {@link Log} constructed from Apache commons-logging {@link LogFactory}.
* @return a new instance of {@link Log} constructed from Apache commons-logging {@link LogFactory}.
* @see org.apache.commons.logging.LogFactory#getLog(Class)
* @see org.apache.commons.logging.Log
*/
Log newLogger() {
private Log newLogger() {
return LogFactory.getLog(getClass());
}
@@ -232,8 +238,11 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
* @see #getMaxInactiveInterval()
*/
public int getMaxInactiveIntervalInSeconds() {
return Optional.ofNullable(getMaxInactiveInterval()).map(Duration::getSeconds)
.map(Long::intValue).orElse(0);
return Optional.ofNullable(getMaxInactiveInterval())
.map(Duration::getSeconds)
.map(Long::intValue)
.orElse(0);
}
/**
@@ -292,17 +301,17 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
/* (non-Javadoc) */
boolean isCreate(EntryEvent<?, ?> event) {
return (isCreate(event.getOperation()) && isNotUpdate(event) && isSessionOrNull(event.getNewValue()));
return isCreate(event.getOperation()) && isNotUpdate(event) && isSession(event.getNewValue());
}
/* (non-Javadoc) */
private boolean isCreate(Operation operation) {
return (operation.isCreate() && !Operation.LOCAL_LOAD_CREATE.equals(operation));
return operation.isCreate() && !Operation.LOCAL_LOAD_CREATE.equals(operation);
}
/* (non-Javadoc) */
private boolean isNotUpdate(EntryEvent event) {
return (isNotProxyRegion() || !this.cachedSessionIds.contains(ObjectUtils.nullSafeHashCode(event.getKey())));
return isNotProxyRegion() || !this.cachedSessionIds.contains(ObjectUtils.nullSafeHashCode(event.getKey()));
}
/* (non-Javadoc) */
@@ -316,70 +325,120 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
}
/**
* Used to determine whether the developer is storing (HTTP) Sessions with other, arbitrary application
* domain objects in the same GemFire cache {@link Region}; crazier things have happened!
* Used to determine whether the application developer is storing (HTTP) Sessions with other, arbitrary
* application domain objects in the same GemFire cache {@link Region}; crazier things have happened!
*
* @param obj {@link Object} to evaluate.
* @return a boolean value indicating whether the {@link Object} from the entry event is indeed
* a {@link Session}.
* @return a boolean value indicating whether the old/new {@link Object} from the {@link Region}
* {@link EntryEvent} is indeed a {@link Session}.
* @see org.springframework.session.Session
*/
private boolean isSessionOrNull(Object obj) {
return (obj instanceof Session || obj == null);
private boolean isSession(Object obj) {
return obj instanceof Session;
}
/**
* Forgets the given {@link Object session ID}.
*
* @param sessionId {@link Object} containing the session ID to forget.
* @return a boolean value indicating whether the given session ID was even being remembered.
* @see #remember(Object)
*/
boolean forget(Object sessionId) {
return this.cachedSessionIds.remove(ObjectUtils.nullSafeHashCode(sessionId));
}
/**
* Rememvers the given {@link Object session ID}.
*
* @param sessionId {@link Object} containing the session ID to remember.
* @return a boolean value whether Spring Session is interested in and will remember
* this given session ID.
* @see #forget(Object)
*/
@SuppressWarnings("all")
boolean remember(Object sessionId) {
return (isProxyRegion() && this.cachedSessionIds.add(ObjectUtils.nullSafeHashCode(sessionId)));
}
/* (non-Javadoc) */
Session toSession(Object obj) {
return (obj instanceof Session ? (Session) obj : null);
return isProxyRegion() && this.cachedSessionIds.add(ObjectUtils.nullSafeHashCode(sessionId));
}
/**
* Casts the given {@link Object} into a {@link Session} iff the {@link Object} is a {@link Session}.
*
* Otherwise, this method attempts to use the supplied {@link String session ID} to create a {@link Session}
* containing only the ID.
*
* @param obj {@link Object} to evaluate as a {@link Session}.
* @param sessionId {@link String} containing the session ID.
* @return a {@link Session} from the given {@link Object}
* or a {@link Session} containing only the supplied {@link String session ID}.
* @throws IllegalStateException if the given {@link Object} is not a {@link Session}
* and {@link String session ID} was not supplied.
*/
Session toSession(Object obj, String sessionId) {
return obj instanceof Session ? (Session) obj
: Optional.ofNullable(sessionId)
.filter(StringUtils::hasText)
.map(SessionIdHolder::create)
.orElseThrow(() -> newIllegalStateException(
"Minimally, the session ID [%s] must be known to trigger a Session event", sessionId));
}
/**
* Callback method triggered when an entry is created in the GemFire cache {@link Region}.
*
* @param event {@link EntryEvent} containing the details of the cache {@link Region} operation.
* @param event {@link EntryEvent} containing the details of the cache operation.
* @see org.apache.geode.cache.EntryEvent
* @see #handleCreated(String, Session)
*/
@Override
public void afterCreate(EntryEvent<Object, Session> event) {
if (isCreate(event)) {
handleCreated(event.getKey().toString(), toSession(event.getNewValue()));
}
Optional.ofNullable(event)
.filter(this::isCreate)
.ifPresent(it -> {
String sessionId = it.getKey().toString();
handleCreated(sessionId, toSession(it.getNewValue(), sessionId));
});
}
/**
* Callback method triggered when an entry is destroyed in the GemFire cache
* {@link Region}.
* Callback method triggered when an entry is destroyed in the GemFire cache {@link Region}.
*
* @param event an EntryEvent containing the details of the cache operation.
* @param event {@link EntryEvent} containing the details of the cache operation.
* @see org.apache.geode.cache.EntryEvent
* @see #handleDestroyed(String, Session)
*/
@Override
public void afterDestroy(EntryEvent<Object, Session> event) {
handleDestroyed(event.getKey().toString(), toSession(event.getOldValue()));
Optional.ofNullable(event)
.ifPresent(it -> {
String sessionId = event.getKey().toString();
handleDestroyed(sessionId, toSession(event.getOldValue(), sessionId));
});
}
/**
* Callback method triggered when an entry is invalidated in the GemFire cache
* {@link Region}.
* Callback method triggered when an entry is invalidated in the GemFire cache {@link Region}.
*
* @param event an EntryEvent containing the details of the cache operation.
* @param event {@link EntryEvent} containing the details of the cache operation.
* @see org.apache.geode.cache.EntryEvent
* @see #handleExpired(String, Session)
*/
@Override
public void afterInvalidate(EntryEvent<Object, Session> event) {
handleExpired(event.getKey().toString(), toSession(event.getOldValue()));
Optional.ofNullable(event)
.ifPresent(it -> {
String sessionId = event.getKey().toString();
handleExpired(sessionId, toSession(event.getOldValue(), sessionId));
});
}
/**
@@ -402,12 +461,12 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
* @param session a reference to the Session triggering the event.
* @see org.springframework.session.events.SessionCreatedEvent
* @see org.springframework.session.Session
* @see #newSessionCreatedEvent(Session, String)
* @see #newSessionCreatedEvent(Session)
* @see #publishEvent(ApplicationEvent)
*/
protected void handleCreated(String sessionId, Session session) {
remember(sessionId);
publishEvent(newSessionCreatedEvent(session, sessionId));
publishEvent(newSessionCreatedEvent(session));
}
/**
@@ -417,13 +476,13 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
* @param session a reference to the Session triggering the event.
* @see org.springframework.session.events.SessionDeletedEvent
* @see org.springframework.session.Session
* @see #newSessionDeletedEvent(Session, String)
* @see #newSessionDeletedEvent(Session)
* @see #publishEvent(ApplicationEvent)
* @see #forget(Object)
*/
protected void handleDeleted(String sessionId, Session session) {
forget(sessionId);
publishEvent(newSessionDeletedEvent(session, sessionId));
publishEvent(newSessionDeletedEvent(session));
}
/**
@@ -433,13 +492,13 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
* @param session a reference to the Session triggering the event.
* @see org.springframework.session.events.SessionDestroyedEvent
* @see org.springframework.session.Session
* @see #newSessionDestroyedEvent(Session, String)
* @see #newSessionDestroyedEvent(Session)
* @see #publishEvent(ApplicationEvent)
* @see #forget(Object)
*/
protected void handleDestroyed(String sessionId, Session session) {
forget(sessionId);
publishEvent(newSessionDestroyedEvent(session, sessionId));
publishEvent(newSessionDestroyedEvent(session));
}
/**
@@ -449,41 +508,33 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
* @param session a reference to the Session triggering the event.
* @see org.springframework.session.events.SessionExpiredEvent
* @see org.springframework.session.Session
* @see #newSessionExpiredEvent(Session, String)
* @see #newSessionExpiredEvent(Session)
* @see #publishEvent(ApplicationEvent)
* @see #forget(Object)
*/
protected void handleExpired(String sessionId, Session session) {
forget(sessionId);
publishEvent(newSessionExpiredEvent(session, sessionId));
publishEvent(newSessionExpiredEvent(session));
}
/* (non-Javadoc) */
private SessionCreatedEvent newSessionCreatedEvent(Session session, String sessionId) {
return (session != null ? new SessionCreatedEvent(this, session)
: new SessionCreatedEvent(this, sessionId));
private SessionCreatedEvent newSessionCreatedEvent(Session session) {
return new SessionCreatedEvent(this, session);
}
/* (non-Javadoc) */
private SessionDeletedEvent newSessionDeletedEvent(Session session, String sessionId) {
return (session != null ? new SessionDeletedEvent(this, session)
: new SessionDeletedEvent(this, sessionId));
private SessionDeletedEvent newSessionDeletedEvent(Session session) {
return new SessionDeletedEvent(this, session);
}
/* (non-Javadoc) */
private SessionDestroyedEvent newSessionDestroyedEvent(Session session, String sessionId) {
return (session != null ? new SessionDestroyedEvent(this, session)
: new SessionDestroyedEvent(this, sessionId));
private SessionDestroyedEvent newSessionDestroyedEvent(Session session) {
return new SessionDestroyedEvent(this, session);
}
/* (non-Javadoc) */
private SessionExpiredEvent newSessionExpiredEvent(Session session, String sessionId) {
return (session != null ? new SessionExpiredEvent(this, session)
: new SessionExpiredEvent(this, sessionId));
private SessionExpiredEvent newSessionExpiredEvent(Session session) {
return new SessionExpiredEvent(this, session);
}
/**
@@ -498,8 +549,8 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
try {
getApplicationEventPublisher().publishEvent(event);
}
catch (Throwable t) {
getLogger().error(String.format("Error occurred publishing event [%s]", event), t);
catch (Throwable cause) {
getLogger().error(String.format("Error occurred while publishing event [%s]", event), cause);
}
}

View File

@@ -189,9 +189,10 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V>
*/
@SuppressWarnings("unchecked")
protected Interest<K>[] registerInterests(boolean register) {
return (!register ? new Interest[0] : new Interest[] {
new Interest<>("ALL_KEYS", InterestResultPolicy.KEYS)
});
return register
? new Interest[] { new Interest<>("ALL_KEYS", InterestResultPolicy.KEYS) }
: new Interest[0];
}
/**

View File

@@ -18,21 +18,26 @@ package org.springframework.session.data.gemfire.support;
import java.io.Closeable;
import java.io.IOException;
import java.util.Optional;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.apache.geode.internal.cache.GemFireCacheImpl;
/**
* GemFireUtils is an abstract, extensible utility class for working with GemFire types
* and functionality and is used by Spring Session's GemFire adapter support classes.
* {@link GemFireUtils} is an abstract, extensible utility class for working with GemFire objects and types.
*
* @author John Blum
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.client.ClientCache
* @since 1.1.0
*/
public abstract class GemFireUtils {
@@ -62,14 +67,17 @@ public abstract class GemFireUtils {
/**
* Determines whether the GemFire cache is a client.
*
* @param gemFireCache a reference to the GemFire cache.
* @param gemfireCache a reference to the GemFire cache.
* @return a boolean value indicating whether the GemFire cache is a client.
* @see org.apache.geode.cache.client.ClientCache
* @see org.apache.geode.cache.GemFireCache
*/
public static boolean isClient(GemFireCache gemFireCache) {
boolean client = (gemFireCache instanceof ClientCache);
client &= (!(gemFireCache instanceof GemFireCacheImpl) || ((GemFireCacheImpl) gemFireCache).isClient());
public static boolean isClient(GemFireCache gemfireCache) {
boolean client = (gemfireCache instanceof ClientCache);
client &= (!(gemfireCache instanceof GemFireCacheImpl) || ((GemFireCacheImpl) gemfireCache).isClient());
return client;
}
@@ -127,16 +135,28 @@ public abstract class GemFireUtils {
}
/**
* Determines whether the given {@link Region} is a PROXY, which would be indicated by the {@link Region}
* having a {@link DataPolicy} of {@link DataPolicy#EMPTY}.
* Determines whether the given {@link Region} is a {@literal PROXY}.
*
* @param region {@link Region} to evaluate.
* @return a boolean value indicating whether the {@link Region} is a PROXY.
* @param region {@link Region} to evaluate as a {@literal PROXY}; must not be {@literal null}.
* @return a boolean value indicating whether the {@link Region} is a {@literal PROXY}.
* @see org.apache.geode.cache.DataPolicy
* @see org.apache.geode.cache.Region
*/
public static boolean isProxy(Region<?, ?> region) {
return DataPolicy.EMPTY.equals(region.getAttributes().getDataPolicy());
RegionAttributes regionAttributes = region.getAttributes();
DataPolicy regionDataPolicy = regionAttributes.getDataPolicy();
boolean proxy = DataPolicy.EMPTY.equals(regionDataPolicy);
proxy |= proxy || Optional.ofNullable(regionDataPolicy)
.filter(DataPolicy.PARTITION::equals)
.map(it -> regionAttributes.getPartitionAttributes())
.filter(partitionAttributes -> partitionAttributes.getLocalMaxMemory() <= 0)
.isPresent();
return proxy;
}
/**

View File

@@ -0,0 +1,120 @@
/*
* 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.session.data.gemfire.support;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
import java.util.Optional;
import org.apache.geode.cache.EntryEvent;
import org.apache.geode.cache.Operation;
import org.apache.geode.cache.Region;
import org.springframework.session.Session;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
* {@link SessionIdHolder} class is a Spring Session {@link Session} implementation that only holds
* the {@link String ID} of the {@link Session}.
*
* This implementation is only used in case Apache Geode or Pivotal GemFire returns a {@literal null} (old) value
* in a {@link Region} {@link EntryEvent} triggered by a {@link Operation#DESTROY} or {@link Operation#INVALIDATE}
* operation.
*
* @author John Blum
* @see org.apache.geode.cache.EntryEvent
* @see org.apache.geode.cache.Operation
* @see org.apache.geode.cache.Region
* @see org.springframework.session.data.gemfire.support.SessionIdHolder
* @since 2.0.0
*/
public final class SessionIdHolder extends AbstractSession {
private final String sessionId;
/***
* Factory method to create an instance of the {@link SessionIdHolder} initialized with
* the given {@link String session ID}.
*
* @param sessionId {@link String} containing the session ID used to initialize
* the new instance of {@link SessionIdHolder}.
* @return a new instance of {@link SessionIdHolder} initialized with
* the given {@link String session ID}.
* @throws IllegalArgumentException if session ID is {@literal null} or empty.
* @see #SessionIdHolder(String)
*/
public static SessionIdHolder create(String sessionId) {
return new SessionIdHolder(sessionId);
}
/**
* Constructs a new instance of the {@link SessionIdHolder} initialized with
* the given {@link String session ID}.
*
* @param sessionId {@link String} containing the session ID used to initialize
* the new instance of {@link SessionIdHolder}.
* @throws IllegalArgumentException if session ID is {@literal null} or empty.
*/
public SessionIdHolder(String sessionId) {
this.sessionId = Optional.ofNullable(sessionId)
.filter(StringUtils::hasText)
.orElseThrow(() -> newIllegalArgumentException("Session ID [%s] is required", sessionId));
}
/**
* Returns the {@link String ID} of this {@link Session}.
*
* @return the {@link String ID} of this {@link Session}.
*/
@Override
public String getId() {
return this.sessionId;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Session)) {
return false;
}
Session that = (Session) obj;
return ObjectUtils.nullSafeEquals(this.getId(), that.getId());
}
@Override
public int hashCode() {
int hashValue = 17;
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getId());
return hashValue;
}
@Override
public String toString() {
return getId();
}
}

View File

@@ -18,10 +18,11 @@ package org.springframework.session.data.gemfire.support;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.willThrow;
import static org.mockito.Mockito.doThrow;
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.io.Closeable;
import java.io.IOException;
@@ -31,6 +32,7 @@ import org.junit.Test;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.PartitionAttributes;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.RegionShortcut;
@@ -38,34 +40,44 @@ import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.client.ClientRegionShortcut;
/**
* The GemFireUtilsTest class is a test suite of test cases testing the contract and
* functionality of the GemFireUtils utility class.
* Unit tests for {@link GemFireUtils}.
*
* @author John Blum
* @since 1.1.0
* @see org.junit.Test
* @see org.mockito.Mockito
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.client.ClientCache
* @see org.springframework.session.data.gemfire.support.GemFireUtils
*/
public class GemFireUtilsTests {
@Test
public void closeNonNullCloseableSuccessfullyReturnsTrue() throws IOException {
public void closeNonNullCloseableReturnsTrue() throws IOException {
Closeable mockCloseable = mock(Closeable.class);
assertThat(GemFireUtils.close(mockCloseable)).isTrue();
verify(mockCloseable, times(1)).close();
}
@Test
public void closeNonNullCloseableObjectThrowingIOExceptionReturnsFalse() throws IOException {
public void closeNonNullCloseableThrowingIOExceptionReturnsFalse() throws IOException {
Closeable mockCloseable = mock(Closeable.class);
willThrow(new IOException("test")).given(mockCloseable).close();
doThrow(new IOException("test")).when(mockCloseable).close();
assertThat(GemFireUtils.close(mockCloseable)).isFalse();
verify(mockCloseable, times(1)).close();
}
@Test
public void closeNullCloseableObjectReturnsFalse() {
public void closeNullCloseableReturnsFalse() {
assertThat(GemFireUtils.close(null)).isFalse();
}
@@ -101,6 +113,7 @@ public class GemFireUtilsTests {
@Test
public void clientRegionShortcutIsLocal() {
assertThat(GemFireUtils.isLocal(ClientRegionShortcut.LOCAL)).isTrue();
assertThat(GemFireUtils.isLocal(ClientRegionShortcut.LOCAL_HEAP_LRU)).isTrue();
assertThat(GemFireUtils.isLocal(ClientRegionShortcut.LOCAL_OVERFLOW)).isTrue();
@@ -110,6 +123,7 @@ public class GemFireUtilsTests {
@Test
public void clientRegionShortcutIsNotLocal() {
assertThat(GemFireUtils.isLocal(ClientRegionShortcut.CACHING_PROXY)).isFalse();
assertThat(GemFireUtils.isLocal(ClientRegionShortcut.CACHING_PROXY_HEAP_LRU)).isFalse();
assertThat(GemFireUtils.isLocal(ClientRegionShortcut.CACHING_PROXY_OVERFLOW)).isFalse();
@@ -123,6 +137,7 @@ public class GemFireUtilsTests {
@Test
public void clientRegionShortcutIsNotProxy() {
assertThat(GemFireUtils.isProxy(ClientRegionShortcut.CACHING_PROXY)).isFalse();
assertThat(GemFireUtils.isProxy(ClientRegionShortcut.CACHING_PROXY_HEAP_LRU)).isFalse();
assertThat(GemFireUtils.isProxy(ClientRegionShortcut.CACHING_PROXY_OVERFLOW)).isFalse();
@@ -134,19 +149,14 @@ public class GemFireUtilsTests {
}
@Test
public void regionShortcutIsProxy() {
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_PROXY)).isTrue();
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_PROXY_REDUNDANT)).isTrue();
assertThat(GemFireUtils.isProxy(RegionShortcut.REPLICATE_PROXY)).isTrue();
}
public void emptyRegionIsProxy() {
@Test
public void regionIsProxy() {
Region mockRegion = mock(Region.class);
RegionAttributes mockRegionAttributes = mock(RegionAttributes.class);
given(mockRegion.getAttributes()).willReturn(mockRegionAttributes);
given(mockRegionAttributes.getDataPolicy()).willReturn(DataPolicy.EMPTY);
when(mockRegion.getAttributes()).thenReturn(mockRegionAttributes);
when(mockRegionAttributes.getDataPolicy()).thenReturn(DataPolicy.EMPTY);
assertThat(GemFireUtils.isProxy(mockRegion)).isTrue();
@@ -155,8 +165,54 @@ public class GemFireUtilsTests {
}
@Test
public void regionIsNotProxy() {
public void partitionRegionWithNoLocalMaxMemoryIsProxy() {
Region mockRegion = mock(Region.class);
RegionAttributes mockRegionAttributes = mock(RegionAttributes.class);
PartitionAttributes mockPartitionAttributes = mock(PartitionAttributes.class);
when(mockRegion.getAttributes()).thenReturn(mockRegionAttributes);
when(mockRegionAttributes.getDataPolicy()).thenReturn(DataPolicy.PARTITION);
when(mockRegionAttributes.getPartitionAttributes()).thenReturn(mockPartitionAttributes);
when(mockPartitionAttributes.getLocalMaxMemory()).thenReturn(0);
assertThat(GemFireUtils.isProxy(mockRegion)).isTrue();
verify(mockRegion, times(1)).getAttributes();
verify(mockRegionAttributes, times(1)).getDataPolicy();
verify(mockRegionAttributes, times(1)).getPartitionAttributes();
verify(mockPartitionAttributes, times(1)).getLocalMaxMemory();
}
@Test
public void partitionRegionWithNegativeLocalMaxMemoryIsProxy() {
Region mockRegion = mock(Region.class);
RegionAttributes mockRegionAttributes = mock(RegionAttributes.class);
PartitionAttributes mockPartitionAttributes = mock(PartitionAttributes.class);
when(mockRegion.getAttributes()).thenReturn(mockRegionAttributes);
when(mockRegionAttributes.getDataPolicy()).thenReturn(DataPolicy.PARTITION);
when(mockRegionAttributes.getPartitionAttributes()).thenReturn(mockPartitionAttributes);
when(mockPartitionAttributes.getLocalMaxMemory()).thenReturn(-1);
assertThat(GemFireUtils.isProxy(mockRegion)).isTrue();
verify(mockRegion, times(1)).getAttributes();
verify(mockRegionAttributes, times(1)).getDataPolicy();
verify(mockRegionAttributes, times(1)).getPartitionAttributes();
verify(mockPartitionAttributes, times(1)).getLocalMaxMemory();
}
@Test
public void normalRegionIsNotProxy() {
Region mockRegion = mock(Region.class);
RegionAttributes mockRegionAttributes = mock(RegionAttributes.class);
given(mockRegion.getAttributes()).willReturn(mockRegionAttributes);
@@ -168,8 +224,89 @@ public class GemFireUtilsTests {
verify(mockRegionAttributes, times(1)).getDataPolicy();
}
@Test
public void partitionRegionWithLocalMaxMemoryIsNotProxy() {
Region mockRegion = mock(Region.class);
RegionAttributes mockRegionAttributes = mock(RegionAttributes.class);
PartitionAttributes mockPartitionAttributes = mock(PartitionAttributes.class);
when(mockRegion.getAttributes()).thenReturn(mockRegionAttributes);
when(mockRegionAttributes.getDataPolicy()).thenReturn(DataPolicy.PARTITION);
when(mockRegionAttributes.getPartitionAttributes()).thenReturn(mockPartitionAttributes);
when(mockPartitionAttributes.getLocalMaxMemory()).thenReturn(1);
assertThat(GemFireUtils.isProxy(mockRegion)).isFalse();
verify(mockRegion, times(1)).getAttributes();
verify(mockRegionAttributes, times(1)).getDataPolicy();
verify(mockRegionAttributes, times(1)).getPartitionAttributes();
verify(mockPartitionAttributes, times(1)).getLocalMaxMemory();
}
@Test
public void partitionRegionWithNoPartitionAttributesIsNotProxy() {
Region mockRegion = mock(Region.class);
RegionAttributes mockRegionAttributes = mock(RegionAttributes.class);
when(mockRegion.getAttributes()).thenReturn(mockRegionAttributes);
when(mockRegionAttributes.getDataPolicy()).thenReturn(DataPolicy.PARTITION);
when(mockRegionAttributes.getPartitionAttributes()).thenReturn(null);
assertThat(GemFireUtils.isProxy(mockRegion)).isFalse();
verify(mockRegion, times(1)).getAttributes();
verify(mockRegionAttributes, times(1)).getDataPolicy();
verify(mockRegionAttributes, times(1)).getPartitionAttributes();
}
@Test
public void preloadedRegionIsNotProxy() {
Region mockRegion = mock(Region.class);
RegionAttributes mockRegionAttributes = mock(RegionAttributes.class);
given(mockRegion.getAttributes()).willReturn(mockRegionAttributes);
given(mockRegionAttributes.getDataPolicy()).willReturn(DataPolicy.PRELOADED);
assertThat(GemFireUtils.isProxy(mockRegion)).isFalse();
verify(mockRegion, times(1)).getAttributes();
verify(mockRegionAttributes, times(1)).getDataPolicy();
}
@Test
public void replicateRegionIsNotProxy() {
Region mockRegion = mock(Region.class);
RegionAttributes mockRegionAttributes = mock(RegionAttributes.class);
given(mockRegion.getAttributes()).willReturn(mockRegionAttributes);
given(mockRegionAttributes.getDataPolicy()).willReturn(DataPolicy.REPLICATE);
assertThat(GemFireUtils.isProxy(mockRegion)).isFalse();
verify(mockRegion, times(1)).getAttributes();
verify(mockRegionAttributes, times(1)).getDataPolicy();
}
@Test
public void regionShortcutIsProxy() {
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_PROXY)).isTrue();
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_PROXY_REDUNDANT)).isTrue();
assertThat(GemFireUtils.isProxy(RegionShortcut.REPLICATE_PROXY)).isTrue();
}
@Test
public void regionShortcutIsNotProxy() {
assertThat(GemFireUtils.isProxy(RegionShortcut.LOCAL)).isFalse();
assertThat(GemFireUtils.isProxy(RegionShortcut.LOCAL_HEAP_LRU)).isFalse();
assertThat(GemFireUtils.isProxy(RegionShortcut.LOCAL_OVERFLOW)).isFalse();
@@ -194,6 +331,7 @@ public class GemFireUtilsTests {
@Test
public void toRegionPath() {
assertThat(GemFireUtils.toRegionPath("A")).isEqualTo("/A");
assertThat(GemFireUtils.toRegionPath("Example")).isEqualTo("/Example");
assertThat(GemFireUtils.toRegionPath("/Example")).isEqualTo("//Example");

View File

@@ -0,0 +1,133 @@
/*
* 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.session.data.gemfire.support;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.springframework.session.Session;
/**
* Unit tests for {@link SessionIdHolder}.
*
* @author John Blum
* @see org.junit.Test
* @see org.springframework.session.Session
* @see org.springframework.session.data.gemfire.support.SessionIdHolder
* @since 2.0.0
*/
public class SessionIdHolderTests {
@Test
public void createSessionIdHolderWithId() {
SessionIdHolder session = SessionIdHolder.create("12345");
assertThat(session).isNotNull();
assertThat(session.getId()).isEqualTo("12345");
}
@Test(expected = IllegalArgumentException.class)
public void createSessionIdHolderWithEmptyId() {
try {
SessionIdHolder.create(" ");
}
catch (IllegalArgumentException expected) {
assertThat(expected).hasMessage("Session ID [ ] is required");
assertThat(expected).hasNoCause();
throw expected;
}
}
@Test(expected = IllegalArgumentException.class)
public void createSessionIdHolderWithNoId() {
try {
SessionIdHolder.create(null);
}
catch (IllegalArgumentException expected) {
assertThat(expected).hasMessage("Session ID [null] is required");
assertThat(expected).hasNoCause();
throw expected;
}
}
@Test
public void equalsWithSameSessionReturnsTrue() {
Session session = SessionIdHolder.create("12345");
assertThat(session.equals(session)).isTrue();
}
@Test
public void equalsWithEqualSessionsReturnsTrue() {
Session sessionOne = SessionIdHolder.create("12345");
Session sessionTwo = SessionIdHolder.create("12345");
assertThat(sessionOne.equals(sessionTwo)).isTrue();
}
@Test
@SuppressWarnings("all")
public void equalsWithUnequalSessionsReturnsFalse() {
Session sessionOne = SessionIdHolder.create("123");
Session sessionTwo = SessionIdHolder.create("12345");
assertThat(sessionOne.equals(sessionTwo)).isFalse();
assertThat(sessionTwo.equals(null)).isFalse();
}
@Test
public void hashCodeForSameSessionIsEqual() {
Session session = SessionIdHolder.create("12345");
assertThat(session.hashCode()).isEqualTo(session.hashCode());
}
@Test
public void hashCodeWithEqualSessionsIsEqual() {
Session sessionOne = SessionIdHolder.create("12345");
Session sessionTwo = SessionIdHolder.create("12345");
assertThat(sessionOne.hashCode()).isEqualTo(sessionTwo.hashCode());
}
@Test
public void hashCodeForUnequalSessionsAreNotEqual() {
Session sessionOne = SessionIdHolder.create("123");
Session sessionTwo = SessionIdHolder.create("12345");
assertThat(sessionOne.hashCode()).isNotEqualTo(sessionTwo.hashCode());
}
@Test
public void toStringReturnsSessionId() {
assertThat(SessionIdHolder.create("12345").toString()).isEqualTo("12345");
}
}