diff --git a/spring-session/src/integration-test/java/org/springframework/session/data/gemfire/AbstractGemFireIntegrationTests.java b/spring-session/src/integration-test/java/org/springframework/session/data/gemfire/AbstractGemFireIntegrationTests.java index 2a3266df..342362f7 100644 --- a/spring-session/src/integration-test/java/org/springframework/session/data/gemfire/AbstractGemFireIntegrationTests.java +++ b/spring-session/src/integration-test/java/org/springframework/session/data/gemfire/AbstractGemFireIntegrationTests.java @@ -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) { diff --git a/spring-session/src/integration-test/java/org/springframework/session/data/gemfire/ClientServerGemFireOperationsSessionRepositoryIntegrationTests.java b/spring-session/src/integration-test/java/org/springframework/session/data/gemfire/ClientServerGemFireOperationsSessionRepositoryIntegrationTests.java index 0cbf2f07..82e35bf1 100644 --- a/spring-session/src/integration-test/java/org/springframework/session/data/gemfire/ClientServerGemFireOperationsSessionRepositoryIntegrationTests.java +++ b/spring-session/src/integration-test/java/org/springframework/session/data/gemfire/ClientServerGemFireOperationsSessionRepositoryIntegrationTests.java @@ -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.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); } } diff --git a/spring-session/src/integration-test/java/org/springframework/session/data/gemfire/ClientServerHttpSessionAttributesDeltaIntegrationTests.java b/spring-session/src/integration-test/java/org/springframework/session/data/gemfire/ClientServerHttpSessionAttributesDeltaIntegrationTests.java new file mode 100644 index 00000000..ceaaa922 --- /dev/null +++ b/spring-session/src/integration-test/java/org/springframework/session/data/gemfire/ClientServerHttpSessionAttributesDeltaIntegrationTests.java @@ -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.getAttribute("attrOne")).isEqualTo(1); + assertThat(loadedSession.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.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); + } + } +} diff --git a/spring-session/src/main/java/org/springframework/session/data/gemfire/AbstractGemFireOperationsSessionRepository.java b/spring-session/src/main/java/org/springframework/session/data/gemfire/AbstractGemFireOperationsSessionRepository.java index 24485a29..3547bf32 100644 --- a/spring-session/src/main/java/org/springframework/session/data/gemfire/AbstractGemFireOperationsSessionRepository.java +++ b/spring-session/src/main/java/org/springframework/session/data/gemfire/AbstractGemFireOperationsSessionRepository.java @@ -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 {@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 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) */ diff --git a/spring-session/src/main/java/org/springframework/session/data/gemfire/GemFireOperationsSessionRepository.java b/spring-session/src/main/java/org/springframework/session/data/gemfire/GemFireOperationsSessionRepository.java index 794c9744..7fedc180 100644 --- a/spring-session/src/main/java/org/springframework/session/data/gemfire/GemFireOperationsSessionRepository.java +++ b/spring-session/src/main/java/org/springframework/session/data/gemfire/GemFireOperationsSessionRepository.java @@ -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)); } /** diff --git a/spring-session/src/main/java/org/springframework/session/data/gemfire/config/annotation/web/http/EnableGemFireHttpSession.java b/spring-session/src/main/java/org/springframework/session/data/gemfire/config/annotation/web/http/EnableGemFireHttpSession.java index c04d3ed7..bdbb8e64 100644 --- a/spring-session/src/main/java/org/springframework/session/data/gemfire/config/annotation/web/http/EnableGemFireHttpSession.java +++ b/spring-session/src/main/java/org/springframework/session/data/gemfire/config/annotation/web/http/EnableGemFireHttpSession.java @@ -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 diff --git a/spring-session/src/test/java/org/springframework/session/data/gemfire/AbstractGemFireOperationsSessionRepositoryTest.java b/spring-session/src/test/java/org/springframework/session/data/gemfire/AbstractGemFireOperationsSessionRepositoryTest.java index a961a307..82fcdc29 100644 --- a/spring-session/src/test/java/org/springframework/session/data/gemfire/AbstractGemFireOperationsSessionRepositoryTest.java +++ b/spring-session/src/test/java/org/springframework/session/data/gemfire/AbstractGemFireOperationsSessionRepositoryTest.java @@ -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 Set 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 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 expectedAttributeNames = asSet("attrOne", "attrTwo", - FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME); + Set 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 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 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"); } } } diff --git a/spring-session/src/test/java/org/springframework/session/data/gemfire/GemFireOperationsSessionRepositoryTest.java b/spring-session/src/test/java/org/springframework/session/data/gemfire/GemFireOperationsSessionRepositoryTest.java index aa46115b..b2101830 100644 --- a/spring-session/src/test/java/org/springframework/session/data/gemfire/GemFireOperationsSessionRepositoryTest.java +++ b/spring-session/src/test/java/org/springframework/session/data/gemfire/GemFireOperationsSessionRepositoryTest.java @@ -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 mockAttributesMutator; - @Mock - private Region mockRegion; - @Mock private GemfireOperationsAccessor mockTemplate; private GemFireOperationsSessionRepository sessionRepository; + @Mock + private Region mockRegion; + @Before public void setup() throws Exception { given(this.mockRegion.getAttributesMutator()).willReturn(this.mockAttributesMutator); given(this.mockRegion.getFullPath()).willReturn("/Example"); given(this.mockTemplate.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 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 mockSelectResults = mock(SelectResults.class); - given(mockSelectResults.asList()).willReturn( - Arrays.asList(mockSessionOne, mockSessionTwo, mockSessionThree)); + given(mockSelectResults.asList()) + .willReturn(Arrays.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 sessions = this.sessionRepository - .findByIndexNameAndIndexValue( - FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, - principalName); + Map 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 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.emptySet()); given(this.mockTemplate.put(eq(expectedSessionId), - isA(AbstractGemFireOperationsSessionRepository.GemFireSession.class))) - .willAnswer(new Answer() { - public ExpiringSession answer(InvocationOnMock invocation) throws Throwable { - ExpiringSession session = invocation.getArgument(1); + isA(AbstractGemFireOperationsSessionRepository.GemFireSession.class))) + .willAnswer(new Answer() { + 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