Restore proper behavior of HttpSession created events in GemFire support when client Region is a PROXY in the client/server topology
Fixes gh-757
(cherry picked from commit c0c404ab96)
Signed-off-by: John Blum <jblum@pivotal.io>
This commit is contained in:
@@ -36,6 +36,7 @@ import com.gemstone.gemfire.cache.client.ClientCache;
|
||||
import com.gemstone.gemfire.cache.client.ClientCacheFactory;
|
||||
import com.gemstone.gemfire.cache.query.Index;
|
||||
import com.gemstone.gemfire.cache.server.CacheServer;
|
||||
|
||||
import org.junit.Before;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -310,6 +311,13 @@ public abstract class AbstractGemFireIntegrationTests {
|
||||
return processControl;
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
protected void assertValidSession(ExpiringSession session) {
|
||||
assertThat(session).isNotNull();
|
||||
assertThat(session.getId()).isNotEmpty();
|
||||
assertThat(session.isExpired()).isFalse();
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
protected void assertRegion(Region<?, ?> actualRegion, String expectedName, DataPolicy expectedDataPolicy) {
|
||||
assertThat(actualRegion).isNotNull();
|
||||
@@ -379,6 +387,12 @@ public abstract class AbstractGemFireIntegrationTests {
|
||||
return (T) session;
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
protected <T extends ExpiringSession> T delete(T session) {
|
||||
this.gemfireSessionRepository.delete(session);
|
||||
return session;
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
protected <T extends ExpiringSession> T expire(T session) {
|
||||
session.setLastAccessedTime(0L);
|
||||
|
||||
@@ -135,7 +135,7 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopGemFireServerAndDeleteArtifacts() {
|
||||
public static void stopGemFireServer() {
|
||||
if (gemfireServer != null) {
|
||||
gemfireServer.destroy();
|
||||
System.err.printf("GemFire Server [exit code = %1$d]%n",
|
||||
@@ -332,7 +332,7 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests
|
||||
}
|
||||
|
||||
String name() {
|
||||
return SpringSessionDataGemFireServerConfiguration.class.getName();
|
||||
return ClientServerGemFireOperationsSessionRepositoryIntegrationTests.class.getName();
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -112,7 +112,7 @@ public class ClientServerHttpSessionAttributesDeltaIntegrationTests extends Abst
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopGemFireServerAndDeleteArtifacts() {
|
||||
public static void stopGemFireServer() {
|
||||
if (gemfireServer != null) {
|
||||
gemfireServer.destroy();
|
||||
System.err.printf("GemFire Server [exit code = %1$d]%n",
|
||||
@@ -165,7 +165,7 @@ public class ClientServerHttpSessionAttributesDeltaIntegrationTests extends Abst
|
||||
assertThat(reloadedSession.<Integer>getAttribute("attrOne")).isEqualTo(1);
|
||||
}
|
||||
|
||||
@EnableGemFireHttpSession(maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
|
||||
@EnableGemFireHttpSession
|
||||
static class SpringSessionDataGemFireClientConfiguration {
|
||||
|
||||
@Bean
|
||||
@@ -245,7 +245,7 @@ public class ClientServerHttpSessionAttributesDeltaIntegrationTests extends Abst
|
||||
}
|
||||
|
||||
String name() {
|
||||
return SpringSessionDataGemFireServerConfiguration.class.getName();
|
||||
return ClientServerHttpSessionAttributesDeltaIntegrationTests.class.getName();
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright 2014-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.session.data.gemfire;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.gemstone.gemfire.cache.Cache;
|
||||
import com.gemstone.gemfire.cache.client.ClientCache;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.data.gemfire.CacheFactoryBean;
|
||||
import org.springframework.data.gemfire.client.ClientCacheFactoryBean;
|
||||
import org.springframework.data.gemfire.client.PoolFactoryBean;
|
||||
import org.springframework.data.gemfire.server.CacheServerFactoryBean;
|
||||
import org.springframework.data.gemfire.support.ConnectionEndpoint;
|
||||
import org.springframework.session.ExpiringSession;
|
||||
import org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession;
|
||||
import org.springframework.session.events.AbstractSessionEvent;
|
||||
import org.springframework.session.events.SessionCreatedEvent;
|
||||
import org.springframework.session.events.SessionDeletedEvent;
|
||||
import org.springframework.session.events.SessionExpiredEvent;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.util.FileSystemUtils;
|
||||
import org.springframework.util.SocketUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* The ClientServerProxyRegionSessionOperationsIntegrationTests class...
|
||||
*
|
||||
* @author John Blum
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration(classes =
|
||||
ClientServerProxyRegionSessionOperationsIntegrationTests.SpringSessionDataGemFireClientConfiguration.class)
|
||||
public class ClientServerProxyRegionSessionOperationsIntegrationTests extends AbstractGemFireIntegrationTests {
|
||||
|
||||
private static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 1;
|
||||
|
||||
private static final DateFormat TIMESTAMP = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
|
||||
|
||||
private static File processWorkingDirectory;
|
||||
|
||||
private static Process gemfireServer;
|
||||
|
||||
@Autowired
|
||||
private SessionEventListener sessionEventListener;
|
||||
|
||||
@BeforeClass
|
||||
public static void startGemFireServer() throws IOException {
|
||||
long t0 = System.currentTimeMillis();
|
||||
|
||||
int port = SocketUtils.findAvailableTcpPort();
|
||||
|
||||
System.err.printf("Starting a GemFire Server running on host [%1$s] listening on port [%2$d]%n",
|
||||
SpringSessionDataGemFireServerConfiguration.SERVER_HOSTNAME, port);
|
||||
|
||||
System.setProperty("spring.session.data.gemfire.port", String.valueOf(port));
|
||||
|
||||
String processWorkingDirectoryPathname =
|
||||
String.format("gemfire-client-server-tests-%1$s", TIMESTAMP.format(new Date()));
|
||||
|
||||
processWorkingDirectory = createDirectory(processWorkingDirectoryPathname);
|
||||
|
||||
gemfireServer = run(SpringSessionDataGemFireServerConfiguration.class, processWorkingDirectory,
|
||||
String.format("-Dspring.session.data.gemfire.port=%1$d", port));
|
||||
|
||||
assertThat(waitForCacheServerToStart(SpringSessionDataGemFireServerConfiguration.SERVER_HOSTNAME, port))
|
||||
.isTrue();
|
||||
|
||||
System.err.printf("GemFire Server [startup time = %1$d ms]%n", System.currentTimeMillis() - t0);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopGemFireServer() {
|
||||
if (gemfireServer != null) {
|
||||
gemfireServer.destroy();
|
||||
System.err.printf("GemFire Server [exit code = %1$d]%n",
|
||||
waitForProcessToStop(gemfireServer, processWorkingDirectory));
|
||||
}
|
||||
|
||||
if (Boolean.valueOf(System.getProperty("spring.session.data.gemfire.fork.clean", Boolean.TRUE.toString()))) {
|
||||
FileSystemUtils.deleteRecursively(processWorkingDirectory);
|
||||
}
|
||||
|
||||
assertThat(waitForClientCacheToClose(DEFAULT_WAIT_DURATION)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createReadUpdateExpireRecreateDeleteRecreateSessionResultsCorrectSessionCreatedEvents() {
|
||||
ExpiringSession session = save(touch(createSession()));
|
||||
|
||||
assertValidSession(session);
|
||||
|
||||
AbstractSessionEvent sessionEvent = this.sessionEventListener.waitForSessionEvent(500);
|
||||
|
||||
assertThat(sessionEvent).isInstanceOf(SessionCreatedEvent.class);
|
||||
assertThat(sessionEvent.getSessionId()).isEqualTo(session.getId());
|
||||
|
||||
// GET
|
||||
ExpiringSession loadedSession = get(session.getId());
|
||||
|
||||
assertThat(loadedSession).isNotNull();
|
||||
assertThat(loadedSession.getId()).isEqualTo(session.getId());
|
||||
assertThat(loadedSession.getCreationTime()).isEqualTo(session.getCreationTime());
|
||||
assertThat(loadedSession.getLastAccessedTime()).isGreaterThanOrEqualTo((session.getLastAccessedTime()));
|
||||
|
||||
sessionEvent = this.sessionEventListener.waitForSessionEvent(500);
|
||||
|
||||
assertThat(sessionEvent).isNull();
|
||||
|
||||
loadedSession.setAttribute("attrOne", 1);
|
||||
loadedSession.setAttribute("attrTwo", 2);
|
||||
|
||||
// UPDATE
|
||||
save(touch(loadedSession));
|
||||
|
||||
sessionEvent = this.sessionEventListener.waitForSessionEvent(500);
|
||||
|
||||
assertThat(sessionEvent).isNull();
|
||||
|
||||
// EXPIRE
|
||||
sessionEvent = this.sessionEventListener.waitForSessionEvent(
|
||||
TimeUnit.SECONDS.toMillis(MAX_INACTIVE_INTERVAL_IN_SECONDS + 1));
|
||||
|
||||
assertThat(sessionEvent).isInstanceOf(SessionExpiredEvent.class);
|
||||
assertThat(sessionEvent.getSessionId()).isEqualTo(session.getId());
|
||||
|
||||
// RECREATE
|
||||
save(touch(session));
|
||||
|
||||
sessionEvent = this.sessionEventListener.waitForSessionEvent(500);
|
||||
|
||||
assertThat(sessionEvent).isInstanceOf(SessionCreatedEvent.class);
|
||||
assertThat(sessionEvent.getSessionId()).isEqualTo(session.getId());
|
||||
|
||||
// DELETE
|
||||
delete(session);
|
||||
|
||||
sessionEvent = this.sessionEventListener.waitForSessionEvent(500);
|
||||
|
||||
assertThat(sessionEvent).isInstanceOf(SessionDeletedEvent.class);
|
||||
assertThat(sessionEvent.getSessionId()).isEqualTo(session.getId());
|
||||
|
||||
// RECREATE
|
||||
save(touch(session));
|
||||
|
||||
sessionEvent = this.sessionEventListener.waitForSessionEvent(500);
|
||||
|
||||
assertThat(sessionEvent).isInstanceOf(SessionCreatedEvent.class);
|
||||
assertThat(sessionEvent.getSessionId()).isEqualTo(session.getId());
|
||||
}
|
||||
|
||||
@EnableGemFireHttpSession
|
||||
static class SpringSessionDataGemFireClientConfiguration {
|
||||
|
||||
@Bean
|
||||
static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
|
||||
return new PropertySourcesPlaceholderConfigurer();
|
||||
}
|
||||
|
||||
Properties gemfireProperties() {
|
||||
Properties gemfireProperties = new Properties();
|
||||
gemfireProperties.setProperty("log-level", GEMFIRE_LOG_LEVEL);
|
||||
return gemfireProperties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
ClientCacheFactoryBean gemfireCache() {
|
||||
ClientCacheFactoryBean clientCacheFactory = new ClientCacheFactoryBean();
|
||||
|
||||
clientCacheFactory.setClose(true);
|
||||
clientCacheFactory.setProperties(gemfireProperties());
|
||||
|
||||
return clientCacheFactory;
|
||||
}
|
||||
|
||||
@Bean
|
||||
PoolFactoryBean gemfirePool(@Value("${spring.session.data.gemfire.port:"
|
||||
+ DEFAULT_GEMFIRE_SERVER_PORT + "}") int port) {
|
||||
|
||||
PoolFactoryBean poolFactory = new PoolFactoryBean();
|
||||
|
||||
poolFactory.setKeepAlive(false);
|
||||
poolFactory.setPingInterval(TimeUnit.SECONDS.toMillis(5));
|
||||
poolFactory.setReadTimeout(2000); // 2 seconds
|
||||
poolFactory.setRetryAttempts(1);
|
||||
poolFactory.setSubscriptionEnabled(true);
|
||||
|
||||
poolFactory.setServers(Collections.singletonList(new ConnectionEndpoint(
|
||||
SpringSessionDataGemFireServerConfiguration.SERVER_HOSTNAME, port)));
|
||||
|
||||
return poolFactory;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SessionEventListener sessionEventListener() {
|
||||
return new SessionEventListener();
|
||||
}
|
||||
|
||||
// used for debugging purposes
|
||||
@SuppressWarnings("resource")
|
||||
public static void main(String[] args) {
|
||||
ConfigurableApplicationContext applicationContext =
|
||||
new AnnotationConfigApplicationContext(SpringSessionDataGemFireClientConfiguration.class);
|
||||
|
||||
applicationContext.registerShutdownHook();
|
||||
|
||||
ClientCache clientCache = applicationContext.getBean(ClientCache.class);
|
||||
|
||||
for (InetSocketAddress server : clientCache.getCurrentServers()) {
|
||||
System.err.printf("GemFire Server [host: %1$s, port: %2$d]%n",
|
||||
server.getHostName(), server.getPort());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EnableGemFireHttpSession(maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
|
||||
static class SpringSessionDataGemFireServerConfiguration {
|
||||
|
||||
static final String SERVER_HOSTNAME = "localhost";
|
||||
|
||||
@Bean
|
||||
static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
|
||||
return new PropertySourcesPlaceholderConfigurer();
|
||||
}
|
||||
|
||||
Properties gemfireProperties() {
|
||||
Properties gemfireProperties = new Properties();
|
||||
|
||||
gemfireProperties.setProperty("name", name());
|
||||
gemfireProperties.setProperty("mcast-port", "0");
|
||||
gemfireProperties.setProperty("log-level", GEMFIRE_LOG_LEVEL);
|
||||
|
||||
return gemfireProperties;
|
||||
}
|
||||
|
||||
String name() {
|
||||
return ClientServerProxyRegionSessionOperationsIntegrationTests.class.getName();
|
||||
}
|
||||
|
||||
@Bean
|
||||
CacheFactoryBean gemfireCache() {
|
||||
CacheFactoryBean gemfireCache = new CacheFactoryBean();
|
||||
|
||||
gemfireCache.setClose(true);
|
||||
gemfireCache.setProperties(gemfireProperties());
|
||||
|
||||
return gemfireCache;
|
||||
}
|
||||
|
||||
@Bean
|
||||
CacheServerFactoryBean gemfireCacheServer(Cache gemfireCache,
|
||||
@Value("${spring.session.data.gemfire.port:" + DEFAULT_GEMFIRE_SERVER_PORT + "}") int port) {
|
||||
|
||||
CacheServerFactoryBean cacheServerFactory = new CacheServerFactoryBean();
|
||||
|
||||
cacheServerFactory.setCache(gemfireCache);
|
||||
cacheServerFactory.setAutoStartup(true);
|
||||
cacheServerFactory.setBindAddress(SERVER_HOSTNAME);
|
||||
cacheServerFactory.setPort(port);
|
||||
|
||||
return cacheServerFactory;
|
||||
}
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
public static void main(String[] args) throws IOException {
|
||||
AnnotationConfigApplicationContext context =
|
||||
new AnnotationConfigApplicationContext(SpringSessionDataGemFireServerConfiguration.class);
|
||||
|
||||
context.registerShutdownHook();
|
||||
|
||||
writeProcessControlFile(WORKING_DIRECTORY);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,8 +39,10 @@ import com.gemstone.gemfire.Delta;
|
||||
import com.gemstone.gemfire.Instantiator;
|
||||
import com.gemstone.gemfire.InvalidDeltaException;
|
||||
import com.gemstone.gemfire.cache.EntryEvent;
|
||||
import com.gemstone.gemfire.cache.Operation;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
import com.gemstone.gemfire.cache.util.CacheListenerAdapter;
|
||||
import com.gemstone.gemfire.internal.concurrent.ConcurrentHashSet;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -58,11 +60,13 @@ import org.springframework.session.FindByIndexNameSessionRepository;
|
||||
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.events.SessionCreatedEvent;
|
||||
import org.springframework.session.events.SessionDeletedEvent;
|
||||
import org.springframework.session.events.SessionDestroyedEvent;
|
||||
import org.springframework.session.events.SessionExpiredEvent;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -91,6 +95,8 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
|
||||
}
|
||||
};
|
||||
|
||||
private final Set<Integer> cachedSessionIds = new ConcurrentHashSet<Integer>();
|
||||
|
||||
private final GemfireOperations template;
|
||||
|
||||
protected final Log logger = newLogger();
|
||||
@@ -217,8 +223,49 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
boolean isExpiringSessionOrNull(Object obj) {
|
||||
return (obj == null || obj instanceof ExpiringSession);
|
||||
boolean isCreate(EntryEvent<?, ?> event) {
|
||||
return (isCreate(event.getOperation()) && isNotUpdate(event) && isExpiringSessionOrNull(event.getNewValue()));
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
private boolean isCreate(Operation operation) {
|
||||
return (operation.isCreate() && !Operation.LOCAL_LOAD_CREATE.equals(operation));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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!
|
||||
*
|
||||
* @param obj {@link Object} to evaluate.
|
||||
* @return a boolean value indicating whether the {@link Object} from the entry event is indeed
|
||||
* a {@link ExpiringSession}.
|
||||
* @see org.springframework.session.ExpiringSession
|
||||
*/
|
||||
private boolean isExpiringSessionOrNull(Object obj) {
|
||||
return (obj instanceof ExpiringSession || obj == null);
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
private boolean isNotUpdate(EntryEvent event) {
|
||||
return (isNotProxyRegion() || !this.cachedSessionIds.contains(ObjectUtils.nullSafeHashCode(event.getKey())));
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
private boolean isNotProxyRegion() {
|
||||
return !isProxyRegion();
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
private boolean isProxyRegion() {
|
||||
return GemFireUtils.isProxy(((GemfireAccessor) getTemplate()).getRegion());
|
||||
}
|
||||
|
||||
boolean forget(Object sessionId) {
|
||||
return this.cachedSessionIds.remove(ObjectUtils.nullSafeHashCode(sessionId));
|
||||
}
|
||||
|
||||
boolean remember(Object sessionId) {
|
||||
return (isProxyRegion() && this.cachedSessionIds.add(ObjectUtils.nullSafeHashCode(sessionId)));
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
@@ -227,16 +274,15 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback method triggered when an entry is created in the GemFire cache
|
||||
* {@link Region}.
|
||||
* Callback method triggered when an entry is created 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 {@link Region} operation.
|
||||
* @see com.gemstone.gemfire.cache.EntryEvent
|
||||
* @see #handleCreated(String, ExpiringSession)
|
||||
*/
|
||||
@Override
|
||||
public void afterCreate(EntryEvent<Object, ExpiringSession> event) {
|
||||
if (isExpiringSessionOrNull(event.getNewValue())) {
|
||||
if (isCreate(event)) {
|
||||
handleCreated(event.getKey().toString(), toExpiringSession(event.getNewValue()));
|
||||
}
|
||||
}
|
||||
@@ -290,6 +336,8 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
|
||||
* @see #publishEvent(ApplicationEvent)
|
||||
*/
|
||||
protected void handleCreated(String sessionId, ExpiringSession session) {
|
||||
remember(sessionId);
|
||||
|
||||
publishEvent(session != null ? new SessionCreatedEvent(this, session)
|
||||
: new SessionCreatedEvent(this, sessionId));
|
||||
}
|
||||
@@ -304,6 +352,8 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
|
||||
* @see #publishEvent(ApplicationEvent)
|
||||
*/
|
||||
protected void handleDeleted(String sessionId, ExpiringSession session) {
|
||||
forget(sessionId);
|
||||
|
||||
publishEvent(session != null ? new SessionDeletedEvent(this, session)
|
||||
: new SessionDeletedEvent(this, sessionId));
|
||||
}
|
||||
@@ -318,6 +368,8 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
|
||||
* @see #publishEvent(ApplicationEvent)
|
||||
*/
|
||||
protected void handleDestroyed(String sessionId, ExpiringSession session) {
|
||||
forget(sessionId);
|
||||
|
||||
publishEvent(session != null ? new SessionDestroyedEvent(this, session)
|
||||
: new SessionDestroyedEvent(this, sessionId));
|
||||
}
|
||||
@@ -332,6 +384,8 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
|
||||
* @see #publishEvent(ApplicationEvent)
|
||||
*/
|
||||
protected void handleExpired(String sessionId, ExpiringSession session) {
|
||||
forget(sessionId);
|
||||
|
||||
publishEvent(session != null ? new SessionExpiredEvent(this, session)
|
||||
: new SessionExpiredEvent(this, sessionId));
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.gemstone.gemfire.cache.Cache;
|
||||
import com.gemstone.gemfire.cache.DataPolicy;
|
||||
import com.gemstone.gemfire.cache.GemFireCache;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
import com.gemstone.gemfire.cache.RegionShortcut;
|
||||
@@ -122,6 +123,19 @@ 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}.
|
||||
*
|
||||
* @param region {@link Region} to evaluate.
|
||||
* @return a boolean value indicating whether the {@link Region} is a PROXY.
|
||||
* @see com.gemstone.gemfire.cache.DataPolicy
|
||||
* @see com.gemstone.gemfire.cache.Region
|
||||
*/
|
||||
public static boolean isProxy(Region<?, ?> region) {
|
||||
return DataPolicy.EMPTY.equals(region.getAttributes().getDataPolicy());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the peer {@link RegionShortcut} is a proxy-based shortcut. NOTE:
|
||||
* "proxy"-based Regions keep no local state.
|
||||
@@ -153,5 +167,4 @@ public abstract class GemFireUtils {
|
||||
public static String toRegionPath(String regionName) {
|
||||
return String.format("%1$s%2$s", Region.SEPARATOR, regionName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,8 +31,11 @@ import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.gemstone.gemfire.cache.AttributesMutator;
|
||||
import com.gemstone.gemfire.cache.DataPolicy;
|
||||
import com.gemstone.gemfire.cache.EntryEvent;
|
||||
import com.gemstone.gemfire.cache.Operation;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
import com.gemstone.gemfire.cache.RegionAttributes;
|
||||
|
||||
import edu.umd.cs.mtc.MultithreadedTestCase;
|
||||
import edu.umd.cs.mtc.TestFramework;
|
||||
@@ -84,7 +87,6 @@ import static org.mockito.Mockito.verify;
|
||||
*
|
||||
* @author John Blum
|
||||
* @since 1.1.0
|
||||
* @see org.junit.Rule
|
||||
* @see org.junit.Test
|
||||
* @see org.junit.runner.RunWith
|
||||
* @see org.mockito.Mock
|
||||
@@ -107,14 +109,14 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
|
||||
private AbstractGemFireOperationsSessionRepository sessionRepository;
|
||||
|
||||
@Mock
|
||||
private GemfireOperations mockGemfireOperations;
|
||||
private ExpiringSession mockExpiringSession;
|
||||
|
||||
@Mock
|
||||
private Log mockLog;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.sessionRepository = spy(new TestGemFireOperationsSessionRepository(this.mockGemfireOperations) {
|
||||
this.sessionRepository = spy(new TestGemFireOperationsSessionRepository(new GemfireTemplate()) {
|
||||
@Override
|
||||
Log newLogger() {
|
||||
return AbstractGemFireOperationsSessionRepositoryTest.this.mockLog;
|
||||
@@ -128,8 +130,31 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
|
||||
return set;
|
||||
}
|
||||
|
||||
protected ExpiringSession mockSession(String sessionId,
|
||||
long creationAndLastAccessedTime, int maxInactiveIntervalInSeconds) {
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <K, V> EntryEvent<K, V> mockEntryEvent(Operation operation, K key, V oldValue, V newValue) {
|
||||
EntryEvent<K, V> mockEntryEvent = mock(EntryEvent.class);
|
||||
|
||||
given(mockEntryEvent.getOperation()).willReturn(operation);
|
||||
given(mockEntryEvent.getKey()).willReturn(key);
|
||||
given(mockEntryEvent.getOldValue()).willReturn(oldValue);
|
||||
given(mockEntryEvent.getNewValue()).willReturn(newValue);
|
||||
|
||||
return mockEntryEvent;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <K, V> Region mockRegion(String name, DataPolicy dataPolicy) {
|
||||
Region<K, V> mockRegion = mock(Region.class, name);
|
||||
RegionAttributes<K, V> mockRegionAttributes = mock(RegionAttributes.class);
|
||||
|
||||
given(mockRegion.getAttributes()).willReturn(mockRegionAttributes);
|
||||
given(mockRegionAttributes.getDataPolicy()).willReturn(dataPolicy);
|
||||
|
||||
return mockRegion;
|
||||
}
|
||||
|
||||
protected ExpiringSession mockSession(String sessionId, long creationAndLastAccessedTime,
|
||||
int maxInactiveIntervalInSeconds) {
|
||||
|
||||
return mockSession(sessionId, creationAndLastAccessedTime, creationAndLastAccessedTime,
|
||||
maxInactiveIntervalInSeconds);
|
||||
@@ -148,6 +173,14 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
|
||||
return mockSession;
|
||||
}
|
||||
|
||||
protected AbstractGemFireOperationsSessionRepository withRegion(
|
||||
AbstractGemFireOperationsSessionRepository sessionRepository, Region region) {
|
||||
|
||||
((GemfireTemplate) sessionRepository.getTemplate()).setRegion(region);
|
||||
|
||||
return sessionRepository;
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructGemFireOperationsSessionRepositoryWithNullTemplate() {
|
||||
try {
|
||||
@@ -220,6 +253,105 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
|
||||
assertThat(this.sessionRepository.getMaxInactiveIntervalInSeconds()).isEqualTo(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isCreateWithCreateOperationReturnsTrue() {
|
||||
EntryEvent<Object, ExpiringSession> mockEvent =
|
||||
this.<Object, ExpiringSession>mockEntryEvent(Operation.CREATE, "123", null,
|
||||
this.mockExpiringSession);
|
||||
|
||||
withRegion(this.sessionRepository, mockRegion("Example", DataPolicy.EMPTY));
|
||||
|
||||
assertThat(this.sessionRepository.isCreate(mockEvent)).isTrue();
|
||||
|
||||
verify(mockEvent, times(1)).getOperation();
|
||||
verify(mockEvent, times(1)).getKey();
|
||||
verify(mockEvent, times(1)).getNewValue();
|
||||
verify(mockEvent, never()).getOldValue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isCreateWithCreateOperationAndNonProxyRegionReturnsTrue() {
|
||||
EntryEvent<Object, ExpiringSession> mockEvent =
|
||||
this.<Object, ExpiringSession>mockEntryEvent(Operation.CREATE, "123", null, null);
|
||||
|
||||
withRegion(this.sessionRepository, mockRegion("Example", DataPolicy.NORMAL));
|
||||
|
||||
this.sessionRepository.remember("123");
|
||||
|
||||
assertThat(this.sessionRepository.isCreate(mockEvent)).isTrue();
|
||||
|
||||
verify(mockEvent, times(1)).getOperation();
|
||||
verify(mockEvent, never()).getKey();
|
||||
verify(mockEvent, times(1)).getNewValue();
|
||||
verify(mockEvent, never()).getOldValue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isCreateWithLocalLoadCreateOperationReturnsFalse() {
|
||||
EntryEvent<Object, ExpiringSession> mockEvent =
|
||||
this.<Object, ExpiringSession>mockEntryEvent(Operation.LOCAL_LOAD_CREATE, "123", null,
|
||||
this.mockExpiringSession);
|
||||
|
||||
withRegion(this.sessionRepository, mockRegion("Example", DataPolicy.EMPTY));
|
||||
|
||||
assertThat(this.sessionRepository.isCreate(mockEvent)).isFalse();
|
||||
|
||||
verify(mockEvent, times(1)).getOperation();
|
||||
verify(mockEvent, never()).getKey();
|
||||
verify(mockEvent, never()).getNewValue();
|
||||
verify(mockEvent, never()).getOldValue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isCreateWithUpdateOperationReturnsFalse() {
|
||||
EntryEvent<Object, ExpiringSession> mockEvent =
|
||||
this.<Object, ExpiringSession>mockEntryEvent(Operation.UPDATE, "123", null,
|
||||
this.mockExpiringSession);
|
||||
|
||||
withRegion(this.sessionRepository, mockRegion("Example", DataPolicy.EMPTY));
|
||||
|
||||
assertThat(this.sessionRepository.isCreate(mockEvent)).isFalse();
|
||||
|
||||
verify(mockEvent, times(1)).getOperation();
|
||||
verify(mockEvent, never()).getKey();
|
||||
verify(mockEvent, never()).getNewValue();
|
||||
verify(mockEvent, never()).getOldValue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isCreateWithRememberedSessionIdReturnsFalse() {
|
||||
EntryEvent<Object, ExpiringSession> mockEvent =
|
||||
this.<Object, ExpiringSession>mockEntryEvent(Operation.CREATE, "123", null,
|
||||
this.mockExpiringSession);
|
||||
|
||||
withRegion(this.sessionRepository, mockRegion("Example", DataPolicy.EMPTY));
|
||||
|
||||
this.sessionRepository.remember("123");
|
||||
|
||||
assertThat(this.sessionRepository.isCreate(mockEvent)).isFalse();
|
||||
|
||||
verify(mockEvent, times(1)).getOperation();
|
||||
verify(mockEvent, times(1)).getKey();
|
||||
verify(mockEvent, never()).getNewValue();
|
||||
verify(mockEvent, never()).getOldValue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isCreateWithTombstoneReturnsFalse() {
|
||||
EntryEvent<Object, Object> mockEvent =
|
||||
this.<Object, Object>mockEntryEvent(Operation.CREATE, "123", null,
|
||||
new Tombstone());
|
||||
|
||||
withRegion(this.sessionRepository, mockRegion("Example", DataPolicy.EMPTY));
|
||||
|
||||
assertThat(this.sessionRepository.isCreate(mockEvent)).isFalse();
|
||||
|
||||
verify(mockEvent, times(1)).getOperation();
|
||||
verify(mockEvent, times(1)).getKey();
|
||||
verify(mockEvent, times(1)).getNewValue();
|
||||
verify(mockEvent, never()).getOldValue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void afterCreateWithSessionPublishesSessionCreatedEvent() {
|
||||
@@ -247,10 +379,10 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
|
||||
}
|
||||
}).given(mockApplicationEventPublisher).publishEvent(isA(ApplicationEvent.class));
|
||||
|
||||
EntryEvent<Object, ExpiringSession> mockEntryEvent = mock(EntryEvent.class);
|
||||
EntryEvent<Object, ExpiringSession> mockEntryEvent =
|
||||
this.<Object, ExpiringSession>mockEntryEvent(Operation.CREATE, sessionId, null, mockSession);
|
||||
|
||||
given(mockEntryEvent.getKey()).willReturn(sessionId);
|
||||
given(mockEntryEvent.getNewValue()).willReturn(mockSession);
|
||||
withRegion(this.sessionRepository, mockRegion("Example", DataPolicy.EMPTY));
|
||||
|
||||
this.sessionRepository.setApplicationEventPublisher(mockApplicationEventPublisher);
|
||||
this.sessionRepository.afterCreate(mockEntryEvent);
|
||||
@@ -258,7 +390,8 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
|
||||
assertThat(this.sessionRepository.getApplicationEventPublisher())
|
||||
.isSameAs(mockApplicationEventPublisher);
|
||||
|
||||
verify(mockEntryEvent, times(1)).getKey();
|
||||
verify(mockEntryEvent, times(1)).getOperation();
|
||||
verify(mockEntryEvent, times(2)).getKey();
|
||||
verify(mockEntryEvent, times(2)).getNewValue();
|
||||
verify(mockEntryEvent, never()).getOldValue();
|
||||
verify(mockSession, times(1)).getId();
|
||||
@@ -290,17 +423,18 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
|
||||
}
|
||||
}).given(mockApplicationEventPublisher).publishEvent(isA(ApplicationEvent.class));
|
||||
|
||||
EntryEvent<Object, ExpiringSession> mockEntryEvent = mock(EntryEvent.class);
|
||||
EntryEvent<Object, ExpiringSession> mockEntryEvent =
|
||||
this.<Object, ExpiringSession>mockEntryEvent(Operation.CREATE, sessionId, null, null);
|
||||
|
||||
given(mockEntryEvent.getKey()).willReturn(sessionId);
|
||||
given(mockEntryEvent.getNewValue()).willReturn(null);
|
||||
withRegion(this.sessionRepository, mockRegion("Example", DataPolicy.EMPTY));
|
||||
|
||||
this.sessionRepository.setApplicationEventPublisher(mockApplicationEventPublisher);
|
||||
this.sessionRepository.afterCreate(mockEntryEvent);
|
||||
|
||||
assertThat(this.sessionRepository.getApplicationEventPublisher()).isSameAs(mockApplicationEventPublisher);
|
||||
|
||||
verify(mockEntryEvent, times(1)).getKey();
|
||||
verify(mockEntryEvent, times(1)).getOperation();
|
||||
verify(mockEntryEvent, times(2)).getKey();
|
||||
verify(mockEntryEvent, times(2)).getNewValue();
|
||||
verify(mockEntryEvent, never()).getOldValue();
|
||||
verify(mockApplicationEventPublisher, times(1))
|
||||
@@ -308,24 +442,73 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void afterCreatedWithNonSessionTypeDoesNotPublishSessionCreatedEvent() {
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void afterCreateForDestroyOperationDoesNotPublishSessionCreatedEvent() {
|
||||
Region mockRegion = mockRegion("Example", DataPolicy.EMPTY);
|
||||
|
||||
TestGemFireOperationsSessionRepository sessionRepository =
|
||||
new TestGemFireOperationsSessionRepository(this.mockGemfireOperations) {
|
||||
new TestGemFireOperationsSessionRepository(new GemfireTemplate(mockRegion)) {
|
||||
@Override
|
||||
protected void handleCreated(String sessionId, ExpiringSession session) {
|
||||
fail("handleCreated(..) should not have been called");
|
||||
}
|
||||
};
|
||||
|
||||
EntryEvent<Object, ExpiringSession> mockEntryEvent =
|
||||
mockEntryEvent(Operation.DESTROY, null, null, null);
|
||||
|
||||
sessionRepository.afterCreate(mockEntryEvent);
|
||||
|
||||
verify(mockEntryEvent, times(1)).getOperation();
|
||||
verify(mockEntryEvent, never()).getKey();
|
||||
verify(mockEntryEvent, never()).getNewValue();
|
||||
verify(mockEntryEvent, never()).getOldValue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public void afterCreateForModificationDoesNotPublishSessionCreatedEvent() {
|
||||
Region mockRegion = mockRegion("Example", DataPolicy.EMPTY);
|
||||
|
||||
TestGemFireOperationsSessionRepository sessionRepository =
|
||||
new TestGemFireOperationsSessionRepository(new GemfireTemplate(mockRegion)) {
|
||||
@Override
|
||||
protected void handleCreated(String sessionId, ExpiringSession session) {
|
||||
fail("handleCreated(..) should not have been called");
|
||||
}
|
||||
};
|
||||
|
||||
EntryEvent<Object, ExpiringSession> mockEntryEvent =
|
||||
this.<Object, ExpiringSession>mockEntryEvent(Operation.CREATE, "123", null, null);
|
||||
|
||||
sessionRepository.remember("123");
|
||||
sessionRepository.afterCreate(mockEntryEvent);
|
||||
|
||||
verify(mockEntryEvent, times(1)).getOperation();
|
||||
verify(mockEntryEvent, times(1)).getKey();
|
||||
verify(mockEntryEvent, never()).getNewValue();
|
||||
verify(mockEntryEvent, never()).getOldValue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void afterCreateForNonSessionTypeDoesNotPublishSessionCreatedEvent() {
|
||||
Region mockRegion = mockRegion("Example", DataPolicy.EMPTY);
|
||||
|
||||
TestGemFireOperationsSessionRepository sessionRepository =
|
||||
new TestGemFireOperationsSessionRepository(new GemfireTemplate(mockRegion)) {
|
||||
@Override
|
||||
protected void handleCreated(String sessionId, ExpiringSession session) {
|
||||
fail("handleCreated(..) should not have been called");
|
||||
}
|
||||
};
|
||||
|
||||
EntryEvent mockEntryEvent = mock(EntryEvent.class);
|
||||
|
||||
given(mockEntryEvent.getKey()).willReturn("abc123");
|
||||
given(mockEntryEvent.getNewValue()).willReturn(new Tombstone());
|
||||
EntryEvent mockEntryEvent = mockEntryEvent(Operation.CREATE, null, null, new Tombstone());
|
||||
|
||||
sessionRepository.afterCreate((EntryEvent<Object, ExpiringSession>) mockEntryEvent);
|
||||
|
||||
verify(mockEntryEvent, never()).getKey();
|
||||
verify(mockEntryEvent, times(1)).getOperation();
|
||||
verify(mockEntryEvent, times(1)).getKey();
|
||||
verify(mockEntryEvent, times(1)).getNewValue();
|
||||
verify(mockEntryEvent, never()).getOldValue();
|
||||
}
|
||||
@@ -357,10 +540,8 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
|
||||
}
|
||||
}).given(mockApplicationEventPublisher).publishEvent(isA(ApplicationEvent.class));
|
||||
|
||||
EntryEvent<Object, ExpiringSession> mockEntryEvent = mock(EntryEvent.class);
|
||||
|
||||
given(mockEntryEvent.getKey()).willReturn(sessionId);
|
||||
given(mockEntryEvent.getOldValue()).willReturn(mockSession);
|
||||
EntryEvent<Object, ExpiringSession> mockEntryEvent =
|
||||
this.<Object, ExpiringSession>mockEntryEvent(Operation.DESTROY, sessionId, mockSession, null);
|
||||
|
||||
this.sessionRepository
|
||||
.setApplicationEventPublisher(mockApplicationEventPublisher);
|
||||
@@ -401,10 +582,8 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
|
||||
}
|
||||
}).given(mockApplicationEventPublisher).publishEvent(isA(ApplicationEvent.class));
|
||||
|
||||
EntryEvent<Object, ExpiringSession> mockEntryEvent = mock(EntryEvent.class);
|
||||
|
||||
given(mockEntryEvent.getKey()).willReturn(sessionId);
|
||||
given(mockEntryEvent.getOldValue()).willReturn(null);
|
||||
EntryEvent<Object, ExpiringSession> mockEntryEvent =
|
||||
this.<Object, ExpiringSession>mockEntryEvent(Operation.DESTROY, sessionId, null, null);
|
||||
|
||||
this.sessionRepository.setApplicationEventPublisher(mockApplicationEventPublisher);
|
||||
this.sessionRepository.afterDestroy(mockEntryEvent);
|
||||
@@ -442,10 +621,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
|
||||
}
|
||||
}).given(mockApplicationEventPublisher).publishEvent(isA(ApplicationEvent.class));
|
||||
|
||||
EntryEvent mockEntryEvent = mock(EntryEvent.class);
|
||||
|
||||
given(mockEntryEvent.getKey()).willReturn(sessionId);
|
||||
given(mockEntryEvent.getOldValue()).willReturn(new Tombstone());
|
||||
EntryEvent mockEntryEvent = mockEntryEvent(Operation.DESTROY, sessionId, new Tombstone(), null);
|
||||
|
||||
this.sessionRepository.setApplicationEventPublisher(mockApplicationEventPublisher);
|
||||
this.sessionRepository.afterDestroy((EntryEvent<Object, ExpiringSession>) mockEntryEvent);
|
||||
@@ -486,10 +662,8 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
|
||||
}
|
||||
}).given(mockApplicationEventPublisher).publishEvent(isA(ApplicationEvent.class));
|
||||
|
||||
EntryEvent<Object, ExpiringSession> mockEntryEvent = mock(EntryEvent.class);
|
||||
|
||||
given(mockEntryEvent.getKey()).willReturn(sessionId);
|
||||
given(mockEntryEvent.getOldValue()).willReturn(mockSession);
|
||||
EntryEvent<Object, ExpiringSession> mockEntryEvent =
|
||||
this.<Object, ExpiringSession>mockEntryEvent(Operation.INVALIDATE, sessionId, mockSession, null);
|
||||
|
||||
this.sessionRepository
|
||||
.setApplicationEventPublisher(mockApplicationEventPublisher);
|
||||
@@ -530,10 +704,8 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
|
||||
}
|
||||
}).given(mockApplicationEventPublisher).publishEvent(isA(ApplicationEvent.class));
|
||||
|
||||
EntryEvent<Object, ExpiringSession> mockEntryEvent = mock(EntryEvent.class);
|
||||
|
||||
given(mockEntryEvent.getKey()).willReturn(sessionId);
|
||||
given(mockEntryEvent.getOldValue()).willReturn(null);
|
||||
EntryEvent<Object, ExpiringSession> mockEntryEvent =
|
||||
this.<Object, ExpiringSession>mockEntryEvent(Operation.INVALIDATE, sessionId, null, null);
|
||||
|
||||
this.sessionRepository.setApplicationEventPublisher(mockApplicationEventPublisher);
|
||||
this.sessionRepository.afterInvalidate(mockEntryEvent);
|
||||
@@ -589,6 +761,69 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
|
||||
.publishEvent(isA(SessionExpiredEvent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sessionCreateCreateExpireRecreatePublishesSessionEventsCreateExpireCreate() {
|
||||
final String sessionId = "123456789";
|
||||
final ExpiringSession mockSession = mock(ExpiringSession.class);
|
||||
|
||||
given(mockSession.getId()).willReturn(sessionId);
|
||||
|
||||
ApplicationEventPublisher mockApplicationEventPublisher = mock(ApplicationEventPublisher.class);
|
||||
|
||||
willAnswer(new Answer<Void>() {
|
||||
int index = 0;
|
||||
|
||||
Class[] expectedSessionTypes = {
|
||||
SessionCreatedEvent.class, SessionExpiredEvent.class, SessionCreatedEvent.class
|
||||
};
|
||||
|
||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
||||
ApplicationEvent applicationEvent = invocation.getArgumentAt(0, ApplicationEvent.class);
|
||||
|
||||
assertThat(applicationEvent).isInstanceOf(this.expectedSessionTypes[this.index++]);
|
||||
|
||||
AbstractSessionEvent sessionEvent = (AbstractSessionEvent) applicationEvent;
|
||||
|
||||
assertThat(sessionEvent.getSource())
|
||||
.isEqualTo(AbstractGemFireOperationsSessionRepositoryTest.this.sessionRepository);
|
||||
assertThat(sessionEvent.<ExpiringSession>getSession()).isEqualTo(mockSession);
|
||||
assertThat(sessionEvent.getSessionId()).isEqualTo(sessionId);
|
||||
|
||||
return null;
|
||||
}
|
||||
}).given(mockApplicationEventPublisher).publishEvent(isA(ApplicationEvent.class));
|
||||
|
||||
EntryEvent<Object, ExpiringSession> mockCreateEvent =
|
||||
this.<Object, ExpiringSession>mockEntryEvent(Operation.CREATE, sessionId, null, mockSession);
|
||||
|
||||
EntryEvent<Object, ExpiringSession> mockExpireEvent =
|
||||
this.<Object, ExpiringSession>mockEntryEvent(Operation.INVALIDATE, sessionId, mockSession, null);
|
||||
|
||||
withRegion(this.sessionRepository, mockRegion("Example", DataPolicy.EMPTY));
|
||||
|
||||
this.sessionRepository.setApplicationEventPublisher(mockApplicationEventPublisher);
|
||||
this.sessionRepository.afterCreate(mockCreateEvent);
|
||||
this.sessionRepository.afterCreate(mockCreateEvent);
|
||||
this.sessionRepository.afterInvalidate(mockExpireEvent);
|
||||
this.sessionRepository.afterCreate(mockCreateEvent);
|
||||
|
||||
assertThat(this.sessionRepository.getApplicationEventPublisher()).isSameAs(mockApplicationEventPublisher);
|
||||
|
||||
verify(mockCreateEvent, times(3)).getOperation();
|
||||
verify(mockCreateEvent, times(5)).getKey();
|
||||
verify(mockCreateEvent, times(4)).getNewValue();
|
||||
verify(mockCreateEvent, never()).getOldValue();
|
||||
verify(mockExpireEvent, never()).getOperation();
|
||||
verify(mockExpireEvent, times(1)).getKey();
|
||||
verify(mockExpireEvent, never()).getNewValue();
|
||||
verify(mockExpireEvent, times(1)).getOldValue();
|
||||
verify(mockSession, times(3)).getId();
|
||||
verify(mockApplicationEventPublisher, times(2))
|
||||
.publishEvent(isA(SessionCreatedEvent.class));
|
||||
verify(mockApplicationEventPublisher, times(1))
|
||||
.publishEvent(isA(SessionExpiredEvent.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteSessionCallsDeleteSessionId() {
|
||||
Session mockSession = mock(Session.class);
|
||||
@@ -1650,9 +1885,9 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
|
||||
static class Tombstone {
|
||||
}
|
||||
|
||||
protected static class TestGemFireOperationsSessionRepository extends AbstractGemFireOperationsSessionRepository {
|
||||
static class TestGemFireOperationsSessionRepository extends AbstractGemFireOperationsSessionRepository {
|
||||
|
||||
protected TestGemFireOperationsSessionRepository(GemfireOperations gemfireOperations) {
|
||||
TestGemFireOperationsSessionRepository(GemfireOperations gemfireOperations) {
|
||||
super(gemfireOperations);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,13 +20,18 @@ import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.gemstone.gemfire.cache.Cache;
|
||||
import com.gemstone.gemfire.cache.DataPolicy;
|
||||
import com.gemstone.gemfire.cache.GemFireCache;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
import com.gemstone.gemfire.cache.RegionAttributes;
|
||||
import com.gemstone.gemfire.cache.RegionShortcut;
|
||||
import com.gemstone.gemfire.cache.client.ClientCache;
|
||||
import com.gemstone.gemfire.cache.client.ClientRegionShortcut;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
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.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
@@ -52,8 +57,7 @@ public class GemFireUtilsTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void closeNonNullCloseableObjectThrowingIOExceptionReturnsFalse()
|
||||
throws IOException {
|
||||
public void closeNonNullCloseableObjectThrowingIOExceptionReturnsFalse() throws IOException {
|
||||
Closeable mockCloseable = mock(Closeable.class);
|
||||
willThrow(new IOException("test")).given(mockCloseable).close();
|
||||
assertThat(GemFireUtils.close(mockCloseable)).isFalse();
|
||||
@@ -101,17 +105,14 @@ public class GemFireUtilsTest {
|
||||
assertThat(GemFireUtils.isLocal(ClientRegionShortcut.LOCAL_HEAP_LRU)).isTrue();
|
||||
assertThat(GemFireUtils.isLocal(ClientRegionShortcut.LOCAL_OVERFLOW)).isTrue();
|
||||
assertThat(GemFireUtils.isLocal(ClientRegionShortcut.LOCAL_PERSISTENT)).isTrue();
|
||||
assertThat(GemFireUtils.isLocal(ClientRegionShortcut.LOCAL_PERSISTENT_OVERFLOW))
|
||||
.isTrue();
|
||||
assertThat(GemFireUtils.isLocal(ClientRegionShortcut.LOCAL_PERSISTENT_OVERFLOW)).isTrue();
|
||||
}
|
||||
|
||||
@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();
|
||||
assertThat(GemFireUtils.isLocal(ClientRegionShortcut.CACHING_PROXY_HEAP_LRU)).isFalse();
|
||||
assertThat(GemFireUtils.isLocal(ClientRegionShortcut.CACHING_PROXY_OVERFLOW)).isFalse();
|
||||
assertThat(GemFireUtils.isLocal(ClientRegionShortcut.PROXY)).isFalse();
|
||||
}
|
||||
|
||||
@@ -123,56 +124,72 @@ public class GemFireUtilsTest {
|
||||
@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();
|
||||
assertThat(GemFireUtils.isProxy(ClientRegionShortcut.CACHING_PROXY_HEAP_LRU)).isFalse();
|
||||
assertThat(GemFireUtils.isProxy(ClientRegionShortcut.CACHING_PROXY_OVERFLOW)).isFalse();
|
||||
assertThat(GemFireUtils.isProxy(ClientRegionShortcut.LOCAL)).isFalse();
|
||||
assertThat(GemFireUtils.isProxy(ClientRegionShortcut.LOCAL_HEAP_LRU)).isFalse();
|
||||
assertThat(GemFireUtils.isProxy(ClientRegionShortcut.LOCAL_OVERFLOW)).isFalse();
|
||||
assertThat(GemFireUtils.isProxy(ClientRegionShortcut.LOCAL_PERSISTENT)).isFalse();
|
||||
assertThat(GemFireUtils.isProxy(ClientRegionShortcut.LOCAL_PERSISTENT_OVERFLOW))
|
||||
.isFalse();
|
||||
assertThat(GemFireUtils.isProxy(ClientRegionShortcut.LOCAL_PERSISTENT_OVERFLOW)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void regionShortcutIsProxy() {
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_PROXY)).isTrue();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_PROXY_REDUNDANT))
|
||||
.isTrue();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_PROXY_REDUNDANT)).isTrue();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.REPLICATE_PROXY)).isTrue();
|
||||
}
|
||||
|
||||
@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);
|
||||
|
||||
assertThat(GemFireUtils.isProxy(mockRegion)).isTrue();
|
||||
|
||||
verify(mockRegion, times(1)).getAttributes();
|
||||
verify(mockRegionAttributes, times(1)).getDataPolicy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void regionIsNotProxy() {
|
||||
Region mockRegion = mock(Region.class);
|
||||
RegionAttributes mockRegionAttributes = mock(RegionAttributes.class);
|
||||
|
||||
given(mockRegion.getAttributes()).willReturn(mockRegionAttributes);
|
||||
given(mockRegionAttributes.getDataPolicy()).willReturn(DataPolicy.NORMAL);
|
||||
|
||||
assertThat(GemFireUtils.isProxy(mockRegion)).isFalse();
|
||||
|
||||
verify(mockRegion, times(1)).getAttributes();
|
||||
verify(mockRegionAttributes, times(1)).getDataPolicy();
|
||||
}
|
||||
|
||||
@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();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.LOCAL_PERSISTENT)).isFalse();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.LOCAL_PERSISTENT_OVERFLOW))
|
||||
.isFalse();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.LOCAL_PERSISTENT_OVERFLOW)).isFalse();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.REPLICATE)).isFalse();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.REPLICATE_HEAP_LRU)).isFalse();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.REPLICATE_OVERFLOW)).isFalse();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.REPLICATE_PERSISTENT)).isFalse();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.REPLICATE_PERSISTENT_OVERFLOW))
|
||||
.isFalse();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.REPLICATE_PERSISTENT_OVERFLOW)).isFalse();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION)).isFalse();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_HEAP_LRU)).isFalse();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_OVERFLOW)).isFalse();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_PERSISTENT)).isFalse();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_PERSISTENT_OVERFLOW))
|
||||
.isFalse();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_PERSISTENT_OVERFLOW)).isFalse();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_REDUNDANT)).isFalse();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_REDUNDANT_HEAP_LRU))
|
||||
.isFalse();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_REDUNDANT_OVERFLOW))
|
||||
.isFalse();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_REDUNDANT_PERSISTENT))
|
||||
.isFalse();
|
||||
assertThat(GemFireUtils
|
||||
.isProxy(RegionShortcut.PARTITION_REDUNDANT_PERSISTENT_OVERFLOW))
|
||||
.isFalse();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_REDUNDANT_HEAP_LRU)).isFalse();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_REDUNDANT_OVERFLOW)).isFalse();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_REDUNDANT_PERSISTENT)).isFalse();
|
||||
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_REDUNDANT_PERSISTENT_OVERFLOW)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -183,5 +200,4 @@ public class GemFireUtilsTest {
|
||||
assertThat(GemFireUtils.toRegionPath("/")).isEqualTo("//");
|
||||
assertThat(GemFireUtils.toRegionPath("")).isEqualTo("/");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user