Add tests for all classes in the new Serialization framework.

Resolves Issue #2.
This commit is contained in:
John Blum
2017-09-28 13:03:58 -07:00
parent ed8de1315a
commit 7a9f3c87a0
24 changed files with 1679 additions and 257 deletions

View File

@@ -25,16 +25,12 @@ 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.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.client.ClientCache;
import org.springframework.beans.factory.annotation.Value;
@@ -42,13 +38,14 @@ 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.config.annotation.CacheServerApplication;
import org.springframework.data.gemfire.config.annotation.CacheServerConfigurer;
import org.springframework.data.gemfire.config.annotation.ClientCacheApplication;
import org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer;
import org.springframework.data.gemfire.support.ConnectionEndpoint;
import org.springframework.session.Session;
import org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession;
import org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.FileSystemUtils;
@@ -169,7 +166,9 @@ public class ClientServerHttpSessionAttributesDeltaIntegrationTests extends Abst
assertThat(reloadedSession.<Integer>getAttribute("attrOne")).isEqualTo(1);
}
@EnableGemFireHttpSession
@ClientCacheApplication
@EnableGemFireHttpSession(poolName = "DEFAULT", sessionSerializerBeanName =
GemFireHttpSessionConfiguration.SESSION_DATA_SERIALIZER_BEAN_NAME)
@SuppressWarnings("unused")
static class SpringSessionDataGemFireClientConfiguration {
@@ -178,42 +177,16 @@ public class ClientServerHttpSessionAttributesDeltaIntegrationTests extends Abst
return new PropertySourcesPlaceholderConfigurer();
}
Properties gemfireProperties() {
@Bean ClientCacheConfigurer clientCachePoolPortConfigurer(
@Value("${spring.session.data.gemfire.port:" + DEFAULT_GEMFIRE_SERVER_PORT + "}") int port) {
Properties gemfireProperties = new Properties();
return (beanName, clientCacheFactoryBean) -> {
gemfireProperties.setProperty("log-level", GEMFIRE_LOG_LEVEL);
clientCacheFactoryBean.setServers(Collections.singleton(
new ConnectionEndpoint(SpringSessionDataGemFireServerConfiguration.SERVER_HOSTNAME, port)));
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;
clientCacheFactoryBean.setSubscriptionEnabled(true);
};
}
// used for debugging purposes
@@ -234,7 +207,9 @@ public class ClientServerHttpSessionAttributesDeltaIntegrationTests extends Abst
}
}
@EnableGemFireHttpSession(maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
@CacheServerApplication(name = "ClientServerHttpSessionAttributesDeltaIntegrationTests")
@EnableGemFireHttpSession(maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS,
sessionSerializerBeanName = GemFireHttpSessionConfiguration.SESSION_DATA_SERIALIZER_BEAN_NAME)
@SuppressWarnings("unused")
static class SpringSessionDataGemFireServerConfiguration {
@@ -245,53 +220,24 @@ public class ClientServerHttpSessionAttributesDeltaIntegrationTests extends Abst
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 ClientServerHttpSessionAttributesDeltaIntegrationTests.class.getName();
}
@Bean
CacheFactoryBean gemfireCache() {
CacheFactoryBean gemfireCache = new CacheFactoryBean();
gemfireCache.setClose(true);
gemfireCache.setProperties(gemfireProperties());
return gemfireCache;
}
@Bean
CacheServerFactoryBean gemfireCacheServer(GemFireCache gemfireCache,
CacheServerConfigurer cacheServerPortConfigurer(
@Value("${spring.session.data.gemfire.port:" + DEFAULT_GEMFIRE_SERVER_PORT + "}") int port) {
CacheServerFactoryBean cacheServerFactory = new CacheServerFactoryBean();
cacheServerFactory.setCache((Cache) gemfireCache);
cacheServerFactory.setAutoStartup(true);
cacheServerFactory.setBindAddress(SERVER_HOSTNAME);
cacheServerFactory.setPort(port);
return cacheServerFactory;
return (beanName, cacheServerFactoryBean) -> {
cacheServerFactoryBean.setAutoStartup(true);
cacheServerFactoryBean.setBindAddress(SERVER_HOSTNAME);
cacheServerFactoryBean.setPort(port);
};
}
@SuppressWarnings("resource")
public static void main(String[] args) throws IOException {
AnnotationConfigApplicationContext context =
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(SpringSessionDataGemFireServerConfiguration.class);
context.registerShutdownHook();
applicationContext.registerShutdownHook();
writeProcessControlFile(WORKING_DIRECTORY);
}

View File

@@ -141,7 +141,8 @@ public class ClientServerProxyRegionSessionOperationsIntegrationTests extends Ab
assertThat(loadedSession).isNotNull();
assertThat(loadedSession.getId()).isEqualTo(session.getId());
assertThat(loadedSession.getCreationTime()).isEqualTo(session.getCreationTime());
assertThat(loadedSession.getLastAccessedTime().compareTo(session.getLastAccessedTime())).isGreaterThanOrEqualTo(0);
assertThat(loadedSession.getLastAccessedTime().compareTo(session.getLastAccessedTime()))
.isGreaterThanOrEqualTo(0);
sessionEvent = this.sessionEventListener.waitForSessionEvent(500);

View File

@@ -0,0 +1,105 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire.serialization.data.support;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import java.io.DataInput;
import java.io.DataOutput;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.gemfire.support.GemfireBeanFactoryLocator;
import org.springframework.session.Session;
import org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.DeltaCapableGemFireSession;
import org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.DeltaCapableGemFireSessionAttributes;
import org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSession;
import org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes;
import org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration;
import org.springframework.session.data.gemfire.serialization.SessionSerializer;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
/**
* Integration tests for {@link DataSerializerSessionSerializerAdapter}.
*
* @author John Blum
* @see java.io.DataInput
* @see java.io.DataOutput
* @see org.junit.Test
* @see org.mockito.Mockito
* @see org.springframework.context.annotation.Bean
* @see org.springframework.context.annotation.Configuration
* @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator
* @see org.springframework.session.Session
* @see org.springframework.session.data.gemfire.serialization.SessionSerializer
* @see org.springframework.session.data.gemfire.serialization.data.support.DataSerializerSessionSerializerAdapter
* @see org.springframework.test.context.ContextConfiguration
* @see org.springframework.test.context.junit4.SpringRunner
* @since 2.0.0
*/
@RunWith(SpringRunner.class)
@ContextConfiguration
public class DataSerializerSessionSerializerAdapterIntegrationTests {
@Autowired
private DataSerializerSessionSerializerAdapter<Session> dataSerializer;
@Autowired
@Qualifier(GemFireHttpSessionConfiguration.SESSION_SERIALIZER_BEAN_ALIAS)
private SessionSerializer<Session, DataInput, DataOutput> sessionSerializer;
@Test
public void constructsAndAutowiresDataSerializerSessionSerializerAdapter() {
assertThat(this.dataSerializer).isNotNull();
assertThat(this.sessionSerializer).isNotNull();
assertThat(this.dataSerializer.getId()).isEqualTo(0xBAC2BAC);
assertThat(this.dataSerializer.getSupportedClasses())
.containsExactly(GemFireSession.class, GemFireSessionAttributes.class, DeltaCapableGemFireSession.class,
DeltaCapableGemFireSessionAttributes.class);
}
@Configuration
@SuppressWarnings("unused")
static class TestConfiguration {
@Bean
GemfireBeanFactoryLocator beanFactoryLocator(BeanFactory beanFactory) {
return GemfireBeanFactoryLocator.newBeanFactoryLocator(beanFactory, "sessionBeanFactory");
}
@Bean
DataSerializerSessionSerializerAdapter dataSerializer() {
return new DataSerializerSessionSerializerAdapter();
}
@Bean
@Qualifier(GemFireHttpSessionConfiguration.SESSION_SERIALIZER_BEAN_ALIAS)
@SuppressWarnings("unchecked")
SessionSerializer<Session, DataInput, DataOutput> mockSessionSerializer() {
return mock(SessionSerializer.class, "SessionSerializer");
}
}
}

View File

@@ -39,18 +39,16 @@ import org.apache.geode.pdx.PdxSerializer;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.gemfire.CacheFactoryBean;
import org.springframework.data.gemfire.GemfireOperations;
@@ -58,8 +56,6 @@ import org.springframework.data.gemfire.GemfireTemplate;
import org.springframework.data.gemfire.IndexFactoryBean;
import org.springframework.data.gemfire.IndexType;
import org.springframework.data.gemfire.RegionAttributesFactoryBean;
import org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer;
import org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer;
import org.springframework.data.gemfire.config.xml.GemfireConstants;
import org.springframework.session.Session;
import org.springframework.session.SessionRepository;
@@ -153,14 +149,9 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
*/
public static final String SESSION_DATA_SERIALIZER_BEAN_NAME = "SessionDataSerializer";
public static final String SESSION_PDX_SERIALIZER_BEAN_NAME = "SessionPdxSerializer";
public static final String SESSION_SERIALIZER_BEAN_ALIAS = "SessionSerializerRegisteredBeanAlias";
public static final String SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME =
"spring.session.data.geode.serializer.qualifier";
public static final String SESSION_SERIALIZER_REGISTERED_ALIAS =
"org.springframework.session.data.geode.serializer.registeredAlias";
public static final String DEFAULT_SESSION_SERIALIZER_BEAN_NAME = SESSION_DATA_SERIALIZER_BEAN_NAME;
public static final String DEFAULT_SESSION_SERIALIZER_BEAN_NAME = SESSION_PDX_SERIALIZER_BEAN_NAME;
/**
* Defaults names of all {@link Session} attributes that will be indexed by Apache Geode.
@@ -185,21 +176,34 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
private String[] indexableSessionAttributes = DEFAULT_INDEXABLE_SESSION_ATTRIBUTES;
/**
* Sets a reference the Spring {@link ApplicationContext}.
*
* @param applicationContext reference to the Spring {@link ApplicationContext}.
* @throws BeansException if the reference cannot be stored.
* @see org.springframework.context.ApplicationContext
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
super.setApplicationContext(applicationContext);
this.applicationContext = applicationContext;
}
/**
* Returns a reference to the Spring {@link ApplicationContext}.
*
* @return a reference to the Spring {@link ApplicationContext}.
* @see org.springframework.context.ApplicationContext
*/
protected ApplicationContext getApplicationContext() {
return Optional.ofNullable(this.applicationContext)
.orElseThrow(() -> newIllegalStateException("The ApplicationContext was not properly configured"));
}
/**
* Sets a reference to the {@link ClassLoader} used by the Spring container to load bean class types.
* Sets a reference to the {@link ClassLoader} used by the Spring container to load bean {@link Class class types}.
*
* @param beanClassLoader {@link ClassLoader} used by the Spring container to load bean class types.
* @param beanClassLoader {@link ClassLoader} used by the Spring container to load bean {@link Class class types}.
* @see org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader(ClassLoader)
* @see java.lang.ClassLoader
*/
@@ -207,6 +211,24 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
this.beanClassLoader = beanClassLoader;
}
/**
* Returns a reference to the {@link ClassLoader} used by the Spring container to load bean
* {@link Class class types}.
*
* @return the {@link ClassLoader} used by the Spring container to load bean {@link Class class types}.
* @see java.lang.ClassLoader
*/
protected ClassLoader getBeanClassLoader() {
return this.beanClassLoader;
}
/**
* Returns a reference to the Spring container {@link ConfigurableBeanFactory}.
*
* @return a reference to the Spring container {@link ConfigurableBeanFactory}.
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory
* @see #getApplicationContext()
*/
protected ConfigurableBeanFactory getBeanFactory() {
ApplicationContext applicationContext = getApplicationContext();
@@ -218,16 +240,6 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
ConfigurableBeanFactory.class.getName(), ObjectUtils.nullSafeClassName(applicationContext)));
}
/**
* Returns a reference to the {@link ClassLoader} used by the Spring container to load bean class types.
*
* @return the {@link ClassLoader} used by the Spring container to load bean class types.
* @see java.lang.ClassLoader
*/
protected ClassLoader getBeanClassLoader() {
return this.beanClassLoader;
}
/**
* Gets the {@link ClientRegionShortcut} used to configure the data management policy of the {@link ClientCache}
* {@link Region} that will store {@link Session} state.
@@ -457,28 +469,31 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
@PostConstruct
public void init() {
System.err.printf("SETTING SYSTEM PROPERTY (%s) TO (%s) %n", SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME,
getSessionSerializerBeanName());
System.setProperty(SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME, getSessionSerializerBeanName());
getBeanFactory().registerAlias(getSessionSerializerBeanName(), SESSION_SERIALIZER_REGISTERED_ALIAS);
getBeanFactory().registerAlias(getSessionSerializerBeanName(), SESSION_SERIALIZER_BEAN_ALIAS);
}
@Bean
@DependsOn({ SESSION_DATA_SERIALIZER_BEAN_NAME, SESSION_PDX_SERIALIZER_BEAN_NAME })
public ClientCacheConfigurer sessionClientCacheConfigurer(
@Qualifier(SESSION_SERIALIZER_REGISTERED_ALIAS) SessionSerializer sessionSerializer) {
BeanPostProcessor sessionSerializerConfigurationBeanPostProcessor() {
return (beanName, clientCacheFactoryBean) -> configureSerialization(clientCacheFactoryBean, sessionSerializer);
return new BeanPostProcessor() {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof CacheFactoryBean) {
SessionSerializer sessionSerializer = resolveSessionSerializer();
configureSerialization((CacheFactoryBean) bean, sessionSerializer);
}
return bean;
}
};
}
@Bean
@DependsOn({ SESSION_DATA_SERIALIZER_BEAN_NAME, SESSION_PDX_SERIALIZER_BEAN_NAME })
public PeerCacheConfigurer sessionPeerCacheConfigurer(
@Qualifier(SESSION_SERIALIZER_REGISTERED_ALIAS) SessionSerializer sessionSerializer) {
return (beanName, cacheFactoryBean) -> configureSerialization(cacheFactoryBean, sessionSerializer);
private SessionSerializer resolveSessionSerializer() {
return getApplicationContext().getBean(SESSION_SERIALIZER_BEAN_ALIAS, SessionSerializer.class);
}
@SuppressWarnings("unchecked")
@@ -497,8 +512,6 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
(PdxSerializer) sessionSerializer, cacheFactoryBean.getPdxSerializer()));
}
else {
// TODO add more intelligence to figure out what type of serializer has been configured
// (e.g. PDX or DataSerialization based serializers)
Optional.ofNullable(sessionSerializer)
.ifPresent(serializer ->
cacheFactoryBean.setPdxSerializer(ComposablePdxSerializer.compose(
@@ -508,28 +521,14 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
}
}
/**
* Defines the {@link SessionRepository} bean used to interact with Apache Geode or Pivotal GemFire
* as the Spring Session provider.
*
* @param gemfireOperations instance of {@link GemfireOperations} used to manage {@link Session} state
* in Apache Geode or Pivotal GemFire.
* @return a {@link GemFireOperationsSessionRepository} for managing (clustering/replicating) {@link Session} state
* in Apache Geode or Pivotal GemFire.
* @see org.springframework.session.data.gemfire.GemFireOperationsSessionRepository
* @see org.springframework.data.gemfire.GemfireOperations
*/
@Bean
public GemFireOperationsSessionRepository sessionRepository(
@Qualifier("sessionRegionTemplate") GemfireOperations gemfireOperations) {
@Bean(SESSION_DATA_SERIALIZER_BEAN_NAME)
public Object sessionDataSerializer() {
return new DataSerializableSessionSerializer();
}
GemFireOperationsSessionRepository sessionRepository =
new GemFireOperationsSessionRepository(gemfireOperations);
sessionRepository.setMaxInactiveIntervalInSeconds(getMaxInactiveIntervalInSeconds());
sessionRepository.setUseDataSerialization(isUsingDataSerialization());
return sessionRepository;
@Bean(SESSION_PDX_SERIALIZER_BEAN_NAME)
public Object sessionPdxSerializer() {
return new PdxSerializableSessionSerializer();
}
/**
@@ -634,16 +633,28 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
return new GemfireTemplate(gemfireCache.getRegion(getSessionRegionName()));
}
@Bean(SESSION_DATA_SERIALIZER_BEAN_NAME)
//@Conditional(DataSerializableSessionSerializerCondition.class)
public Object sessionDataSerializer() {
return new PdxSerializableSessionSerializer();
}
/**
* Defines the {@link SessionRepository} bean used to interact with Apache Geode or Pivotal GemFire
* as the Spring Session provider.
*
* @param gemfireOperations instance of {@link GemfireOperations} used to manage {@link Session} state
* in Apache Geode or Pivotal GemFire.
* @return a {@link GemFireOperationsSessionRepository} for managing (clustering/replicating) {@link Session} state
* in Apache Geode or Pivotal GemFire.
* @see org.springframework.session.data.gemfire.GemFireOperationsSessionRepository
* @see org.springframework.data.gemfire.GemfireOperations
*/
@Bean
public GemFireOperationsSessionRepository sessionRepository(
@Qualifier("sessionRegionTemplate") GemfireOperations gemfireOperations) {
@Bean(SESSION_PDX_SERIALIZER_BEAN_NAME)
//@Conditional(PdxSerializableSessionSerializerCondition.class)
public Object sessionPdxSerializer() {
return new DataSerializableSessionSerializer();
GemFireOperationsSessionRepository sessionRepository =
new GemFireOperationsSessionRepository(gemfireOperations);
sessionRepository.setMaxInactiveIntervalInSeconds(getMaxInactiveIntervalInSeconds());
sessionRepository.setUseDataSerialization(isUsingDataSerialization());
return sessionRepository;
}
/**
@@ -695,40 +706,4 @@ public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfigurat
return sessionAttributesIndex;
}
public static class DataSerializableSessionSerializerCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
System.err.printf("%1$s-System.getProperty(%2$s) = '%3$s'%n", getClass().getSimpleName(),
SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME,
System.getProperty(SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME));
System.err.printf("%1$s-Environment.get(%2$s) = '%3$s'%n", getClass().getSimpleName(),
SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME,
context.getEnvironment().getProperty(SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME));
return SESSION_DATA_SERIALIZER_BEAN_NAME
.equals(context.getEnvironment().getProperty(SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME));
}
}
public static class PdxSerializableSessionSerializerCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
System.err.printf("%1$s-System.getProperty(%2$s) = '%3$s'%n", getClass().getSimpleName(),
SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME,
System.getProperty(SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME));
System.err.printf("%1$s-Environment.get(%2$s) = '%3$s'%n", getClass().getSimpleName(),
SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME,
context.getEnvironment().getProperty(SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME));
return SESSION_PDX_SERIALIZER_BEAN_NAME
.equals(context.getEnvironment().getProperty(SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME));
}
}
}

View File

@@ -58,13 +58,6 @@ public abstract class AbstractDataSerializableSessionSerializer<T> extends DataS
return DEFAULT_ALLOW_JAVA_SERIALIZATION;
}
@Override
@SuppressWarnings("unchecked")
public boolean canSerialize(Class<?> type) {
return stream(nullSafeArray(getSupportedClasses(), Class.class))
.anyMatch(supportedClass -> supportedClass.isAssignableFrom(type));
}
@Override
@SuppressWarnings("unchecked")
public boolean toData(Object session, DataOutput out) throws IOException {
@@ -95,6 +88,14 @@ public abstract class AbstractDataSerializableSessionSerializer<T> extends DataS
return DataSerializer.readObject(in);
}
@Override
@SuppressWarnings("unchecked")
public boolean canSerialize(Class<?> type) {
return stream(nullSafeArray(getSupportedClasses(), Class.class))
.filter(it -> type != null)
.anyMatch(supportedClass -> supportedClass.isAssignableFrom(type));
}
protected <T> T safeRead(DataInput in, DataInputReader<T> reader) {
try {
return reader.doRead(in);

View File

@@ -18,18 +18,28 @@ package org.springframework.session.data.gemfire.serialization.data.provider;
import static org.springframework.data.gemfire.util.ArrayUtils.asArray;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeSet;
import static org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.DeltaCapableGemFireSessionAttributes;
import static org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes;
import java.io.DataInput;
import java.io.DataOutput;
import java.util.Set;
import org.springframework.session.Session;
import org.springframework.session.data.gemfire.serialization.SessionSerializer;
import org.springframework.session.data.gemfire.serialization.data.AbstractDataSerializableSessionSerializer;
/**
* The {@link DataSerializableSessionAttributesSerializer} class...
* The {@link DataSerializableSessionAttributesSerializer} class is an implementation of the {@link SessionSerializer}
* interface used to serialize a Spring {@link Session} attributes using the GemFire/Geode's Data Serialization
* framework.
*
* @author John Blum
* @see java.io.DataInput
* @see java.io.DataOutput
* @see org.springframework.session.Session
* @see org.springframework.session.data.gemfire.serialization.SessionSerializer
* @see org.springframework.session.data.gemfire.serialization.data.AbstractDataSerializableSessionSerializer
* @since 2.0.0
*/
@SuppressWarnings("unused")
@@ -47,7 +57,7 @@ public class DataSerializableSessionAttributesSerializer
@Override
public Class<?>[] getSupportedClasses() {
return asArray(GemFireSessionAttributes.class);
return asArray(GemFireSessionAttributes.class, DeltaCapableGemFireSessionAttributes.class);
}
@Override

View File

@@ -25,16 +25,25 @@ import java.time.Instant;
import java.util.Collections;
import java.util.Set;
import org.springframework.session.Session;
import org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.DeltaCapableGemFireSession;
import org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSession;
import org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes;
import org.springframework.session.data.gemfire.serialization.SessionSerializer;
import org.springframework.session.data.gemfire.serialization.data.AbstractDataSerializableSessionSerializer;
import org.springframework.session.data.gemfire.support.AbstractSession;
import org.springframework.util.StringUtils;
/**
* The {@link DataSerializableSessionSerializer} class...
* The {@link DataSerializableSessionSerializer} class is an implementation of the {@link SessionSerializer} interface
* used to serialize a Spring {@link Session} using the GemFire/Geode's Data Serialization framework.
*
* @author John Blum
* @see java.io.DataInput
* @see java.io.DataOutput
* @see org.springframework.session.Session
* @see org.springframework.session.data.gemfire.serialization.SessionSerializer
* @see org.springframework.session.data.gemfire.serialization.data.AbstractDataSerializableSessionSerializer
* @since 2.0.0
*/
@SuppressWarnings("unused")
@@ -52,7 +61,7 @@ public class DataSerializableSessionSerializer extends AbstractDataSerializableS
@Override
public Class<?>[] getSupportedClasses() {
return asArray(GemFireSession.class);
return asArray(GemFireSession.class, DeltaCapableGemFireSession.class);
}
@Override

View File

@@ -24,43 +24,58 @@ import java.io.DataInput;
import java.io.DataOutput;
import java.util.Optional;
import javax.annotation.Resource;
import org.apache.geode.DataSerializer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.session.Session;
import org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.DeltaCapableGemFireSession;
import org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.DeltaCapableGemFireSessionAttributes;
import org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSession;
import org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes;
import org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration;
import org.springframework.session.data.gemfire.serialization.SessionSerializer;
import org.springframework.stereotype.Component;
/**
* The DataSerializerSessionSerializerAdapter class...
* The {@link DataSerializerSessionSerializerAdapter} class is a two-way Adapter adapting a {@link SessionSerializer}
* instance as an instance of {@link DataSerializer} in a GemFire/Geode context, or adapting a {@link DataSerializer}
* as a {@link SessionSerializer} in a Spring Session context.
*
* @author John Blum
* @see org.apache.geode.DataSerializer
* @see org.springframework.session.Session
* @see org.springframework.session.data.gemfire.serialization.SessionSerializer
* @see org.springframework.session.data.gemfire.serialization.data.support.WirableDataSerializer
* @see org.springframework.stereotype.Component
* @since 2.0.0
*/
@SuppressWarnings("unused")
@Component("org.springfamework.session.data.gemfire.serialization.data.support.DataSerializerSessionSerializerAdapter")
public class DataSerializerSessionSerializerAdapter<T extends Session> extends WirableDataSerializer<T> {
static {
register(DataSerializerSessionSerializerAdapter.class);
}
@Resource(name = "${" + GemFireHttpSessionConfiguration.SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME
+ ":" + GemFireHttpSessionConfiguration.SESSION_DATA_SERIALIZER_BEAN_NAME + "}")
private SessionSerializer<T, DataInput, DataOutput> sessionSerializer;
public DataSerializerSessionSerializerAdapter() {
autowire();
}
public DataSerializerSessionSerializerAdapter(SessionSerializer<T, DataInput, DataOutput> sessionSerializer) {
this.sessionSerializer = Optional.ofNullable(sessionSerializer)
.orElseThrow(() -> newIllegalArgumentException("SessionSerializer is required"));
}
@Override
public int getId() {
return 0x0BAC2BAC;
}
@Autowired
@Qualifier(GemFireHttpSessionConfiguration.SESSION_SERIALIZER_BEAN_ALIAS)
public final void setSessionSerializer(SessionSerializer<T, DataInput, DataOutput> sessionSerializer) {
this.sessionSerializer = Optional.ofNullable(sessionSerializer)
.orElseThrow(() -> newIllegalArgumentException("SessionSerializer is required"));
}
protected SessionSerializer<T, DataInput, DataOutput> getSessionSerializer() {
return Optional.ofNullable(this.sessionSerializer)
.orElseThrow(() -> newIllegalStateException("SessionSerializer was not properly configured"));
@@ -68,7 +83,8 @@ public class DataSerializerSessionSerializerAdapter<T extends Session> extends W
@Override
public Class<?>[] getSupportedClasses() {
return asArray(Session.class);
return asArray(GemFireSession.class, GemFireSessionAttributes.class, DeltaCapableGemFireSession.class,
DeltaCapableGemFireSessionAttributes.class);
}
@Override

View File

@@ -18,31 +18,47 @@ package org.springframework.session.data.gemfire.serialization.data.support;
import static org.springframework.data.gemfire.support.GemfireBeanFactoryLocator.newBeanFactoryLocator;
import java.util.Optional;
import org.apache.geode.DataSerializer;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.wiring.BeanConfigurerSupport;
import org.springframework.session.data.gemfire.serialization.data.AbstractDataSerializableSessionSerializer;
import org.springframework.stereotype.Component;
/**
* The WirableDataSerializer class...
* {@link WirableDataSerializer} is an abstract base class supporting auto-wiring of a non-managed,
* GemFire/Geode {@link DataSerializer}, Spring {@link Component}.
*
* @author John Blum
* @see org.apache.geode.DataSerializer
* @see org.springframework.beans.factory.BeanFactory
* @see org.springframework.beans.factory.wiring.BeanConfigurerSupport
* @see org.springframework.session.data.gemfire.serialization.data.AbstractDataSerializableSessionSerializer
* @since 2.0.0
*/
public abstract class WirableDataSerializer<T> extends AbstractDataSerializableSessionSerializer<T> {
abstract class WirableDataSerializer<T> extends AbstractDataSerializableSessionSerializer<T> {
protected final void autowire() {
BeanConfigurerSupport beanConfigurer = newBeanConfigurer(locateBeanFactory());
beanConfigurer.configureBean(this);
beanConfigurer.destroy();
locateBeanFactory().map(this::newBeanConfigurer).ifPresent(beanConfigurer -> {
beanConfigurer.configureBean(this);
beanConfigurer.destroy();
});
}
private BeanFactory locateBeanFactory() {
return newBeanFactoryLocator().useBeanFactory();
Optional<BeanFactory> locateBeanFactory() {
try {
return Optional.ofNullable(newBeanFactoryLocator().useBeanFactory());
}
catch (Exception ignore) {
return Optional.empty();
}
}
private BeanConfigurerSupport newBeanConfigurer(BeanFactory beanFactory) {
BeanConfigurerSupport newBeanConfigurer(BeanFactory beanFactory) {
BeanConfigurerSupport beanConfigurer = new BeanConfigurerSupport();

View File

@@ -26,19 +26,23 @@ import org.springframework.session.Session;
import org.springframework.session.data.gemfire.serialization.SessionSerializer;
/**
* The {@link AbstractPdxSerializableSessionSerializer} class...
* The {@link AbstractPdxSerializableSessionSerializer} class is an abstract base class containing functionality common
* to all GemFire/Geode PDX-based {@link SessionSerializer} implementations.
*
* This class also implements GemFire/Geode's {@link PdxSerializer} interface, adapting it to the Spring Session,
* Data GemFire {@link SessionSerializer} interface.
*
* @author John Blum
* @see org.apache.geode.pdx.PdxReader
* @see org.apache.geode.pdx.PdxWriter
* @see org.apache.geode.pdx.PdxSerializer
* @see org.springframework.session.Session
* @see org.springframework.session.data.gemfire.serialization.SessionSerializer
* @since 2.0.0
*/
public abstract class AbstractPdxSerializableSessionSerializer<T extends Session>
implements PdxSerializer, SessionSerializer<T, PdxReader, PdxWriter> {
@Override
public boolean canSerialize(Class<?> type) {
return Optional.ofNullable(type).map(Session.class::isAssignableFrom).orElse(false);
}
@Override
@SuppressWarnings("unchecked")
public boolean toData(Object session, PdxWriter writer) {
@@ -60,4 +64,9 @@ public abstract class AbstractPdxSerializableSessionSerializer<T extends Session
.map(it -> deserialize(reader))
.orElse(null);
}
@Override
public boolean canSerialize(Class<?> type) {
return Optional.ofNullable(type).map(Session.class::isAssignableFrom).orElse(false);
}
}

View File

@@ -29,29 +29,31 @@ import java.util.Set;
import org.apache.geode.pdx.PdxReader;
import org.apache.geode.pdx.PdxWriter;
import org.springframework.session.Session;
import org.springframework.session.data.gemfire.serialization.SessionSerializer;
import org.springframework.session.data.gemfire.serialization.pdx.AbstractPdxSerializableSessionSerializer;
import org.springframework.session.data.gemfire.support.AbstractSession;
/**
* The PdxSerializableSessionSerializer class...
* The {@link PdxSerializableSessionSerializer} class is an implementation of the {@link SessionSerializer} interface
* used to serialize a Spring {@link Session} using the GemFire/Geode's PDX Serialization framework.
*
* @author John Blum
* @since 1.0.0
* @see org.apache.geode.pdx.PdxReader
* @see org.apache.geode.pdx.PdxWriter
* @see org.springframework.session.Session
* @see org.springframework.session.data.gemfire.serialization.SessionSerializer
* @see org.springframework.session.data.gemfire.serialization.pdx.AbstractPdxSerializableSessionSerializer
* @since 2.0.0
*/
@SuppressWarnings("unused")
public class PdxSerializableSessionSerializer extends AbstractPdxSerializableSessionSerializer<GemFireSession> {
@Override
public boolean canSerialize(Class<?> type) {
return Optional.ofNullable(type).map(GemFireSession.class::isAssignableFrom).orElse(false);
}
@Override
@SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter")
public void serialize(GemFireSession session, PdxWriter writer) {
synchronized (session) {
writer.writeString("id", session.getId());
writer.writeLong("creationTime", session.getCreationTime().toEpochMilli());
writer.writeLong("lastAccessedTime", session.getLastAccessedTime().toEpochMilli());
@@ -102,4 +104,9 @@ public class PdxSerializableSessionSerializer extends AbstractPdxSerializableSes
return session;
}
@Override
public boolean canSerialize(Class<?> type) {
return Optional.ofNullable(type).map(GemFireSession.class::isAssignableFrom).orElse(false);
}
}

View File

@@ -34,23 +34,19 @@ import org.apache.geode.pdx.PdxSerializer;
import org.apache.geode.pdx.PdxWriter;
/**
* The ComposablePdxSerializer class...
* The {@link ComposablePdxSerializer} class is a composite of {@link PdxSerializer} objects implementing
* the Composite Software Design Pattern.
*
* @author John Blum
* @since 1.0.0
* @see java.lang.Iterable
* @see org.apache.geode.pdx.PdxSerializer
* @since 2.0.0
*/
@SuppressWarnings("unused")
public class ComposablePdxSerializer implements Iterable<PdxSerializer>, PdxSerializer {
public class ComposablePdxSerializer implements PdxSerializer, Iterable<PdxSerializer> {
private final List<PdxSerializer> pdxSerializers;
private ComposablePdxSerializer(List<PdxSerializer> pdxSerializers) {
this.pdxSerializers = Optional.ofNullable(pdxSerializers)
.map(it -> Collections.unmodifiableList(pdxSerializers))
.orElseThrow(() -> newIllegalArgumentException("PdxSerializers [%s] are required", pdxSerializers));
}
public static PdxSerializer compose(PdxSerializer... pdxSerializers) {
return compose(Arrays.asList(nullSafeArray(pdxSerializers, PdxSerializer.class)));
}
@@ -66,6 +62,13 @@ public class ComposablePdxSerializer implements Iterable<PdxSerializer>, PdxSeri
: new ComposablePdxSerializer(pdxSerializerList)));
}
private ComposablePdxSerializer(List<PdxSerializer> pdxSerializers) {
this.pdxSerializers = Optional.ofNullable(pdxSerializers)
.map(it -> Collections.unmodifiableList(pdxSerializers))
.orElseThrow(() -> newIllegalArgumentException("PdxSerializers [%s] are required", pdxSerializers));
}
@Override
public Iterator<PdxSerializer> iterator() {
return this.pdxSerializers.iterator();

View File

@@ -21,6 +21,7 @@ import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newI
import java.util.Optional;
import org.apache.geode.pdx.PdxReader;
import org.apache.geode.pdx.PdxSerializer;
import org.apache.geode.pdx.PdxWriter;
import org.springframework.session.Session;
@@ -28,9 +29,15 @@ import org.springframework.session.data.gemfire.serialization.SessionSerializer;
import org.springframework.session.data.gemfire.serialization.pdx.AbstractPdxSerializableSessionSerializer;
/**
* The {@link PdxSerializerSessionSerializerAdapter} class...
* The {@link PdxSerializerSessionSerializerAdapter} class is a two-way Adapter adapting a {@link SessionSerializer}
* instance as an instance of {@link PdxSerializer} in a GemFire/Geode context, or adapting a {@link PdxSerializer}
* as a {@link SessionSerializer} in a Spring Session context.
*
* @author John Blum
* @see org.apache.geode.pdx.PdxSerializer
* @see org.springframework.session.Session
* @see org.springframework.session.data.gemfire.serialization.SessionSerializer
* @see org.springframework.session.data.gemfire.serialization.pdx.AbstractPdxSerializableSessionSerializer
* @since 2.0.0
*/
@SuppressWarnings("unused")

View File

@@ -28,7 +28,6 @@ import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
@@ -78,11 +77,6 @@ public class GemFireHttpSessionConfigurationTests {
private GemFireHttpSessionConfiguration gemfireConfiguration;
@AfterClass
public static void tearDown() {
System.clearProperty(GemFireHttpSessionConfiguration.SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME);
}
@SuppressWarnings("unchecked")
protected <T> T getField(Object obj, String fieldName) {
try {
@@ -324,7 +318,7 @@ public class GemFireHttpSessionConfigurationTests {
}
@Test
public void postConstructInitSetsSystemPropertyAndRegistersBeanAlias() {
public void postConstructInitRegistersBeanAlias() {
ConfigurableListableBeanFactory mockBeanFactory = mock(ConfigurableListableBeanFactory.class);
@@ -332,20 +326,18 @@ public class GemFireHttpSessionConfigurationTests {
given(mockApplicationContext.getBeanFactory()).willReturn(mockBeanFactory);
assertThat(System.getProperty(GemFireHttpSessionConfiguration.SESSION_SERIALIZER_REGISTERED_ALIAS)).isNull();
assertThat(System.getProperty(GemFireHttpSessionConfiguration.SESSION_SERIALIZER_BEAN_ALIAS)).isNull();
this.gemfireConfiguration.setApplicationContext(mockApplicationContext);
this.gemfireConfiguration.setSessionSerializerBeanName("testSessionSerializer");
this.gemfireConfiguration.init();
assertThat(this.gemfireConfiguration.getApplicationContext()).isSameAs(mockApplicationContext);
assertThat(System.getProperty(GemFireHttpSessionConfiguration.SESSION_SERIALIZER_QUALIFIER_PROPERTY_NAME))
.isEqualTo("testSessionSerializer");
verify(mockApplicationContext, times(1)).getBeanFactory();
verify(mockBeanFactory, times(1)).registerAlias(eq("testSessionSerializer"),
eq(GemFireHttpSessionConfiguration.SESSION_SERIALIZER_REGISTERED_ALIAS));
eq(GemFireHttpSessionConfiguration.SESSION_SERIALIZER_BEAN_ALIAS));
}
@Test

View File

@@ -0,0 +1,83 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire.serialization;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
/**
* Unit tests for the {@link SessionSerializer} interface.
*
* @author John Blum
* @see org.junit.Test
* @see org.mockito.Mock
* @see org.mockito.Mockito
* @see org.springframework.session.data.gemfire.serialization.SessionSerializer
* @since 2.0.0
*/
@RunWith(MockitoJUnitRunner.class)
public class SessionSerializerTests {
@Mock
private SessionSerializer sessionSerializer;
@Test
@SuppressWarnings("unchecked")
public void canSerializeWithSerializableObjectReturnsTrue() {
when(this.sessionSerializer.canSerialize(any(Class.class))).thenReturn(true);
when(this.sessionSerializer.canSerialize(any(Object.class))).thenCallRealMethod();
assertThat(this.sessionSerializer.canSerialize("test")).isTrue();
verify(this.sessionSerializer, times(1)).canSerialize(eq("test"));
verify(this.sessionSerializer, times(1)).canSerialize(eq(String.class));
}
@Test
@SuppressWarnings("unchecked")
public void canSerializeWithNullReturnFalse() {
assertThat(this.sessionSerializer.canSerialize((Object) null)).isFalse();
verify(this.sessionSerializer, times(1)).canSerialize(eq((Object) null));
verify(this.sessionSerializer, never()).canSerialize(any(Class.class));
}
@Test
@SuppressWarnings("unchecked")
public void canSerializeWithNonSerializableObjectReturnFalse() {
when(this.sessionSerializer.canSerialize(any(Class.class))).thenReturn(false);
when(this.sessionSerializer.canSerialize(any(Object.class))).thenCallRealMethod();
assertThat(this.sessionSerializer.canSerialize("test")).isFalse();
verify(this.sessionSerializer, times(1)).canSerialize(eq("test"));
verify(this.sessionSerializer, times(1)).canSerialize(eq(String.class));
}
}

View File

@@ -0,0 +1,296 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire.serialization.data;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.data.gemfire.util.ArrayUtils.asArray;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.session.Session;
import org.springframework.session.data.gemfire.serialization.SerializationException;
import org.springframework.session.data.gemfire.serialization.data.AbstractDataSerializableSessionSerializer.DataInputReader;
import org.springframework.session.data.gemfire.serialization.data.AbstractDataSerializableSessionSerializer.DataOutputWriter;
/**
* Unit tests for {@link AbstractDataSerializableSessionSerializer}.
*
* @author John Blum
* @see org.junit.Test
* @see org.mockito.Mock
* @see org.mockito.Mockito
* @see org.mockito.Spy
* @see org.springframework.session.data.gemfire.serialization.data.AbstractDataSerializableSessionSerializer
* @since 2.0.0
*/
@RunWith(MockitoJUnitRunner.class)
public class AbstractDataSerializableSessionSerializerTests {
@Spy
private AbstractDataSerializableSessionSerializer<Session> sessionSerializer;
@Mock
private DataInput mockDataInput;
@Mock
private DataOutput mockDataOuput;
@Mock
private Session mockSession;
@Test
public void constructAbstractDataSerializableSessionSerializer() {
assertThat(this.sessionSerializer).isNotNull();
assertThat(this.sessionSerializer.getId()).isEqualTo(0xA11ACE5);
assertThat(this.sessionSerializer.getSupportedClasses()).isEmpty();
assertThat(this.sessionSerializer.allowJavaSerialization()).isTrue();
}
@Test
public void toDataCallsSerializeForSerializableObjectAndReturnsTrue() throws IOException {
when(this.sessionSerializer.canSerialize(any(Session.class))).thenReturn(true);
assertThat(this.sessionSerializer.toData(this.mockSession, this.mockDataOuput)).isTrue();
verify(this.sessionSerializer, times(1)).canSerialize(eq(this.mockSession));
verify(this.sessionSerializer, times(1))
.serialize(eq(this.mockSession), eq(this.mockDataOuput));
}
@Test
public void toDataWithNonSerializableObjectReturnsFalse() throws IOException {
when(this.sessionSerializer.canSerialize(any())).thenReturn(false);
assertThat(this.sessionSerializer.toData("test", this.mockDataOuput)).isFalse();
verify(this.sessionSerializer, times(1)).canSerialize(eq("test"));
verify(this.sessionSerializer, never()).serialize(any(), any(DataOutput.class));
}
@Test
public void toDataWithNullReturnsFalse() throws IOException {
assertThat(this.sessionSerializer.toData(null, this.mockDataOuput)).isFalse();
verify(this.sessionSerializer, never()).canSerialize(any());
verify(this.sessionSerializer, never()).serialize(any(), any(DataOutput.class));
}
@Test
public void serializeObjectDefaultsAllowJavaSerializationToTrue() throws IOException {
this.sessionSerializer.serializeObject("test", this.mockDataOuput);
verify(this.sessionSerializer, times(1))
.serializeObject(eq("test"), eq(this.mockDataOuput), eq(true));
}
@Test
public void serializeObjectWithAllowJavaSerializationSetToFalse() throws IOException {
this.sessionSerializer.serializeObject("test", this.mockDataOuput, false);
}
@Test
public void fromDataCallsDeserialize() throws IOException, ClassNotFoundException {
when(this.sessionSerializer.deserialize(any(DataInput.class))).thenReturn(this.mockSession);
assertThat(this.sessionSerializer.fromData(this.mockDataInput)).isEqualTo(this.mockSession);
verify(this.sessionSerializer, times(1)).deserialize(eq(this.mockDataInput));
}
@Test
public void canSerializeSerializableType() {
when(this.sessionSerializer.getSupportedClasses()).thenReturn(asArray(Session.class));
assertThat(this.sessionSerializer.canSerialize(this.mockSession)).isTrue();
verify(this.sessionSerializer, times(1)).getSupportedClasses();
}
@Test
public void canSerializeSerializableSubType() {
when(this.sessionSerializer.getSupportedClasses()).thenReturn(asArray(Number.class, Integer.class, Long.class));
assertThat(this.sessionSerializer.canSerialize((short) 64)).isTrue();
verify(this.sessionSerializer, times(1)).getSupportedClasses();
}
@Test
public void cannotSerializeNonSerializableType() {
when(this.sessionSerializer.getSupportedClasses()).thenReturn(asArray(Session.class));
assertThat(this.sessionSerializer.canSerialize("sessionId")).isFalse();
verify(this.sessionSerializer, times(1)).getSupportedClasses();
}
@Test
public void cannotSerializeNull() {
when(this.sessionSerializer.getSupportedClasses()).thenReturn(asArray(Object.class));
assertThat(this.sessionSerializer.canSerialize(null)).isFalse();
verify(this.sessionSerializer, times(1)).getSupportedClasses();
}
@Test
public void cannotSerializeWhenSupportClassesAreEmpty() {
when(this.sessionSerializer.getSupportedClasses()).thenReturn(asArray());
assertThat(this.sessionSerializer.canSerialize("test")).isFalse();
verify(this.sessionSerializer, times(1)).getSupportedClasses();
}
@Test
public void cannotSerializeWhenSupportClassesAreNull() {
when(this.sessionSerializer.getSupportedClasses()).thenReturn(null);
assertThat(this.sessionSerializer.canSerialize("test")).isFalse();
verify(this.sessionSerializer, times(1)).getSupportedClasses();
}
@Test
@SuppressWarnings("unchecked")
public void safeReadReturnsValue() throws IOException, ClassNotFoundException {
DataInputReader<String> mockDataInputReader = mock(DataInputReader.class);
when(mockDataInputReader.doRead(any(DataInput.class))).thenReturn("test");
assertThat(this.sessionSerializer.safeRead(this.mockDataInput, mockDataInputReader)).isEqualTo("test");
verify(mockDataInputReader, times(1)).doRead(eq(this.mockDataInput));
}
@Test(expected = SerializationException.class)
@SuppressWarnings("unchecked")
public void safeReadHandlesClassCastException() throws IOException, ClassNotFoundException {
DataInputReader<String> mockDataInputReader = mock(DataInputReader.class);
when(mockDataInputReader.doRead(any(DataInput.class))).thenThrow(new ClassNotFoundException("test"));
try {
this.sessionSerializer.safeRead(this.mockDataInput, mockDataInputReader);
}
catch (Exception expected) {
assertThat(expected).isInstanceOf(SerializationException.class);
assertThat(expected).hasCauseInstanceOf(ClassNotFoundException.class);
assertThat(expected.getCause()).hasMessage("test");
assertThat(expected.getCause()).hasNoCause();
throw expected;
}
finally {
verify(mockDataInputReader, times(1)).doRead(eq(this.mockDataInput));
}
}
@Test(expected = SerializationException.class)
@SuppressWarnings("unchecked")
public void safeReadHandlesIOException() throws IOException, ClassNotFoundException {
DataInputReader<String> mockDataInputReader = mock(DataInputReader.class);
when(mockDataInputReader.doRead(any(DataInput.class))).thenAnswer(invocation ->
invocation.<DataInput>getArgument(0).readUTF());
when(this.mockDataInput.readUTF()).thenThrow(new IOException("test"));
try {
this.sessionSerializer.safeRead(this.mockDataInput, mockDataInputReader);
}
catch (Exception expected) {
assertThat(expected).isInstanceOf(SerializationException.class);
assertThat(expected).hasCauseInstanceOf(IOException.class);
assertThat(expected.getCause()).hasMessage("test");
assertThat(expected.getCause()).hasNoCause();
throw expected;
}
finally {
verify(mockDataInputReader, times(1)).doRead(eq(this.mockDataInput));
verify(this.mockDataInput, times(1)).readUTF();
}
}
@Test
public void safeWriteWritesValue() throws IOException {
DataOutputWriter mockDataOutputWriter = mock(DataOutputWriter.class);
this.sessionSerializer.safeWrite(this.mockDataOuput, mockDataOutputWriter);
verify(mockDataOutputWriter, times(1)).doWrite(eq(this.mockDataOuput));
}
@Test(expected = SerializationException.class)
public void safeWriteHandlesIOException() throws IOException {
DataOutputWriter mockDataOutputWriter = mock(DataOutputWriter.class);
doThrow(new IOException("test")).when(mockDataOutputWriter).doWrite(any(DataOutput.class));
try {
this.sessionSerializer.safeWrite(this.mockDataOuput, mockDataOutputWriter);
}
catch (Exception expected ) {
assertThat(expected).isInstanceOf(SerializationException.class);
assertThat(expected).hasCauseInstanceOf(IOException.class);
assertThat(expected.getCause()).hasMessage("test");
assertThat(expected.getCause()).hasNoCause();
throw expected;
}
finally {
verify(mockDataOutputWriter, times(1)).doWrite(eq(this.mockDataOuput));
}
}
}

View File

@@ -26,6 +26,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.springframework.data.gemfire.util.CollectionUtils.asSet;
import static org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.DeltaCapableGemFireSessionAttributes;
import static org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes;
import java.io.DataInput;
@@ -62,8 +63,9 @@ public class DataSerializableSessionAttributesSerializerTests {
}
@Test
public void supportedClassesContainsGemFireSessionAttributes() {
public void supportedClassesContainsGemFireSessionAttributesAndSubTypes() {
assertThat(this.sessionAttributesSerializer.getSupportedClasses()).contains(GemFireSessionAttributes.class);
assertThat(this.sessionAttributesSerializer.getSupportedClasses()).contains(DeltaCapableGemFireSessionAttributes.class);
}
@Test

View File

@@ -27,6 +27,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.springframework.data.gemfire.util.CollectionUtils.asSet;
import static org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.DeltaCapableGemFireSession;
import static org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSession;
import static org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSessionAttributes;
@@ -73,8 +74,9 @@ public class DataSerializableSessionSerializerTests {
}
@Test
public void supportedClassContainsGemFireSession() {
public void supportedClassContainsGemFireSessionAndSubTypes() {
assertThat(this.sessionSerializer.getSupportedClasses()).contains(GemFireSession.class);
assertThat(this.sessionSerializer.getSupportedClasses()).contains(DeltaCapableGemFireSession.class);
}
@Test

View File

@@ -0,0 +1,137 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire.serialization.data.support;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.DataInput;
import java.io.DataOutput;
import org.junit.Test;
import org.springframework.session.Session;
import org.springframework.session.data.gemfire.serialization.SessionSerializer;
/**
* Unit tests for {@link DataSerializerSessionSerializerAdapter}.
*
* @author John Blum
* @see java.io.DataInput
* @see java.io.DataOutput
* @see org.junit.Test
* @see org.mockito.Mockito
* @see org.springframework.session.Session
* @see org.springframework.session.data.gemfire.serialization.SessionSerializer
* @see org.springframework.session.data.gemfire.serialization.data.support.DataSerializerSessionSerializerAdapter
* @since 2.0.0
*/
public class DataSerializerSessionSerializerAdapterUnitTests {
@Test
@SuppressWarnings("unchecked")
public void setAndGetSessionSerializerReturnsExpected() {
SessionSerializer<Session, DataInput, DataOutput> mockSessionSerializer = mock(SessionSerializer.class);
DataSerializerSessionSerializerAdapter<Session> dataSerializer =
new DataSerializerSessionSerializerAdapter<>();
dataSerializer.setSessionSerializer(mockSessionSerializer);
assertThat(dataSerializer.getSessionSerializer()).isSameAs(mockSessionSerializer);
}
@Test(expected = IllegalArgumentException.class)
public void setSessionSerializerToNullThrowsIllegalArgumentException() {
try {
new DataSerializerSessionSerializerAdapter<>().setSessionSerializer(null);
}
catch (IllegalArgumentException expected) {
assertThat(expected).hasMessage("SessionSerializer is required");
assertThat(expected).hasNoCause();
throw expected;
}
}
@SuppressWarnings("unchecked")
@Test(expected = IllegalStateException.class)
public void getUninitializedSessionSerializerThrowsIllegalStateException() {
try {
new DataSerializerSessionSerializerAdapter<>().getSessionSerializer();
}
catch (IllegalStateException expected) {
assertThat(expected).hasMessage("SessionSerializer was not properly configured");
assertThat(expected).hasNoCause();
throw expected;
}
}
@Test
@SuppressWarnings("unchecked")
public void serializeDelegatesToSessionSerializerSerialize() {
DataOutput mockDataOutput = mock(DataOutput.class);
Session mockSession = mock(Session.class);
SessionSerializer<Session, DataInput, DataOutput> mockSessionSerializer = mock(SessionSerializer.class);
DataSerializerSessionSerializerAdapter<Session> dataSerializer = new DataSerializerSessionSerializerAdapter<>();
dataSerializer.setSessionSerializer(mockSessionSerializer);
assertThat(dataSerializer.getSessionSerializer()).isSameAs(mockSessionSerializer);
dataSerializer.serialize(mockSession, mockDataOutput);
verify(mockSessionSerializer, times(1)).serialize(eq(mockSession), eq(mockDataOutput));
}
@Test
@SuppressWarnings("unchecked")
public void deserializeDelegatesToSessionSerializerDeserialize() {
DataInput mockDataInput = mock(DataInput.class);
Session mockSession = mock(Session.class);
SessionSerializer<Session, DataInput, DataOutput> mockSessionSerializer = mock(SessionSerializer.class);
when(mockSessionSerializer.deserialize(any(DataInput.class))).thenReturn(mockSession);
DataSerializerSessionSerializerAdapter<Session> dataSerializer = new DataSerializerSessionSerializerAdapter<>();
dataSerializer.setSessionSerializer(mockSessionSerializer);
assertThat(dataSerializer.getSessionSerializer()).isSameAs(mockSessionSerializer);
assertThat(dataSerializer.deserialize(mockDataInput)).isEqualTo(mockSession);
verify(mockSessionSerializer, times(1)).deserialize(eq(mockDataInput));
}
}

View File

@@ -0,0 +1,135 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire.serialization.data.support;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.wiring.BeanConfigurerSupport;
import org.springframework.data.gemfire.support.GemfireBeanFactoryLocator;
import org.springframework.session.Session;
/**
* The WirableDataSerializerTests class...
*
* @author John Blum
* @since 1.0.0
*/
@RunWith(MockitoJUnitRunner.class)
public class WirableDataSerializerTests {
@Mock
private ConfigurableListableBeanFactory mockBeanFactory;
@Spy
private WirableDataSerializer<Session> dataSerializer;
@Test
public void autowiresThis() {
AtomicReference<BeanConfigurerSupport> beanConfigurerReference = new AtomicReference<>(null);
doReturn(Optional.of(this.mockBeanFactory)).when(this.dataSerializer).locateBeanFactory();
doAnswer(invocation -> {
BeanConfigurerSupport beanConfigurer = spy((BeanConfigurerSupport) invocation.callRealMethod());
doNothing().when(beanConfigurer).configureBean(any());
beanConfigurerReference.compareAndSet(null, beanConfigurer);
return beanConfigurer;
}).when(this.dataSerializer).newBeanConfigurer(any(BeanFactory.class));
this.dataSerializer.autowire();
assertThat(beanConfigurerReference.get()).isNotNull();
verify(this.dataSerializer, times(1)).locateBeanFactory();
verify(this.dataSerializer, times(1)).newBeanConfigurer(eq(this.mockBeanFactory));
verify(beanConfigurerReference.get(), times(1)).configureBean(eq(this.dataSerializer));
verify(beanConfigurerReference.get(), times(1)).destroy();
}
@Test
public void noAutowiringWhenBeanFactoryCannotBeLocated() {
doReturn(Optional.empty()).when(this.dataSerializer).locateBeanFactory();
this.dataSerializer.autowire();
verify(this.dataSerializer, times(1)).locateBeanFactory();
verify(this.dataSerializer, never()).newBeanConfigurer(any(BeanFactory.class));
}
@Test
public void locatesBeanFactory() {
GemfireBeanFactoryLocator beanFactoryLocator = null;
try {
when(this.mockBeanFactory.getAliases(anyString())).thenReturn(new String[0]);
beanFactoryLocator = GemfireBeanFactoryLocator.newBeanFactoryLocator(this.mockBeanFactory,
"testBeanFactory");
assertThat(this.dataSerializer.locateBeanFactory().orElse(null)).isSameAs(this.mockBeanFactory);
}
finally {
verify(this.mockBeanFactory, times(1)).getAliases(eq("testBeanFactory"));
Optional.ofNullable(beanFactoryLocator).ifPresent(GemfireBeanFactoryLocator::destroy);
}
}
@Test
public void unableToLocateBeanFactory() {
assertThat(this.dataSerializer.locateBeanFactory().orElse(null)).isNull();
}
@Test
public void constructsNewBeanConfigurerSupportWithBeanFactory() {
BeanConfigurerSupport beanConfigurer = null;
try {
beanConfigurer = this.dataSerializer.newBeanConfigurer(this.mockBeanFactory);
assertThat(beanConfigurer).isNotNull();
}
finally {
Optional.ofNullable(beanConfigurer).ifPresent(BeanConfigurerSupport::destroy);
}
}
}

View File

@@ -0,0 +1,147 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire.serialization.pdx;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSession;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import org.apache.geode.pdx.PdxReader;
import org.apache.geode.pdx.PdxWriter;
import org.springframework.session.Session;
/**
* Unit tests for {@link AbstractPdxSerializableSessionSerializer}.
*
* @author John Blum
* @see org.junit.Test
* @see org.mockito.Mock
* @see org.mockito.Mockito
* @see org.mockito.Spy
* @see org.apache.geode.pdx.PdxReader
* @see org.apache.geode.pdx.PdxWriter
* @see org.springframework.session.Session
* @see org.springframework.session.data.gemfire.serialization.pdx.AbstractPdxSerializableSessionSerializer
* @since 2.0.0
*/
@RunWith(MockitoJUnitRunner.class)
public class AbstractPdxSerializableSessionSerializerTests {
@Spy
private AbstractPdxSerializableSessionSerializer<Session> sessionSerializer;
@Mock
private PdxReader mockPdxReader;
@Mock
private PdxWriter mockPdxWriter;
@Mock
private Session mockSession;
@Test
public void toDataSerializesSessionAndReturnsTrue() {
when(this.sessionSerializer.canSerialize(any(Object.class))).thenReturn(true);
assertThat(this.sessionSerializer.toData(this.mockSession, this.mockPdxWriter)).isTrue();
verify(this.sessionSerializer, times(1))
.serialize(eq(this.mockSession), eq(this.mockPdxWriter));
}
@Test
public void toDataWithNonSerializableObjectReturnsFalse() {
when(this.sessionSerializer.canSerialize(any(Object.class))).thenReturn(false);
assertThat(this.sessionSerializer.toData("test", this.mockPdxWriter)).isFalse();
verify(this.sessionSerializer, never()).serialize(any(), any(PdxWriter.class));
}
@Test
public void toDataWithNullReturnsFalse() {
assertThat(this.sessionSerializer.toData(null, this.mockPdxWriter)).isFalse();
verify(this.sessionSerializer, never()).serialize(any(), any(PdxWriter.class));
}
@Test
public void fromDataWithSessionTypeReturnsSessionObject() {
when(this.sessionSerializer.deserialize(eq(this.mockPdxReader))).thenReturn(this.mockSession);
assertThat(this.sessionSerializer.fromData(Session.class, this.mockPdxReader)).isEqualTo(this.mockSession);
verify(this.sessionSerializer, times(1)).canSerialize(eq(Session.class));
verify(this.sessionSerializer, times(1)).deserialize(eq(this.mockPdxReader));
}
@Test
public void fromDataWithNonSerializableTypeReturnsNull() {
when(this.sessionSerializer.canSerialize(any(Class.class))).thenReturn(false);
assertThat(this.sessionSerializer.fromData(Object.class, this.mockPdxReader)).isNull();
verify(this.sessionSerializer, times(1)).canSerialize(eq(Object.class));
verify(this.sessionSerializer, never()).deserialize(any(PdxReader.class));
}
@Test
public void fromDataWithNullReturnsNull() {
assertThat(this.sessionSerializer.fromData(null, this.mockPdxReader)).isNull();
verify(this.sessionSerializer, never()).canSerialize(any());
verify(this.sessionSerializer, never()).deserialize(any(PdxReader.class));
}
@Test
public void canSerializeSessionIsTrue() {
assertThat(this.sessionSerializer.canSerialize(Session.class)).isTrue();
}
@Test
public void canSerializeGemFireSessionIsTrue() {
assertThat(this.sessionSerializer.canSerialize(GemFireSession.class)).isTrue();
}
@Test
public void canSerializeObjectIsFalse() {
assertThat(this.sessionSerializer.canSerialize(Object.class)).isFalse();
}
@Test
public void canSerializeNullIsFalse() {
assertThat(this.sessionSerializer.canSerialize(null)).isFalse();
}
}

View File

@@ -0,0 +1,165 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire.serialization.pdx.provider;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.DeltaCapableGemFireSession;
import static org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSession;
import java.time.Duration;
import java.time.Instant;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.apache.geode.pdx.PdxReader;
import org.apache.geode.pdx.PdxWriter;
import org.springframework.session.FindByIndexNameSessionRepository;
/**
* The PdxSerializableSessionSerializerTests class...
*
* @author John Blum
* @since 1.0.0
*/
@RunWith(MockitoJUnitRunner.class)
public class PdxSerializableSessionSerializerTests {
@Mock
private PdxReader mockPdxReader;
@Mock
private PdxWriter mockPdxWriter;
private PdxSerializableSessionSerializer sessionSerializer = new PdxSerializableSessionSerializer();
@Test
public void serializeSessionIsCorrect() {
GemFireSession session = GemFireSession.create();
session.setMaxInactiveInterval(Duration.ofMinutes(30));
session.setAttribute("attributeOne", "valueOne");
session.setAttribute("attributeTwo", "valueTwo");
this.sessionSerializer.serialize(session, this.mockPdxWriter);
verify(this.mockPdxWriter, times(1))
.writeString(eq("id"), eq(session.getId()));
verify(this.mockPdxWriter, times(1))
.writeLong(eq("creationTime"), eq(session.getCreationTime().toEpochMilli()));
verify(this.mockPdxWriter, times(1))
.writeLong(eq("lastAccessedTime"), eq(session.getLastAccessedTime().toEpochMilli()));
verify(this.mockPdxWriter, times(1))
.writeLong(eq("maxInactiveIntervalInSeconds"), eq(session.getMaxInactiveInterval().getSeconds()));
verify(this.mockPdxWriter, times(1))
.writeString(eq("principalName"), eq(session.getPrincipalName()));
verify(this.mockPdxWriter, times(1))
.writeObject(eq("attributes"), eq(new HashMap<>(session.getAttributes())));
}
@Test
public void newMapCopiesMap() {
Map<String, String> mapCopy = this.sessionSerializer.newMap(Collections.singletonMap("testKey", "testValue"));
assertThat(mapCopy).isInstanceOf(HashMap.class);
assertThat(mapCopy).hasSize(1);
assertThat(mapCopy).containsKey("testKey");
assertThat(mapCopy.get("testKey")).isEqualTo("testValue");
}
@Test
@SuppressWarnings("unchecked")
public void deserializeSessionIsCorrect() {
Duration expectedMaxInactiveInterval = Duration.ofMinutes(30);
Instant expectedCreationTime = Instant.now();
Instant expectedLastAccessedTime = Instant.now();
Map<String, String> expectedAttributes = new HashMap<>(2);
expectedAttributes.put("attributeOne", "valueOne");
expectedAttributes.put("attributeTwo", "valueTwo");
expectedAttributes.put(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, "jonDoe");
when(this.mockPdxReader.readString(eq("id"))).thenReturn("123");
when(this.mockPdxReader.readLong(eq("creationTime"))).thenReturn(expectedCreationTime.toEpochMilli());
when(this.mockPdxReader.readLong(eq("lastAccessedTime")))
.thenReturn(expectedLastAccessedTime.toEpochMilli());
when(this.mockPdxReader.readLong(eq("maxInactiveIntervalInSeconds")))
.thenReturn(expectedMaxInactiveInterval.getSeconds());
when(this.mockPdxReader.readString(eq("principalName"))).thenReturn("jonDoe");
when(this.mockPdxReader.readObject(eq("attributes"))).thenReturn(expectedAttributes);
GemFireSession session = this.sessionSerializer.deserialize(this.mockPdxReader);
assertThat(session).isNotNull();
assertThat(session.getId()).isEqualTo("123");
assertThat(session.getCreationTime()).isEqualTo(expectedCreationTime);
assertThat(session.getLastAccessedTime()).isEqualTo(expectedLastAccessedTime);
assertThat(session.getMaxInactiveInterval()).isEqualTo(expectedMaxInactiveInterval);
assertThat(session.getPrincipalName()).isEqualTo("jonDoe");
assertThat(this.sessionSerializer.newMap(session.getAttributes())).isEqualTo(expectedAttributes);
verify(this.mockPdxReader, times(1)).readString(eq("id"));
verify(this.mockPdxReader, times(1)).readLong(eq("creationTime"));
verify(this.mockPdxReader, times(1)).readLong(eq("lastAccessedTime"));
verify(this.mockPdxReader, times(1)).readLong(eq("maxInactiveIntervalInSeconds"));
verify(this.mockPdxReader, times(1)).readString(eq("principalName"));
verify(this.mockPdxReader, times(1)).readObject(eq("attributes"));
}
@Test
public void canSerializeGemFireSessionClassTypeIsTrue() {
assertThat(this.sessionSerializer.canSerialize(GemFireSession.class)).isTrue();
}
@Test
public void canSerializeDeltaCapableGemFireSessionClassTypeIsTrue() {
assertThat(this.sessionSerializer.canSerialize(DeltaCapableGemFireSession.class)).isTrue();
}
@Test
public void canSerializeObjectClassTypeIsFalse() {
assertThat(this.sessionSerializer.canSerialize(Object.class)).isFalse();
}
@Test
public void canSerializeNullClassTypeIsFalse() {
assertThat(this.sessionSerializer.canSerialize(null)).isFalse();
}
}

View File

@@ -0,0 +1,219 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire.serialization.pdx.support;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Arrays;
import java.util.Collections;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.apache.geode.pdx.PdxReader;
import org.apache.geode.pdx.PdxSerializer;
import org.apache.geode.pdx.PdxWriter;
/**
* Unit tests for {@link ComposablePdxSerializer}.
*
* @author John Blum
* @see org.junit.Test
* @see org.mockito.Mock
* @see org.mockito.Mockito
* @see org.apache.geode.pdx.PdxReader
* @see org.apache.geode.pdx.PdxSerializer
* @see org.apache.geode.pdx.PdxWriter
* @see org.springframework.session.data.gemfire.serialization.pdx.support.ComposablePdxSerializer
* @since 2.0.0
*/
@RunWith(MockitoJUnitRunner.class)
public class ComposablePdxSerializerTests {
@Mock
private PdxReader mockPdxReader;
@Mock
private PdxWriter mockPdxWriter;
@Mock
private PdxSerializer mockPdxSerializerOne;
@Mock
private PdxSerializer mockPdxSerializerTwo;
@Test
public void composeArrayWithTwoPdxSerializers() {
PdxSerializer pdxSerializer =
ComposablePdxSerializer.compose(this.mockPdxSerializerOne, this.mockPdxSerializerTwo);
assertThat(pdxSerializer).isInstanceOf(ComposablePdxSerializer.class);
assertThat((ComposablePdxSerializer) pdxSerializer)
.contains(this.mockPdxSerializerOne, this.mockPdxSerializerTwo);
}
@Test
public void composeArrayWithOnePdxSerializer() {
assertThat(ComposablePdxSerializer.compose(this.mockPdxSerializerOne)).isSameAs(this.mockPdxSerializerOne);
}
@Test
public void composeArrayWithNoPdxSerializers() {
assertThat(ComposablePdxSerializer.compose()).isNull();
}
@Test
public void composeIterableWithTwoPdxSerializers() {
PdxSerializer pdxSerializer =
ComposablePdxSerializer.compose(Arrays.asList(this.mockPdxSerializerOne, this.mockPdxSerializerTwo));
assertThat(pdxSerializer).isInstanceOf(ComposablePdxSerializer.class);
assertThat((ComposablePdxSerializer) pdxSerializer)
.contains(this.mockPdxSerializerOne, this.mockPdxSerializerTwo);
}
@Test
public void composeIterableWithOnePdxSerializer() {
assertThat(ComposablePdxSerializer.compose(Collections.singleton(this.mockPdxSerializerTwo)))
.isSameAs(this.mockPdxSerializerTwo);
}
@Test
public void composeIterableWithNoPdxSerializers() {
assertThat(ComposablePdxSerializer.compose(Collections.emptyList())).isNull();
}
@Test
public void toDataSerializesObjectWithFirstPdxSerializer() {
when(this.mockPdxSerializerOne.toData(any(), any(PdxWriter.class))).thenReturn(true);
PdxSerializer pdxSerializer =
ComposablePdxSerializer.compose(this.mockPdxSerializerOne, this.mockPdxSerializerTwo);
assertThat(pdxSerializer).isNotNull();
assertThat(pdxSerializer.toData("test", this.mockPdxWriter)).isTrue();
verify(this.mockPdxSerializerOne, times(1))
.toData(eq("test"), eq(this.mockPdxWriter));
verify(this.mockPdxSerializerTwo, never()).toData(any(), any(PdxWriter.class));
}
@Test
public void toDataSerializesObjectWithSecondPdxSerializer() {
when(this.mockPdxSerializerOne.toData(any(), any(PdxWriter.class))).thenReturn(false);
when(this.mockPdxSerializerTwo.toData(any(), any(PdxWriter.class))).thenReturn(true);
PdxSerializer pdxSerializer =
ComposablePdxSerializer.compose(this.mockPdxSerializerOne, this.mockPdxSerializerTwo);
assertThat(pdxSerializer).isNotNull();
assertThat(pdxSerializer.toData("test", this.mockPdxWriter)).isTrue();
verify(this.mockPdxSerializerOne, times(1))
.toData(eq("test"), eq(this.mockPdxWriter));
verify(this.mockPdxSerializerTwo, times(1))
.toData(eq("test"), eq(this.mockPdxWriter));
}
@Test
public void toDataCannotSerializeObject() {
when(this.mockPdxSerializerOne.toData(any(), any(PdxWriter.class))).thenReturn(false);
when(this.mockPdxSerializerTwo.toData(any(), any(PdxWriter.class))).thenReturn(false);
PdxSerializer pdxSerializer =
ComposablePdxSerializer.compose(this.mockPdxSerializerOne, this.mockPdxSerializerTwo);
assertThat(pdxSerializer).isNotNull();
assertThat(pdxSerializer.toData("test", this.mockPdxWriter)).isFalse();
verify(this.mockPdxSerializerOne, times(1))
.toData(eq("test"), eq(this.mockPdxWriter));
verify(this.mockPdxSerializerTwo, times(1))
.toData(eq("test"), eq(this.mockPdxWriter));
}
@Test
public void fromDataDeserializesObjectWithFirstPdxSerializer() {
when(this.mockPdxSerializerOne.fromData(any(Class.class), any(PdxReader.class))).thenReturn("test");
PdxSerializer pdxSerializer =
ComposablePdxSerializer.compose(this.mockPdxSerializerOne, this.mockPdxSerializerTwo);
assertThat(pdxSerializer).isNotNull();
assertThat(pdxSerializer.fromData(Object.class, this.mockPdxReader)).isEqualTo("test");
verify(this.mockPdxSerializerOne, times(1))
.fromData(eq(Object.class), eq(this.mockPdxReader));
verify(this.mockPdxSerializerTwo, never()).fromData(any(Class.class), any(PdxReader.class));
}
@Test
public void fromDataDeserializesObjectWithSecondPdxSerializer() {
when(this.mockPdxSerializerOne.fromData(any(Class.class), any(PdxReader.class))).thenReturn(null);
when(this.mockPdxSerializerTwo.fromData(any(Class.class), any(PdxReader.class))).thenReturn("two");
PdxSerializer pdxSerializer =
ComposablePdxSerializer.compose(this.mockPdxSerializerOne, this.mockPdxSerializerTwo);
assertThat(pdxSerializer).isNotNull();
assertThat(pdxSerializer.fromData(Object.class, this.mockPdxReader)).isEqualTo("two");
verify(this.mockPdxSerializerOne, times(1))
.fromData(eq(Object.class), eq(this.mockPdxReader));
verify(this.mockPdxSerializerTwo, times(1))
.fromData(eq(Object.class), eq(this.mockPdxReader));
}
@Test
public void fromDataCannotDeserializeObject() {
when(this.mockPdxSerializerOne.fromData(any(Class.class), any(PdxReader.class))).thenReturn(null);
when(this.mockPdxSerializerTwo.fromData(any(Class.class), any(PdxReader.class))).thenReturn(null);
PdxSerializer pdxSerializer =
ComposablePdxSerializer.compose(this.mockPdxSerializerOne, this.mockPdxSerializerTwo);
assertThat(pdxSerializer).isNotNull();
assertThat(pdxSerializer.fromData(Object.class, this.mockPdxReader)).isNull();
verify(this.mockPdxSerializerOne, times(1))
.fromData(eq(Object.class), eq(this.mockPdxReader));
verify(this.mockPdxSerializerTwo, times(1))
.fromData(eq(Object.class), eq(this.mockPdxReader));
}
}

View File

@@ -0,0 +1,139 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire.serialization.pdx.support;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.apache.geode.pdx.PdxReader;
import org.apache.geode.pdx.PdxWriter;
import org.springframework.session.Session;
import org.springframework.session.data.gemfire.serialization.SessionSerializer;
/**
* Unit tests for {@link PdxSerializerSessionSerializerAdapter}.
*
* @author John Blum
* @see org.junit.Test
* @see org.mockito.Mock
* @see org.mockito.Mockito
* @see org.apache.geode.pdx.PdxReader
* @see org.apache.geode.pdx.PdxWriter
* @see org.springframework.session.Session
* @see org.springframework.session.data.gemfire.serialization.pdx.support.PdxSerializerSessionSerializerAdapter
* @since 2.0.0
*/
@RunWith(MockitoJUnitRunner.class)
public class PdxSerializerSessionSerializerAdapterTests {
@Mock
private PdxReader mockPdxReader;
@Mock
private PdxWriter mockPdxWriter;
@Mock
private Session mockSession;
@Mock
private SessionSerializer<Session, PdxReader, PdxWriter> mockSessionSerializer;
@Test
public void constructPdxSerializerSessionSerializerAdapterWithSessionSerializer() {
PdxSerializerSessionSerializerAdapter<Session> sessionSerializerAdapter =
new PdxSerializerSessionSerializerAdapter<>(this.mockSessionSerializer);
assertThat(sessionSerializerAdapter).isNotNull();
assertThat(sessionSerializerAdapter.getSessionSerializer()).isSameAs(this.mockSessionSerializer);
}
@Test(expected = IllegalArgumentException.class)
public void constructPdxSerializerSessionSerializerAdapterWithNull() {
try {
new PdxSerializerSessionSerializerAdapter<>(null);
}
catch (IllegalArgumentException expected) {
assertThat(expected).hasMessage("SessionSerializer is required");
assertThat(expected).hasNoCause();
throw expected;
}
}
@Test
public void serializeSessionCallsSessionSerializerSerialize() {
PdxSerializerSessionSerializerAdapter<Session> sessionSerializerAdapter =
new PdxSerializerSessionSerializerAdapter<>(this.mockSessionSerializer);
sessionSerializerAdapter.serialize(this.mockSession, this.mockPdxWriter);
verify(this.mockSessionSerializer, times(1))
.serialize(eq(this.mockSession), eq(this.mockPdxWriter));
}
@Test
public void deserializeSessionCallsSessionSerializerDeserialize() {
when(this.mockSessionSerializer.deserialize(any(PdxReader.class))).thenReturn(this.mockSession);
PdxSerializerSessionSerializerAdapter<Session> sessionSerializerAdapter =
new PdxSerializerSessionSerializerAdapter<>(this.mockSessionSerializer);
assertThat(sessionSerializerAdapter.deserialize(this.mockPdxReader)).isEqualTo(this.mockSession);
verify(this.mockSessionSerializer, times(1)).deserialize(eq(this.mockPdxReader));
}
@Test
public void toDataSerializesSessionWithSessionSerializer() {
PdxSerializerSessionSerializerAdapter<Session> sessionSerializerAdapter =
new PdxSerializerSessionSerializerAdapter<>(this.mockSessionSerializer);
sessionSerializerAdapter.toData(this.mockSession, this.mockPdxWriter);
verify(this.mockSessionSerializer, times(1))
.serialize(eq(this.mockSession), eq(this.mockPdxWriter));
}
@Test
public void fromDataDeserializesSessionWithSessionSerializer() {
when(this.mockSessionSerializer.deserialize(any(PdxReader.class))).thenReturn(this.mockSession);
PdxSerializerSessionSerializerAdapter<Session> sessionSerializerAdapter =
new PdxSerializerSessionSerializerAdapter<>(this.mockSessionSerializer);
assertThat(sessionSerializerAdapter.fromData(Session.class, this.mockPdxReader)).isEqualTo(this.mockSession);
verify(this.mockSessionSerializer, times(1)).deserialize(eq(this.mockPdxReader));
}
}