Improve GemFire SessionRepository, Session copy logic to avoid issues with delta propagation on updates

Fixes #gh-755

(cherry picked from commit dcc0c07981)
Signed-off-by: John Blum <jblum@pivotal.io>
This commit is contained in:
John Blum
2017-04-20 17:39:00 -07:00
parent 9b30726805
commit 25ded686ac
8 changed files with 571 additions and 217 deletions

View File

@@ -80,7 +80,7 @@ public abstract class AbstractGemFireIntegrationTests {
System.getProperty("spring.session.data.gemfire.log-file", "server.log");
protected static final String GEMFIRE_LOG_LEVEL =
System.getProperty("spring.session.data.gemfire.log-level", "warning");
System.getProperty("spring.session.data.gemfire.log-level", "error");
@Autowired
protected Cache gemfireCache;
@@ -255,7 +255,7 @@ public abstract class AbstractGemFireIntegrationTests {
/* (non-Javadoc) */
protected static int waitForProcessToStop(Process process, File directory, long duration) {
final long timeout = (System.currentTimeMillis() + duration);
long timeout = (System.currentTimeMillis() + duration);
try {
while (process.isAlive() && System.currentTimeMillis() < timeout) {
@@ -279,7 +279,7 @@ public abstract class AbstractGemFireIntegrationTests {
/* (non-Javadoc) */
@SuppressWarnings("all")
protected static boolean waitOnCondition(Condition condition, long duration) {
final long timeout = (System.currentTimeMillis() + duration);
long timeout = (System.currentTimeMillis() + duration);
try {
while (!condition.evaluate() && System.currentTimeMillis() < timeout) {

View File

@@ -31,6 +31,7 @@ import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.junit.After;
import org.junit.AfterClass;
@@ -59,7 +60,7 @@ import org.springframework.session.events.SessionDeletedEvent;
import org.springframework.session.events.SessionExpiredEvent;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.SocketUtils;
@@ -67,28 +68,30 @@ import org.springframework.util.SocketUtils;
import static org.assertj.core.api.Assertions.assertThat;
/**
* The ClientServerGemFireOperationsSessionRepositoryIntegrationTests class is a test
* suite of test cases testing the functionality of GemFire-backed Spring Sessions using a
* GemFire client-server topology.
* Integration tests to test the functionality of GemFire-backed Spring Sessions using
* the GemFire client-server topology.
*
* @author John Blum
* @since 1.1.0
* @see org.junit.Test
* @see org.junit.runner.RunWith
* @see org.springframework.context.ConfigurableApplicationContext
* @see org.springframework.session.ExpiringSession
* @see org.springframework.session.data.gemfire.AbstractGemFireIntegrationTests
* @see org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession
* @see org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration
* @see org.springframework.test.annotation.DirtiesContext
* @see org.springframework.test.context.ContextConfiguration
* @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner
* @see org.springframework.test.context.junit4.SpringRunner
* @see org.springframework.test.context.web.WebAppConfiguration
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.client.ClientCache
* @see org.apache.geode.cache.client.Pool
* @see org.apache.geode.cache.server.CacheServer
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ClientServerGemFireOperationsSessionRepositoryIntegrationTests.SpringSessionGemFireClientConfiguration.class)
@RunWith(SpringRunner.class)
@ContextConfiguration(classes =
ClientServerGemFireOperationsSessionRepositoryIntegrationTests.SpringSessionDataGemFireClientConfiguration.class)
@DirtiesContext
@WebAppConfiguration
public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests
@@ -109,24 +112,25 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests
@BeforeClass
public static void startGemFireServer() throws IOException {
final long t0 = System.currentTimeMillis();
long t0 = System.currentTimeMillis();
final int port = SocketUtils.findAvailableTcpPort();
int port = SocketUtils.findAvailableTcpPort();
System.err.printf("Starting a GemFire Server on [%1$s] listening on port [%2$d]%n",
SpringSessionGemFireServerConfiguration.SERVER_HOSTNAME, port);
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()));
String processWorkingDirectoryPathname =
String.format("gemfire-client-server-tests-%1$s", TIMESTAMP.format(new Date()));
processWorkingDirectory = createDirectory(processWorkingDirectoryPathname);
gemfireServer = run(SpringSessionGemFireServerConfiguration.class, processWorkingDirectory,
gemfireServer = run(SpringSessionDataGemFireServerConfiguration.class, processWorkingDirectory,
String.format("-Dspring.session.data.gemfire.port=%1$d", port));
assertThat(waitForCacheServerToStart(SpringSessionGemFireServerConfiguration.SERVER_HOSTNAME, port)).isTrue();
assertThat(waitForCacheServerToStart(SpringSessionDataGemFireServerConfiguration.SERVER_HOSTNAME, port))
.isTrue();
System.err.printf("GemFire Server [startup time = %1$d ms]%n", System.currentTimeMillis() - t0);
}
@@ -134,7 +138,7 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests
@AfterClass
public static void stopGemFireServerAndDeleteArtifacts() {
if (gemfireServer != null) {
gemfireServer.destroyForcibly();
gemfireServer.destroy();
System.err.printf("GemFire Server [exit code = %1$d]%n",
waitForProcessToStop(gemfireServer, processWorkingDirectory));
}
@@ -159,7 +163,7 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests
springSessionGemFireRegion.getAttributes();
assertThat(springSessionGemFireRegionAttributes).isNotNull();
assertThat(springSessionGemFireRegionAttributes.getDataPolicy()).isEqualTo(DataPolicy.EMPTY);
assertThat(springSessionGemFireRegionAttributes.getDataPolicy()).isEqualTo(DataPolicy.NORMAL);
}
@After
@@ -169,7 +173,7 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests
@Test
public void createSessionFiresSessionCreatedEvent() {
final long beforeOrAtCreationTime = System.currentTimeMillis();
long beforeOrAtCreationTime = System.currentTimeMillis();
ExpiringSession expectedSession = save(createSession());
@@ -179,12 +183,19 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests
ExpiringSession createdSession = sessionEvent.getSession();
assertThat(createdSession).isEqualTo(expectedSession);
assertThat(createdSession.getId()).isNotNull();
assertThat(createdSession.getId()).isEqualTo(expectedSession.getId());
assertThat(createdSession.getCreationTime()).isGreaterThanOrEqualTo(beforeOrAtCreationTime);
assertThat(createdSession.getLastAccessedTime()).isEqualTo(createdSession.getCreationTime());
assertThat(createdSession.getMaxInactiveIntervalInSeconds()).isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
createdSession.setAttribute("attrOne", 1);
assertThat(save(touch(createdSession)).getAttribute("attrOne")).isEqualTo(1);
sessionEvent = this.sessionEventListener.waitForSessionEvent(500);
assertThat(sessionEvent).isNull();
this.gemfireSessionRepository.delete(expectedSession.getId());
}
@@ -195,19 +206,13 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests
AbstractSessionEvent sessionEvent = this.sessionEventListener.waitForSessionEvent(500);
assertThat(sessionEvent).isInstanceOf(SessionCreatedEvent.class);
assertThat(sessionEvent.<ExpiringSession>getSession()).isEqualTo(expectedSession);
assertThat(sessionEvent.getSession()).isEqualTo(expectedSession);
assertThat(this.sessionEventListener.getSessionEvent()).isNull();
ExpiringSession savedSession = this.gemfireSessionRepository.getSession(expectedSession.getId());
assertThat(savedSession).isEqualTo(expectedSession);
// NOTE for some reason or another, performing a GemFire (Client)Cache
// Region.get(key)
// causes a Region CREATE event... o.O
// calling sessionEventListener.getSessionEvent() here to clear the event
this.sessionEventListener.getSessionEvent();
sessionEvent = this.sessionEventListener.waitForSessionEvent(
TimeUnit.SECONDS.toMillis(MAX_INACTIVE_INTERVAL_IN_SECONDS + 1));
@@ -241,11 +246,12 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests
}
@EnableGemFireHttpSession(regionName = SPRING_SESSION_GEMFIRE_REGION_NAME,
maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
static class SpringSessionGemFireClientConfiguration {
clientRegionShortcut = ClientRegionShortcut.CACHING_PROXY,
maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
static class SpringSessionDataGemFireClientConfiguration {
@Bean
static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
@@ -271,17 +277,14 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests
PoolFactoryBean poolFactory = new PoolFactoryBean();
poolFactory.setFreeConnectionTimeout(5000); // 5 seconds
poolFactory.setKeepAlive(false);
poolFactory.setMaxConnections(SpringSessionGemFireServerConfiguration.MAX_CONNECTIONS);
poolFactory.setPingInterval(TimeUnit.SECONDS.toMillis(5));
poolFactory.setReadTimeout(2000); // 2 seconds
poolFactory.setRetryAttempts(1);
poolFactory.setSubscriptionEnabled(true);
poolFactory.setThreadLocalConnections(false);
poolFactory.setServers(Collections.singletonList(new ConnectionEndpoint(
SpringSessionGemFireServerConfiguration.SERVER_HOSTNAME, port)));
SpringSessionDataGemFireServerConfiguration.SERVER_HOSTNAME, port)));
return poolFactory;
}
@@ -293,9 +296,9 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests
// used for debugging purposes
@SuppressWarnings("resource")
public static void main(final String[] args) {
ConfigurableApplicationContext applicationContext =
new AnnotationConfigApplicationContext(SpringSessionGemFireClientConfiguration.class);
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = new AnnotationConfigApplicationContext(
SpringSessionDataGemFireClientConfiguration.class);
applicationContext.registerShutdownHook();
@@ -310,30 +313,27 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests
@EnableGemFireHttpSession(regionName = SPRING_SESSION_GEMFIRE_REGION_NAME,
maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
static class SpringSessionGemFireServerConfiguration {
static class SpringSessionDataGemFireServerConfiguration {
static final int MAX_CONNECTIONS = 50;
static final String SERVER_HOSTNAME = "localhost";
@Bean
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
@Bean
Properties gemfireProperties() {
Properties gemfireProperties = new Properties();
gemfireProperties.setProperty("name", name());
gemfireProperties.setProperty("mcast-port", "0");
gemfireProperties.setProperty("log-file", "server.log");
gemfireProperties.setProperty("log-level", GEMFIRE_LOG_LEVEL);
return gemfireProperties;
}
String name() {
return SpringSessionGemFireServerConfiguration.class.getName();
return SpringSessionDataGemFireServerConfiguration.class.getName();
}
@Bean
@@ -352,20 +352,21 @@ public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests
CacheServerFactoryBean cacheServerFactory = new CacheServerFactoryBean();
cacheServerFactory.setCache(gemfireCache);
cacheServerFactory.setAutoStartup(true);
cacheServerFactory.setBindAddress(SERVER_HOSTNAME);
cacheServerFactory.setCache(gemfireCache);
cacheServerFactory.setMaxConnections(MAX_CONNECTIONS);
cacheServerFactory.setPort(port);
return cacheServerFactory;
}
@SuppressWarnings("resource")
public static void main(final String[] args) throws IOException {
public static void main(String[] args) throws IOException {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(SpringSessionGemFireServerConfiguration.class);
new AnnotationConfigApplicationContext(SpringSessionDataGemFireServerConfiguration.class);
context.registerShutdownHook();
writeProcessControlFile(WORKING_DIRECTORY);
}
}

View File

@@ -0,0 +1,285 @@
/*
* 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 org.apache.geode.cache.Cache;
import org.apache.geode.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.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.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;
/**
* Integration tests testing the addition/removal of HTTP Session Attributes
* and the proper persistence of the HTTP Session state in a GemFire cache
* across a client/server topology.
*
* @author John Blum
* @see org.junit.Test
* @see org.junit.runner.RunWith
* @see org.springframework.context.ConfigurableApplicationContext
* @see org.springframework.session.ExpiringSession
* @see org.springframework.session.data.gemfire.AbstractGemFireIntegrationTests
* @see org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession
* @see org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration
* @see org.springframework.test.context.ContextConfiguration
* @see org.springframework.test.context.junit4.SpringRunner
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.client.ClientCache
* @since 1.3.1
*/
@RunWith(SpringRunner.class)
@ContextConfiguration(classes =
ClientServerHttpSessionAttributesDeltaIntegrationTests.SpringSessionDataGemFireClientConfiguration.class)
public class ClientServerHttpSessionAttributesDeltaIntegrationTests 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;
@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 stopGemFireServerAndDeleteArtifacts() {
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 sessionCreationAndAccessIsSuccessful() {
ExpiringSession session = save(touch(createSession()));
assertThat(session).isNotNull();
assertThat(session.isExpired()).isFalse();
session.setAttribute("attrOne", 1);
session.setAttribute("attrTwo", 2);
save(touch(session));
ExpiringSession loadedSession = get(session.getId());
assertThat(loadedSession).isNotNull();
assertThat(loadedSession.isExpired()).isFalse();
assertThat(loadedSession).isNotSameAs(session);
assertThat(loadedSession.getId()).isEqualTo(session.getId());
assertThat(loadedSession.<Integer>getAttribute("attrOne")).isEqualTo(1);
assertThat(loadedSession.<Integer>getAttribute("attrTwo")).isEqualTo(2);
loadedSession.removeAttribute("attrTwo");
assertThat(loadedSession.getAttributeNames()).doesNotContain("attrTwo");
assertThat(loadedSession.getAttributeNames()).hasSize(1);
save(touch(loadedSession));
ExpiringSession reloadedSession = get(loadedSession.getId());
assertThat(reloadedSession).isNotNull();
assertThat(reloadedSession.isExpired()).isFalse();
assertThat(reloadedSession).isNotSameAs(loadedSession);
assertThat(reloadedSession.getId()).isEqualTo(loadedSession.getId());
assertThat(reloadedSession.getAttributeNames()).hasSize(1);
assertThat(reloadedSession.getAttributeNames()).doesNotContain("attrTwo");
assertThat(reloadedSession.<Integer>getAttribute("attrOne")).isEqualTo(1);
}
@EnableGemFireHttpSession(maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
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;
}
// 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 SpringSessionDataGemFireServerConfiguration.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);
}
}
}

View File

@@ -276,6 +276,19 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
handleExpired(event.getKey().toString(), toExpiringSession(event.getOldValue()));
}
/**
* Deletes the given {@link Session} from GemFire.
*
* @param session {@link Session} to delete.
* @return {@literal null}.
* @see org.springframework.session.Session
* @see #delete(String)
*/
protected ExpiringSession delete(Session session) {
delete(session.getId());
return null;
}
/**
* Causes Session created events to be published to the Spring application context.
*
@@ -344,10 +357,23 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
getApplicationEventPublisher().publishEvent(event);
}
catch (Throwable t) {
this.logger.error(String.format("error occurred publishing event (%1$s)", event), t);
this.logger.error(String.format("Error occurred publishing event [%s]", event), t);
}
}
/**
* Updates the {@link ExpiringSession#setLastAccessedTime(long)} property of the {@link ExpiringSession}.
*
* @param <T> {@link Class} sub-type of the {@link ExpiringSession}.
* @param expiringSession {@link ExpiringSession} to touch.
* @return the {@link ExpiringSession}.
* @see org.springframework.session.ExpiringSession#setLastAccessedTime(long)
*/
protected <T extends ExpiringSession> T touch(T expiringSession) {
expiringSession.setLastAccessedTime(System.currentTimeMillis());
return expiringSession;
}
/**
* GemFireSession is a GemFire representation model of a Spring {@link ExpiringSession}
* that stores and manages Session state information in GemFire. This class implements
@@ -407,11 +433,13 @@ public abstract class AbstractGemFireOperationsSessionRepository extends CacheLi
return session;
}
public static GemFireSession copy(ExpiringSession session) {
return new GemFireSession(session);
}
/* (non-Javadoc) */
public static GemFireSession from(ExpiringSession expiringSession) {
GemFireSession session = new GemFireSession(expiringSession);
session.setLastAccessedTime(System.currentTimeMillis());
return session;
public static GemFireSession from(ExpiringSession session) {
return (session instanceof GemFireSession ? (GemFireSession) session : copy(session));
}
/* (non-Javadoc) */

View File

@@ -122,15 +122,12 @@ public class GemFireOperationsSessionRepository extends AbstractGemFireOperation
ExpiringSession storedSession = getTemplate().get(sessionId);
if (storedSession != null) {
if (storedSession.isExpired()) {
delete(storedSession.getId());
}
else {
return GemFireSession.from(storedSession);
}
storedSession = storedSession.isExpired()
? delete(storedSession)
: touch(GemFireSession.from(storedSession));
}
return null;
return storedSession;
}
/**
@@ -141,7 +138,7 @@ public class GemFireOperationsSessionRepository extends AbstractGemFireOperation
* @see org.springframework.session.ExpiringSession
*/
public void save(ExpiringSession session) {
getTemplate().put(session.getId(), new GemFireSession(session));
getTemplate().put(session.getId(), GemFireSession.from(session));
}
/**

View File

@@ -101,7 +101,7 @@ import org.springframework.context.annotation.Import;
*
* @author John Blum
* @see org.springframework.session.config.annotation.web.http.EnableSpringHttpSession
* @see GemFireHttpSessionConfiguration
* @see org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration
* @since 1.1.0
*/
@Documented

View File

@@ -32,14 +32,13 @@ import java.util.concurrent.TimeUnit;
import edu.umd.cs.mtc.MultithreadedTestCase;
import edu.umd.cs.mtc.TestFramework;
import org.apache.commons.logging.Log;
import org.apache.geode.cache.AttributesMutator;
import org.apache.geode.cache.EntryEvent;
import org.apache.geode.cache.Region;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
@@ -70,14 +69,17 @@ import static org.mockito.ArgumentMatchers.same;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.willAnswer;
import static org.mockito.BDDMockito.willThrow;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
/**
* Unit tests for {@link AbstractGemFireOperationsSessionRepository} class.
* Unit tests for {@link AbstractGemFireOperationsSessionRepository}.
*
* @author John Blum
* @since 1.1.0
@@ -88,6 +90,7 @@ import static org.mockito.Mockito.verify;
* @see org.mockito.Mock
* @see org.mockito.Mockito
* @see org.mockito.junit.MockitoJUnitRunner
* @see org.mockito.Spy
* @see org.springframework.data.gemfire.GemfireOperations
* @see org.springframework.data.gemfire.GemfireTemplate
* @see org.springframework.session.ExpiringSession
@@ -103,8 +106,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
protected static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 600;
@Rule
public ExpectedException expectedException = ExpectedException.none();
private AbstractGemFireOperationsSessionRepository sessionRepository;
@Mock
private GemfireOperations mockGemfireOperations;
@@ -112,16 +114,14 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
@Mock
private Log mockLog;
private AbstractGemFireOperationsSessionRepository sessionRepository;
@Before
public void setup() {
this.sessionRepository = new TestGemFireOperationsSessionRepository(this.mockGemfireOperations) {
this.sessionRepository = spy(new TestGemFireOperationsSessionRepository(this.mockGemfireOperations) {
@Override
Log newLogger() {
return AbstractGemFireOperationsSessionRepositoryTest.this.mockLog;
}
};
});
}
protected static <E> Set<E> asSet(E... elements) {
@@ -133,12 +133,12 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
protected ExpiringSession mockSession(String sessionId, long creationAndLastAccessedTime,
int maxInactiveIntervalInSeconds) {
return mockSession(sessionId, creationAndLastAccessedTime,
creationAndLastAccessedTime, maxInactiveIntervalInSeconds);
return mockSession(sessionId, creationAndLastAccessedTime, creationAndLastAccessedTime,
maxInactiveIntervalInSeconds);
}
protected ExpiringSession mockSession(String sessionId, long creationTime,
long lastAccessedTime, int maxInactiveIntervalInSeconds) {
protected ExpiringSession mockSession(String sessionId, long creationTime, long lastAccessedTime,
int maxInactiveIntervalInSeconds) {
ExpiringSession mockSession = mock(ExpiringSession.class, sessionId);
@@ -150,12 +150,17 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
return mockSession;
}
@Test
@Test(expected = IllegalArgumentException.class)
public void constructGemFireOperationsSessionRepositoryWithNullTemplate() {
this.expectedException.expect(IllegalArgumentException.class);
this.expectedException.expectMessage("GemfireOperations must not be null");
try {
new TestGemFireOperationsSessionRepository(null);
}
catch (IllegalArgumentException expected) {
assertThat(expected).hasMessage("GemfireOperations must not be null");
assertThat(expected).hasNoCause();
new TestGemFireOperationsSessionRepository(null);
throw expected;
}
}
@Test
@@ -208,9 +213,9 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
assertThat(this.sessionRepository.getMaxInactiveIntervalInSeconds()).isEqualTo(Integer.MIN_VALUE);
this.sessionRepository.setMaxInactiveIntervalInSeconds(3600);
this.sessionRepository.setMaxInactiveIntervalInSeconds(1024000);
assertThat(this.sessionRepository.getMaxInactiveIntervalInSeconds()).isEqualTo(3600);
assertThat(this.sessionRepository.getMaxInactiveIntervalInSeconds()).isEqualTo(1024000);
this.sessionRepository.setMaxInactiveIntervalInSeconds(Integer.MAX_VALUE);
@@ -258,7 +263,8 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
verify(mockEntryEvent, times(2)).getNewValue();
verify(mockEntryEvent, never()).getOldValue();
verify(mockSession, times(1)).getId();
verify(mockApplicationEventPublisher, times(1)).publishEvent(isA(SessionCreatedEvent.class));
verify(mockApplicationEventPublisher, times(1))
.publishEvent(isA(SessionCreatedEvent.class));
}
@Test
@@ -298,7 +304,8 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
verify(mockEntryEvent, times(1)).getKey();
verify(mockEntryEvent, times(2)).getNewValue();
verify(mockEntryEvent, never()).getOldValue();
verify(mockApplicationEventPublisher, times(1)).publishEvent(isA(SessionCreatedEvent.class));
verify(mockApplicationEventPublisher, times(1))
.publishEvent(isA(SessionCreatedEvent.class));
}
@Test
@@ -364,7 +371,8 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
verify(mockEntryEvent, never()).getNewValue();
verify(mockEntryEvent, times(1)).getOldValue();
verify(mockSession, times(1)).getId();
verify(mockApplicationEventPublisher, times(1)).publishEvent(isA(SessionDestroyedEvent.class));
verify(mockApplicationEventPublisher, times(1))
.publishEvent(isA(SessionDestroyedEvent.class));
}
@Test
@@ -404,7 +412,8 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
verify(mockEntryEvent, times(1)).getKey();
verify(mockEntryEvent, never()).getNewValue();
verify(mockEntryEvent, times(1)).getOldValue();
verify(mockApplicationEventPublisher, times(1)).publishEvent(isA(SessionDestroyedEvent.class));
verify(mockApplicationEventPublisher, times(1))
.publishEvent(isA(SessionDestroyedEvent.class));
}
@Test
@@ -444,7 +453,8 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
verify(mockEntryEvent, times(1)).getKey();
verify(mockEntryEvent, never()).getNewValue();
verify(mockEntryEvent, times(1)).getOldValue();
verify(mockApplicationEventPublisher, times(1)).publishEvent(isA(SessionDestroyedEvent.class));
verify(mockApplicationEventPublisher, times(1))
.publishEvent(isA(SessionDestroyedEvent.class));
}
@Test
@@ -528,7 +538,8 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
verify(mockEntryEvent, times(1)).getKey();
verify(mockEntryEvent, never()).getNewValue();
verify(mockEntryEvent, times(1)).getOldValue();
verify(mockApplicationEventPublisher, times(1)).publishEvent(isA(SessionExpiredEvent.class));
verify(mockApplicationEventPublisher, times(1))
.publishEvent(isA(SessionExpiredEvent.class));
}
@Test
@@ -568,7 +579,20 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
verify(mockEntryEvent, times(1)).getKey();
verify(mockEntryEvent, never()).getNewValue();
verify(mockEntryEvent, times(1)).getOldValue();
verify(mockApplicationEventPublisher, times(1)).publishEvent(isA(SessionExpiredEvent.class));
verify(mockApplicationEventPublisher, times(1))
.publishEvent(isA(SessionExpiredEvent.class));
}
@Test
public void deleteSessionCallsDeleteSessionId() {
Session mockSession = mock(Session.class);
doNothing().when(this.sessionRepository).delete(anyString());
given(mockSession.getId()).willReturn("2");
assertThat(this.sessionRepository.delete(mockSession)).isNull();
verify(this.sessionRepository, times(1)).delete(eq("2"));
}
@Test
@@ -603,7 +627,8 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
assertThat(this.sessionRepository.getApplicationEventPublisher()).isSameAs(mockApplicationEventPublisher);
verify(mockSession, times(1)).getId();
verify(mockApplicationEventPublisher, times(1)).publishEvent(isA(SessionDeletedEvent.class));
verify(mockApplicationEventPublisher, times(1))
.publishEvent(isA(SessionDeletedEvent.class));
}
@Test
@@ -634,7 +659,8 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
assertThat(this.sessionRepository.getApplicationEventPublisher()).isSameAs(mockApplicationEventPublisher);
verify(mockApplicationEventPublisher, times(1)).publishEvent(isA(SessionDeletedEvent.class));
verify(mockApplicationEventPublisher, times(1))
.publishEvent(isA(SessionDeletedEvent.class));
}
@Test
@@ -652,13 +678,23 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
assertThat(this.sessionRepository.getApplicationEventPublisher()).isSameAs(mockApplicationEventPublisher);
verify(mockApplicationEventPublisher, times(1)).publishEvent(eq(mockApplicationEvent));
verify(this.mockLog, times(1)).error(eq(String.format("error occurred publishing event (%s)",
mockApplicationEvent)), isA(IllegalStateException.class));
verify(this.mockLog, times(1))
.error(eq(String.format("Error occurred publishing event [%s]", mockApplicationEvent)),
isA(IllegalStateException.class));
}
@Test
public void touchSetsLastAccessedTime() {
ExpiringSession mockSession = mock(ExpiringSession.class);
assertThat(this.sessionRepository.touch(mockSession)).isSameAs(mockSession);
verify(mockSession, times(1)).setLastAccessedTime(anyInt());
}
@Test
public void constructGemFireSessionWithDefaultInitialization() {
final long beforeOrAtCreationTime = System.currentTimeMillis();
long beforeOrAtCreationTime = System.currentTimeMillis();
AbstractGemFireOperationsSessionRepository.GemFireSession session =
new AbstractGemFireOperationsSessionRepository.GemFireSession();
@@ -668,12 +704,12 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
assertThat(session.getLastAccessedTime()).isGreaterThanOrEqualTo(beforeOrAtCreationTime);
assertThat(session.getMaxInactiveIntervalInSeconds()).isEqualTo(0);
assertThat(session.getAttributeNames()).isNotNull();
assertThat(session.getAttributeNames().isEmpty()).isTrue();
assertThat(session.getAttributeNames()).isEmpty();
}
@Test
public void constructGemFireSessionWithId() {
final long beforeOrAtCreationTime = System.currentTimeMillis();
long beforeOrAtCreationTime = System.currentTimeMillis();
AbstractGemFireOperationsSessionRepository.GemFireSession session =
new AbstractGemFireOperationsSessionRepository.GemFireSession("1");
@@ -683,16 +719,29 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
assertThat(session.getLastAccessedTime()).isGreaterThanOrEqualTo(beforeOrAtCreationTime);
assertThat(session.getMaxInactiveIntervalInSeconds()).isEqualTo(0);
assertThat(session.getAttributeNames()).isNotNull();
assertThat(session.getAttributeNames().isEmpty()).isTrue();
assertThat(session.getAttributeNames()).isEmpty();
}
@Test(expected = IllegalArgumentException.class)
public void constructGemFireSessionWithUnspecifiedId() {
try {
new AbstractGemFireOperationsSessionRepository.GemFireSession(" ");
}
catch (IllegalArgumentException expected) {
assertThat(expected).hasMessage("ID must be specified");
assertThat(expected).hasNoCause();
throw expected;
}
}
@Test
public void constructGemFireSessionWithSession() {
final long expectedCreationTime = 1L;
final long expectedLastAccessTime = 2L;
long expectedCreationTime = 1L;
long expectedLastAccessTime = 2L;
ExpiringSession mockSession = mockSession("2", expectedCreationTime, expectedLastAccessTime,
MAX_INACTIVE_INTERVAL_IN_SECONDS);
ExpiringSession mockSession =
mockSession("2", expectedCreationTime, expectedLastAccessTime, MAX_INACTIVE_INTERVAL_IN_SECONDS);
Set<String> expectedAttributedNames = asSet("attrOne", "attrTwo");
@@ -720,25 +769,22 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
verify(mockSession, times(1)).getAttribute(eq("attrTwo"));
}
@Test
@Test(expected = IllegalArgumentException.class)
public void constructGemFireSessionWithNullSession() {
this.expectedException.expect(IllegalArgumentException.class);
this.expectedException.expectMessage("The ExpiringSession to copy cannot be null");
try {
new AbstractGemFireOperationsSessionRepository.GemFireSession((ExpiringSession) null);
}
catch (IllegalArgumentException expected) {
assertThat(expected).hasMessage("The ExpiringSession to copy cannot be null");
assertThat(expected).hasNoCause();
new AbstractGemFireOperationsSessionRepository.GemFireSession((ExpiringSession) null);
}
@Test
public void constructGemFireSessionWithUnspecifiedId() {
this.expectedException.expect(IllegalArgumentException.class);
this.expectedException.expectMessage("ID must be specified");
new AbstractGemFireOperationsSessionRepository.GemFireSession(" ");
throw expected;
}
}
@Test
public void createNewGemFireSession() {
final long beforeOrAtCreationTime = System.currentTimeMillis();
long beforeOrAtCreationTime = System.currentTimeMillis();
AbstractGemFireOperationsSessionRepository.GemFireSession session =
AbstractGemFireOperationsSessionRepository.GemFireSession.create(120);
@@ -754,8 +800,8 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
@Test
public void fromExistingSession() {
final long expectedCreationTime = 1L;
final long expectedLastAccessedTime = 2L;
long expectedCreationTime = 1L;
long expectedLastAccessedTime = 2L;
ExpiringSession mockSession = mockSession("4", expectedCreationTime, expectedLastAccessedTime,
MAX_INACTIVE_INTERVAL_IN_SECONDS);
@@ -768,9 +814,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
assertThat(gemfireSession).isNotNull();
assertThat(gemfireSession.getId()).isEqualTo("4");
assertThat(gemfireSession.getCreationTime()).isEqualTo(expectedCreationTime);
assertThat(gemfireSession.getLastAccessedTime()).isNotEqualTo(expectedLastAccessedTime);
assertThat(gemfireSession.getLastAccessedTime()).isGreaterThanOrEqualTo(expectedCreationTime);
assertThat(gemfireSession.getLastAccessedTime()).isLessThanOrEqualTo(System.currentTimeMillis());
assertThat(gemfireSession.getLastAccessedTime()).isEqualTo(expectedLastAccessedTime);
assertThat(gemfireSession.getMaxInactiveIntervalInSeconds()).isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
assertThat(gemfireSession.getAttributeNames()).isNotNull();
assertThat(gemfireSession.getAttributeNames().isEmpty()).isTrue();
@@ -783,6 +827,17 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
verify(mockSession, never()).getAttribute(anyString());
}
@Test
public void fromExistingGemFireSessionIsGemFireSession() {
AbstractGemFireOperationsSessionRepository.GemFireSession gemfireSession =
AbstractGemFireOperationsSessionRepository.GemFireSession.create(300);
AbstractGemFireOperationsSessionRepository.GemFireSession fromGemFireSession =
AbstractGemFireOperationsSessionRepository.GemFireSession.from(gemfireSession);
assertThat(fromGemFireSession).isSameAs(gemfireSession);
}
@Test
public void setGetAndRemoveAttribute() {
AbstractGemFireOperationsSessionRepository.GemFireSession session =
@@ -918,17 +973,18 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
verify(mockDataOutput, times(1)).writeUTF(eq("1"));
verify(mockDataOutput, times(1)).writeLong(eq(session.getCreationTime()));
verify(mockDataOutput, times(1)).writeLong(eq(session.getLastAccessedTime()));
verify(mockDataOutput, times(1)).writeInt(eq(session.getMaxInactiveIntervalInSeconds()));
verify(mockDataOutput, times(1))
.writeInt(eq(session.getMaxInactiveIntervalInSeconds()));
verify(mockDataOutput, times(1)).writeInt(eq("jblum".length()));
verify(mockDataOutput, times(1)).writeUTF(eq(session.getPrincipalName()));
}
@Test
public void sessionFromData() throws Exception {
final long expectedCreationTime = 1L;
final long expectedLastAccessedTime = 2L;
long expectedCreationTime = 1L;
long expectedLastAccessedTime = 2L;
final int expectedMaxInactiveIntervalInSeconds = (int) TimeUnit.HOURS.toSeconds(6);
int expectedMaxInactiveIntervalInSeconds = (int) TimeUnit.HOURS.toSeconds(6);
final String expectedPrincipalName = "jblum";
@@ -958,8 +1014,8 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
session.fromData(mockDataInput);
Set<String> expectedAttributeNames = asSet("attrOne", "attrTwo",
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME);
Set<String> expectedAttributeNames =
asSet("attrOne", "attrTwo", FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME);
assertThat(session.getId()).isEqualTo("2");
assertThat(session.getCreationTime()).isEqualTo(expectedCreationTime);
@@ -1044,7 +1100,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
@Test
public void hasDeltaWhenSessionLastAccessedTimeIsUpdatedIsTrue() {
final long expectedLastAccessTime = 1L;
long expectedLastAccessTime = 1L;
AbstractGemFireOperationsSessionRepository.GemFireSession session =
new AbstractGemFireOperationsSessionRepository.GemFireSession();
@@ -1065,7 +1121,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
@Test
public void hasDeltaWhenSessionMaxInactiveIntervalInSecondsIsUpdatedIsTrue() {
final int expectedMaxInactiveIntervalInSeconds = 300;
int expectedMaxInactiveIntervalInSeconds = 300;
AbstractGemFireOperationsSessionRepository.GemFireSession session =
new AbstractGemFireOperationsSessionRepository.GemFireSession();
@@ -1146,7 +1202,7 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
@Test
public void sessionComparisons() {
final long twoHoursAgo = (System.currentTimeMillis() - TimeUnit.HOURS.toMillis(2));
long twoHoursAgo = (System.currentTimeMillis() - TimeUnit.HOURS.toMillis(2));
AbstractGemFireOperationsSessionRepository.GemFireSession sessionOne =
new AbstractGemFireOperationsSessionRepository.GemFireSession(
@@ -1528,8 +1584,9 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
assertThat(this.session.getMaxInactiveIntervalInSeconds()).isEqualTo(60);
assertThat(this.session.getPrincipalName()).isEqualTo("jblum");
assertThat(this.session.getAttributeNames().size()).isEqualTo(1);
assertThat(String.valueOf(this.session.getAttribute(
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME))).isEqualTo("jblum");
assertThat(String.valueOf(
this.session.getAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME)))
.isEqualTo("jblum");
this.session.setAttribute("tennis", "ping");
this.session.setAttribute("junk", "test");
@@ -1595,24 +1652,24 @@ public class AbstractGemFireOperationsSessionRepositoryTest {
super(gemfireOperations);
}
public Map<String, ExpiringSession> findByIndexNameAndIndexValue(String indexName, String indexValue) {
throw new UnsupportedOperationException("not implemented");
public ExpiringSession createSession() {
throw new UnsupportedOperationException("Not Implemented");
}
public ExpiringSession createSession() {
throw new UnsupportedOperationException("not implemented");
public Map<String, ExpiringSession> findByIndexNameAndIndexValue(String indexName, String indexValue) {
throw new UnsupportedOperationException("Not Implemented");
}
public ExpiringSession getSession(String id) {
throw new UnsupportedOperationException("not implemented");
throw new UnsupportedOperationException("Not Implemented");
}
public void save(ExpiringSession session) {
throw new UnsupportedOperationException("not implemented");
throw new UnsupportedOperationException("Not Implemented");
}
public void delete(String id) {
throw new UnsupportedOperationException("not implemented");
throw new UnsupportedOperationException("Not Implemented");
}
}
}

View File

@@ -24,6 +24,7 @@ import java.util.concurrent.TimeUnit;
import org.apache.geode.cache.AttributesMutator;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.query.SelectResults;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -65,6 +66,7 @@ import static org.mockito.Mockito.verify;
* @see org.mockito.Mock
* @see org.mockito.Mockito
* @see org.mockito.junit.MockitoJUnitRunner
* @see org.springframework.data.gemfire.GemfireOperations
* @see org.springframework.session.data.gemfire.GemFireOperationsSessionRepository
* @see org.apache.geode.cache.Region
*/
@@ -79,34 +81,28 @@ public class GemFireOperationsSessionRepositoryTest {
@Mock
private AttributesMutator<Object, ExpiringSession> mockAttributesMutator;
@Mock
private Region<Object, ExpiringSession> mockRegion;
@Mock
private GemfireOperationsAccessor mockTemplate;
private GemFireOperationsSessionRepository sessionRepository;
@Mock
private Region<Object, ExpiringSession> mockRegion;
@Before
public void setup() throws Exception {
given(this.mockRegion.getAttributesMutator()).willReturn(this.mockAttributesMutator);
given(this.mockRegion.getFullPath()).willReturn("/Example");
given(this.mockTemplate.<Object, ExpiringSession>getRegion()).willReturn(this.mockRegion);
this.sessionRepository = new GemFireOperationsSessionRepository(
this.mockTemplate);
this.sessionRepository
.setApplicationEventPublisher(this.mockApplicationEventPublisher);
this.sessionRepository
.setMaxInactiveIntervalInSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS);
this.sessionRepository = new GemFireOperationsSessionRepository(this.mockTemplate);
this.sessionRepository.setApplicationEventPublisher(this.mockApplicationEventPublisher);
this.sessionRepository.setMaxInactiveIntervalInSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS);
this.sessionRepository.afterPropertiesSet();
assertThat(this.sessionRepository.getApplicationEventPublisher())
.isSameAs(this.mockApplicationEventPublisher);
assertThat(this.sessionRepository.getFullyQualifiedRegionName())
.isEqualTo("/Example");
assertThat(this.sessionRepository.getMaxInactiveIntervalInSeconds())
.isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
assertThat(this.sessionRepository.getApplicationEventPublisher()).isSameAs(this.mockApplicationEventPublisher);
assertThat(this.sessionRepository.getFullyQualifiedRegionName()).isEqualTo("/Example");
assertThat(this.sessionRepository.getMaxInactiveIntervalInSeconds()).isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
}
@After
@@ -130,14 +126,13 @@ public class GemFireOperationsSessionRepositoryTest {
String indexName = "vip";
String indexValue = "rwinch";
String expectedQql = String.format(
GemFireOperationsSessionRepository.FIND_SESSIONS_BY_INDEX_NAME_VALUE_QUERY,
this.sessionRepository.getFullyQualifiedRegionName(), indexName);
String expectedQql = String.format(GemFireOperationsSessionRepository.FIND_SESSIONS_BY_INDEX_NAME_VALUE_QUERY,
this.sessionRepository.getFullyQualifiedRegionName(), indexName);
given(this.mockTemplate.find(eq(expectedQql), eq(indexValue))).willReturn(mockSelectResults);
Map<String, ExpiringSession> sessions =
this.sessionRepository.findByIndexNameAndIndexValue(indexName, indexValue);
this.sessionRepository.findByIndexNameAndIndexValue(indexName, indexValue);
assertThat(sessions).isNotNull();
assertThat(sessions.size()).isEqualTo(1);
@@ -161,22 +156,18 @@ public class GemFireOperationsSessionRepositoryTest {
SelectResults<Object> mockSelectResults = mock(SelectResults.class);
given(mockSelectResults.asList()).willReturn(
Arrays.<Object>asList(mockSessionOne, mockSessionTwo, mockSessionThree));
given(mockSelectResults.asList())
.willReturn(Arrays.<Object>asList(mockSessionOne, mockSessionTwo, mockSessionThree));
String principalName = "jblum";
String expectedOql = String.format(
GemFireOperationsSessionRepository.FIND_SESSIONS_BY_PRINCIPAL_NAME_QUERY,
this.sessionRepository.getFullyQualifiedRegionName());
String expectedOql = String.format(GemFireOperationsSessionRepository.FIND_SESSIONS_BY_PRINCIPAL_NAME_QUERY,
this.sessionRepository.getFullyQualifiedRegionName());
given(this.mockTemplate.find(eq(expectedOql), eq(principalName)))
.willReturn(mockSelectResults);
given(this.mockTemplate.find(eq(expectedOql), eq(principalName))).willReturn(mockSelectResults);
Map<String, ExpiringSession> sessions = this.sessionRepository
.findByIndexNameAndIndexValue(
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME,
principalName);
Map<String, ExpiringSession> sessions = this.sessionRepository.findByIndexNameAndIndexValue(
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, principalName);
assertThat(sessions).isNotNull();
assertThat(sessions.size()).isEqualTo(3);
@@ -200,15 +191,13 @@ public class GemFireOperationsSessionRepositoryTest {
String principalName = "jblum";
String expectedOql = String.format(
GemFireOperationsSessionRepository.FIND_SESSIONS_BY_PRINCIPAL_NAME_QUERY,
this.sessionRepository.getFullyQualifiedRegionName());
String expectedOql = String.format(GemFireOperationsSessionRepository.FIND_SESSIONS_BY_PRINCIPAL_NAME_QUERY,
this.sessionRepository.getFullyQualifiedRegionName());
given(this.mockTemplate.find(eq(expectedOql), eq(principalName)))
.willReturn(mockSelectResults);
given(this.mockTemplate.find(eq(expectedOql), eq(principalName))).willReturn(mockSelectResults);
Map<String, ExpiringSession> sessions = this.sessionRepository.findByIndexNameAndIndexValue(
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, principalName);
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, principalName);
assertThat(sessions).isNotNull();
assertThat(sessions.isEmpty()).isTrue();
@@ -219,12 +208,11 @@ public class GemFireOperationsSessionRepositoryTest {
@Test
public void prepareQueryReturnsPrincipalNameOql() {
String actualQql = this.sessionRepository.prepareQuery(
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME);
String actualQql =
this.sessionRepository.prepareQuery(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME);
String expectedOql = String.format(
GemFireOperationsSessionRepository.FIND_SESSIONS_BY_PRINCIPAL_NAME_QUERY,
this.sessionRepository.getFullyQualifiedRegionName());
String expectedOql = String.format(GemFireOperationsSessionRepository.FIND_SESSIONS_BY_PRINCIPAL_NAME_QUERY,
this.sessionRepository.getFullyQualifiedRegionName());
assertThat(actualQql).isEqualTo(expectedOql);
}
@@ -233,21 +221,19 @@ public class GemFireOperationsSessionRepositoryTest {
public void prepareQueryReturnsIndexNameValueOql() {
String attributeName = "testAttributeName";
String actualOql = this.sessionRepository.prepareQuery(attributeName);
String expectedOql = String.format(
GemFireOperationsSessionRepository.FIND_SESSIONS_BY_INDEX_NAME_VALUE_QUERY,
this.sessionRepository.getFullyQualifiedRegionName(), attributeName);
String expectedOql = String.format(GemFireOperationsSessionRepository.FIND_SESSIONS_BY_INDEX_NAME_VALUE_QUERY,
this.sessionRepository.getFullyQualifiedRegionName(), attributeName);
assertThat(actualOql).isEqualTo(expectedOql);
}
@Test
public void createProperlyInitializedSession() {
final long beforeOrAtCreationTime = System.currentTimeMillis();
long beforeOrAtCreationTime = System.currentTimeMillis();
ExpiringSession session = this.sessionRepository.createSession();
assertThat(session).isInstanceOf(
AbstractGemFireOperationsSessionRepository.GemFireSession.class);
assertThat(session).isInstanceOf(AbstractGemFireOperationsSessionRepository.GemFireSession.class);
assertThat(session.getId()).isNotNull();
assertThat(session.getAttributeNames().isEmpty()).isTrue();
assertThat(session.getCreationTime()).isGreaterThanOrEqualTo(beforeOrAtCreationTime);
@@ -274,8 +260,8 @@ public class GemFireOperationsSessionRepositoryTest {
AbstractSessionEvent sessionEvent = (AbstractSessionEvent) applicationEvent;
assertThat(sessionEvent.getSource()).isSameAs(
GemFireOperationsSessionRepositoryTest.this.sessionRepository);
assertThat(sessionEvent.getSource())
.isSameAs(GemFireOperationsSessionRepositoryTest.this.sessionRepository);
assertThat(sessionEvent.getSession()).isSameAs(mockSession);
assertThat(sessionEvent.getSessionId()).isEqualTo(expectedSessionId);
@@ -289,16 +275,16 @@ public class GemFireOperationsSessionRepositoryTest {
verify(this.mockTemplate, times(1)).remove(eq(expectedSessionId));
verify(mockSession, times(1)).isExpired();
verify(mockSession, times(2)).getId();
verify(this.mockApplicationEventPublisher, times(1)).publishEvent(isA(SessionDeletedEvent.class));
verify(this.mockApplicationEventPublisher, times(1))
.publishEvent(isA(SessionDeletedEvent.class));
}
@Test
public void getSessionFindsMatchingNonExpiredSessionById() {
final String expectedId = "1";
String expectedId = "1";
final long expectedCreationTime = System.currentTimeMillis();
final long currentLastAccessedTime = (expectedCreationTime
+ TimeUnit.MINUTES.toMillis(5));
long expectedCreationTime = System.currentTimeMillis();
long currentLastAccessedTime = (expectedCreationTime + TimeUnit.MINUTES.toMillis(5));
ExpiringSession mockSession = mock(ExpiringSession.class);
@@ -340,8 +326,7 @@ public class GemFireOperationsSessionRepositoryTest {
final String expectedSessionId = "1";
final long expectedCreationTime = System.currentTimeMillis();
final long expectedLastAccessTime = (expectedCreationTime
+ TimeUnit.MINUTES.toMillis(5));
final long expectedLastAccessTime = (expectedCreationTime + TimeUnit.MINUTES.toMillis(5));
ExpiringSession mockSession = mock(ExpiringSession.class);
@@ -353,22 +338,22 @@ public class GemFireOperationsSessionRepositoryTest {
given(mockSession.getAttributeNames()).willReturn(Collections.<String>emptySet());
given(this.mockTemplate.put(eq(expectedSessionId),
isA(AbstractGemFireOperationsSessionRepository.GemFireSession.class)))
.willAnswer(new Answer<ExpiringSession>() {
public ExpiringSession answer(InvocationOnMock invocation) throws Throwable {
ExpiringSession session = invocation.getArgument(1);
isA(AbstractGemFireOperationsSessionRepository.GemFireSession.class)))
.willAnswer(new Answer<ExpiringSession>() {
public ExpiringSession answer(InvocationOnMock invocation) throws Throwable {
ExpiringSession session = invocation.getArgument(1);
assertThat(session).isNotNull();
assertThat(session.getId()).isEqualTo(expectedSessionId);
assertThat(session.getCreationTime()).isEqualTo(expectedCreationTime);
assertThat(session.getLastAccessedTime()).isEqualTo(expectedLastAccessTime);
assertThat(session.getMaxInactiveIntervalInSeconds())
.isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
assertThat(session.getAttributeNames().isEmpty()).isTrue();
assertThat(session).isNotNull();
assertThat(session.getId()).isEqualTo(expectedSessionId);
assertThat(session.getCreationTime()).isEqualTo(expectedCreationTime);
assertThat(session.getLastAccessedTime()).isEqualTo(expectedLastAccessTime);
assertThat(session.getMaxInactiveIntervalInSeconds())
.isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
assertThat(session.getAttributeNames().isEmpty()).isTrue();
return null;
}
});
return null;
}
});
this.sessionRepository.save(mockSession);
@@ -378,7 +363,7 @@ public class GemFireOperationsSessionRepositoryTest {
verify(mockSession, times(1)).getMaxInactiveIntervalInSeconds();
verify(mockSession, times(1)).getAttributeNames();
verify(this.mockTemplate, times(1)).put(eq(expectedSessionId),
isA(AbstractGemFireOperationsSessionRepository.GemFireSession.class));
isA(AbstractGemFireOperationsSessionRepository.GemFireSession.class));
}
@Test
@@ -398,8 +383,8 @@ public class GemFireOperationsSessionRepositoryTest {
AbstractSessionEvent sessionEvent = (AbstractSessionEvent) applicationEvent;
assertThat(sessionEvent.getSource()).isSameAs(
GemFireOperationsSessionRepositoryTest.this.sessionRepository);
assertThat(sessionEvent.getSource())
.isSameAs(GemFireOperationsSessionRepositoryTest.this.sessionRepository);
assertThat(sessionEvent.getSession()).isSameAs(mockSession);
assertThat(sessionEvent.getSessionId()).isEqualTo(expectedSessionId);
@@ -411,7 +396,8 @@ public class GemFireOperationsSessionRepositoryTest {
verify(mockSession, times(1)).getId();
verify(this.mockTemplate, times(1)).remove(eq(expectedSessionId));
verify(this.mockApplicationEventPublisher, times(1)).publishEvent(isA(SessionDeletedEvent.class));
verify(this.mockApplicationEventPublisher, times(1))
.publishEvent(isA(SessionDeletedEvent.class));
}
@Test
@@ -428,20 +414,20 @@ public class GemFireOperationsSessionRepositoryTest {
AbstractSessionEvent sessionEvent = (AbstractSessionEvent) applicationEvent;
assertThat(sessionEvent.getSource()).isSameAs(
GemFireOperationsSessionRepositoryTest.this.sessionRepository);
assertThat(sessionEvent.getSource()).
isSameAs(GemFireOperationsSessionRepositoryTest.this.sessionRepository);
assertThat(sessionEvent.getSession()).isNull();
assertThat(sessionEvent.getSessionId()).isEqualTo(expectedSessionId);
return null;
}
}).given(this.mockApplicationEventPublisher)
.publishEvent(isA(SessionDeletedEvent.class));
}).given(this.mockApplicationEventPublisher).publishEvent(isA(SessionDeletedEvent.class));
this.sessionRepository.delete(expectedSessionId);
verify(this.mockTemplate, times(1)).remove(eq(expectedSessionId));
verify(this.mockApplicationEventPublisher, times(1)).publishEvent(isA(SessionDeletedEvent.class));
verify(this.mockApplicationEventPublisher, times(1))
.publishEvent(isA(SessionDeletedEvent.class));
}
protected abstract class GemfireOperationsAccessor extends GemfireAccessor