/*
* Copyright 2012 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.data.gemfire.mapping;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.isA;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.atMost;
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.RuntimeExceptionFactory.newIllegalArgumentException;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException;
import java.util.Collections;
import org.apache.geode.pdx.PdxReader;
import org.apache.geode.pdx.PdxSerializer;
import org.apache.geode.pdx.PdxWriter;
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.junit.MockitoJUnitRunner;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.data.convert.EntityInstantiator;
import org.springframework.data.gemfire.repository.sample.Address;
import org.springframework.data.gemfire.repository.sample.Person;
import org.springframework.data.mapping.model.MappingException;
import org.springframework.data.mapping.model.ParameterValueProvider;
/**
* Unit tests for {@link MappingPdxSerializer}.
*
* @author Oliver Gierke
* @author John Blum
* @see org.junit.Rule
* @see org.junit.Test
* @see org.junit.rules.ExpectedException
* @see org.junit.runner.RunWith
* @see org.mockito.Mock
* @see org.mockito.Mockito
* @see org.mockito.runners.MockitoJUnitRunner
* @see org.springframework.core.convert.ConversionService
* @see org.springframework.data.gemfire.mapping.MappingPdxSerializer
* @see org.apache.geode.pdx.PdxReader
* @see org.apache.geode.pdx.PdxSerializer
* @see org.apache.geode.pdx.PdxWriter
*/
@RunWith(MockitoJUnitRunner.class)
public class MappingPdxSerializerUnitTests {
ConversionService conversionService;
GemfireMappingContext context;
MappingPdxSerializer serializer;
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Mock
EntityInstantiator mockInstantiator;
@Mock
PdxReader mockReader;
@Mock
PdxSerializer mockAddressSerializer;
@Mock
PdxWriter mockWriter;
@Before
public void setUp() {
context = new GemfireMappingContext();
conversionService = new GenericConversionService();
serializer = new MappingPdxSerializer(context, conversionService);
serializer.setCustomSerializers(Collections.singletonMap(Address.class, mockAddressSerializer));
}
@Test
public void createFullyInitialized() {
ConversionService mockConversionService = mock(ConversionService.class);
GemfireMappingContext mockMappingContext = mock(GemfireMappingContext.class);
MappingPdxSerializer pdxSerializer = MappingPdxSerializer.create(mockMappingContext, mockConversionService);
assertThat(pdxSerializer).isNotNull();
assertThat(pdxSerializer.getConversionService()).isEqualTo(mockConversionService);
assertThat(pdxSerializer.getMappingContext()).isEqualTo(mockMappingContext);
}
@Test
public void createWithNullConversionService() {
GemfireMappingContext mockMappingContext = mock(GemfireMappingContext.class);
MappingPdxSerializer pdxSerializer = MappingPdxSerializer.create(mockMappingContext, null);
assertThat(pdxSerializer).isNotNull();
assertThat(pdxSerializer.getConversionService()).isInstanceOf(ConversionService.class);
assertThat(pdxSerializer.getMappingContext()).isEqualTo(mockMappingContext);
}
@Test
public void createWithNullMappingContext() {
ConversionService mockConversionService = mock(ConversionService.class);
MappingPdxSerializer pdxSerializer = MappingPdxSerializer.create(null, mockConversionService);
assertThat(pdxSerializer).isNotNull();
assertThat(pdxSerializer.getConversionService()).isEqualTo(mockConversionService);
assertThat(pdxSerializer.getMappingContext()).isInstanceOf(GemfireMappingContext.class);
}
@Test
public void createWithNullConversionServiceAndNullMappingContext() {
MappingPdxSerializer pdxSerializer = MappingPdxSerializer.create(null, null);
assertThat(pdxSerializer).isNotNull();
assertThat(pdxSerializer.getConversionService()).isInstanceOf(ConversionService.class);
assertThat(pdxSerializer.getMappingContext()).isInstanceOf(GemfireMappingContext.class);
}
@Test
@SuppressWarnings("unchecked")
public void usesRegisteredInstantiator() {
Address address = new Address();
address.city = "London";
address.zipCode = "01234";
Person person = new Person(1L, "Oliver", "Gierke");
person.address = address;
when(mockInstantiator.createInstance(any(GemfirePersistentEntity.class), any(ParameterValueProvider.class)))
.thenReturn(person);
serializer.setGemfireInstantiators(Collections.singletonMap(Person.class, mockInstantiator));
serializer.fromData(Person.class, mockReader);
GemfirePersistentEntity<?> persistentEntity = context.getPersistentEntity(Person.class)
.orElseThrow(() -> newIllegalStateException("Unable to resolve PersistentEntity for type [%s]",
Person.class.getName()));
verify(mockInstantiator, times(1)).createInstance(eq(persistentEntity),
any(ParameterValueProvider.class));
verify(mockAddressSerializer, times(1)).fromData(eq(Address.class), any(PdxReader.class));
}
@Test
@SuppressWarnings("unchecked")
public void fromDataMapsPdxDataToApplicationDomainObject() {
Address expectedAddress = new Address();
expectedAddress.city = "Portland";
expectedAddress.zipCode = "12345";
when(mockInstantiator.createInstance(any(GemfirePersistentEntity.class), any(ParameterValueProvider.class)))
.thenReturn(new Person(null, null, null));
when(mockReader.readField(eq("id"))).thenReturn(1L);
when(mockReader.readField(eq("firstname"))).thenReturn("Jon");
when(mockReader.readField(eq("lastname"))).thenReturn("Doe");
when(mockAddressSerializer.fromData(eq(Address.class), eq(mockReader))).thenReturn(expectedAddress);
serializer.setGemfireInstantiators(Collections.singletonMap(Person.class, mockInstantiator));
Object obj = serializer.fromData(Person.class, mockReader);
assertThat(obj).isInstanceOf(Person.class);
Person jonDoe = (Person) obj;
assertThat(jonDoe.getAddress()).isEqualTo(expectedAddress);
assertThat(jonDoe.getId()).isEqualTo(1L);
assertThat(jonDoe.getFirstname()).isEqualTo("Jon");
assertThat(jonDoe.getLastname()).isEqualTo("Doe");
verify(mockInstantiator, times(1)).createInstance(any(GemfirePersistentEntity.class), any(ParameterValueProvider.class));
verify(mockReader, times(1)).readField(eq("id"));
verify(mockReader, times(1)).readField(eq("firstname"));
verify(mockReader, times(1)).readField(eq("lastname"));
verify(mockAddressSerializer, times(1)).fromData(eq(Address.class), eq(mockReader));
}
@Test
@SuppressWarnings("unchecked")
public void fromDataHandlesExceptionProperly() {
when(mockInstantiator.createInstance(any(GemfirePersistentEntity.class), any(ParameterValueProvider.class)))
.thenReturn(new Person(null, null, null));
when(mockReader.readField(eq("id"))).thenThrow(newIllegalArgumentException("test"));
serializer.setGemfireInstantiators(Collections.singletonMap(Person.class, mockInstantiator));
try {
expectedException.expect(MappingException.class);
expectedException.expectCause(isA(IllegalArgumentException.class));
expectedException.expectMessage(String.format(
"While setting value [null] of property [id] for entity of type [%s] from PDX", Person.class));
serializer.fromData(Person.class, mockReader);
}
finally {
verify(mockInstantiator, times(1))
.createInstance(any(GemfirePersistentEntity.class), any(ParameterValueProvider.class));
verify(mockReader, times(1)).readField(eq("id"));
}
}
@Test
public void toDataSerializesApplicationDomainObjectToPdx() {
Address address = new Address();
address.city = "Portland";
address.zipCode = "12345";
Person jonDoe = new Person(1L, "Jon", "Doe");
jonDoe.address = address;
serializer.setCustomSerializers(Collections.singletonMap(Address.class, mockAddressSerializer));
assertThat(serializer.toData(jonDoe, mockWriter)).isTrue();
verify(mockAddressSerializer, times(1)).toData(eq(address), eq(mockWriter));
verify(mockWriter, times(1)).writeField(eq("id"), eq(1L), eq(Long.class));
verify(mockWriter, times(1)).writeField(eq("firstname"), eq("Jon"), eq(String.class));
verify(mockWriter, times(1)).writeField(eq("lastname"), eq("Doe"), eq(String.class));
verify(mockWriter, times(1)).markIdentityField(eq("id"));
}
@Test
public void toDataHandlesExceptionProperly() {
Address address = new Address();
address.city = "Portland";
address.zipCode = "12345";
Person jonDoe = new Person(1L, "Jon", "Doe");
jonDoe.address = address;
when(mockWriter.writeField(eq("address"), eq(address), eq(Address.class)))
.thenThrow(newIllegalArgumentException("test"));
try {
expectedException.expect(MappingException.class);
expectedException.expectCause(isA(IllegalArgumentException.class));
expectedException.expectMessage(String.format(
"While serializing entity property [address] value [Portland, 12345] of type [%s] to PDX",
Person.class));
new MappingPdxSerializer(context, conversionService).toData(jonDoe, mockWriter);
}
finally {
verify(mockWriter, atMost(1)).writeField(eq("id"), eq(1L), eq(Long.class));
verify(mockWriter, atMost(1)).writeField(eq("firstname"), eq("Jon"), eq(String.class));
verify(mockWriter, atMost(1)).writeField(eq("lastname"), eq("Doe"), eq(String.class));
verify(mockWriter, times(1)).writeField(eq("address"), eq(address), eq(Address.class));
verify(mockWriter, never()).markIdentityField(anyString());
}
}
}