Refactor JsonCacheDataImporterExporter to extend ResourceCapableCacheDataImporterExporter.

Change doImportInto(:Region) logic to make use of the ImportResourceResolver and ResourceReader on import.

Change doExportFrom(:Region) logic to make use of the ExportResourceResolver and ResourceWriter on export.

Resolves gh-92.
This commit is contained in:
John Blum
2020-07-20 13:25:26 -07:00
parent 4bf62d9bf0
commit 2d1cc28188
4 changed files with 404 additions and 632 deletions

View File

@@ -42,7 +42,6 @@ import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -58,17 +57,21 @@ import org.apache.geode.pdx.PdxInstanceFactory;
import org.apache.geode.pdx.PdxSerializationException;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.data.gemfire.LocalRegionFactoryBean;
import org.springframework.data.gemfire.config.annotation.EnablePdx;
import org.springframework.data.gemfire.config.annotation.PeerCacheApplication;
import org.springframework.data.gemfire.tests.integration.IntegrationTestsSupport;
import org.springframework.data.gemfire.tests.integration.SpringApplicationContextIntegrationTestsSupport;
import org.springframework.geode.core.io.ResourceWriteException;
import org.springframework.geode.core.io.ResourceWriter;
import org.springframework.geode.core.util.ObjectUtils;
import org.springframework.geode.data.support.ResourceCapableCacheDataImporterExporter.ImportResourceResolver;
import org.springframework.geode.pdx.PdxInstanceBuilder;
import org.springframework.lang.NonNull;
import org.springframework.mock.env.MockPropertySource;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;
@@ -78,11 +81,12 @@ import example.app.pos.model.Product;
import example.app.pos.model.PurchaseOrder;
/**
* Integration Test for {@link JsonCacheDataImporterExporter}.
* Integration Tests for {@link JsonCacheDataImporterExporter}.
*
* @author John Blum
* @see org.junit.Test
* @see com.fasterxml.jackson.databind.ObjectMapper
* @see com.fasterxml.jackson.databind.node.ObjectNode
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.RegionService
@@ -90,65 +94,58 @@ import example.app.pos.model.PurchaseOrder;
* @see org.apache.geode.pdx.PdxInstance
* @see org.apache.geode.pdx.PdxInstanceFactory
* @see org.springframework.context.ConfigurableApplicationContext
* @see org.springframework.context.annotation.AnnotationConfigApplicationContext
* @see org.springframework.context.annotation.Bean
* @see org.springframework.core.io.ClassPathResource
* @see org.springframework.core.io.Resource
* @see org.springframework.data.gemfire.LocalRegionFactoryBean
* @see org.springframework.data.gemfire.config.annotation.EnablePdx
* @see org.springframework.data.gemfire.config.annotation.PeerCacheApplication
* @see org.springframework.data.gemfire.tests.integration.IntegrationTestsSupport
* @see org.springframework.data.gemfire.tests.integration.SpringApplicationContextIntegrationTestsSupport
* @see org.springframework.geode.pdx.PdxInstanceBuilder
* @since 1.3.0
*/
@SuppressWarnings("unused")
public class JsonCacheDataImporterExporterIntegrationTests extends IntegrationTestsSupport {
public class JsonCacheDataImporterExporterIntegrationTests extends SpringApplicationContextIntegrationTestsSupport {
private static final String EXPORT_ENABLED_PROPERTY = "spring.boot.data.gemfire.cache.data.export.enabled";
private static final String EXPORT_RESOURCE_LOCATION_PROPERTY = "spring.boot.data.gemfire.cache.data.export.resource.location";
private static final String IMPORT_ENABLED_PROPERTY = "spring.boot.data.gemfire.cache.data.import.enabled";
private static final String IMPORT_RESOURCE_LOCATION_PROPERTY = "spring.boot.data.gemfire.cache.data.import.resource.location";
private static volatile Supplier<Resource> resourceSupplier;
private static volatile Supplier<StringWriter> writerSupplier;
private ConfigurableApplicationContext applicationContext;
private static volatile Supplier<Boolean> exportEnabledSupplier;
private static volatile Supplier<Boolean> importEnabledSupplier;
private static volatile Supplier<ImportResourceResolver> importResourceResolverSupplier;
private static volatile Supplier<String> resourceLocationSupplier;
private static volatile Supplier<StringWriter> resourceWriterSupplier;
@Before
public void initializeSuppliers() {
resourceSupplier = () -> null;
writerSupplier = StringWriter::new;
exportEnabledSupplier = () -> false;
importEnabledSupplier = () -> true;
importResourceResolverSupplier = () -> null;
resourceLocationSupplier = () -> "";
resourceWriterSupplier = StringWriter::new;
}
@After
public void closeApplicationContext() {
@Override
protected ConfigurableApplicationContext processBeforeRefresh(ConfigurableApplicationContext applicationContext) {
Optional.ofNullable(this.applicationContext)
.ifPresent(ConfigurableApplicationContext::close);
applicationContext = super.processBeforeRefresh(applicationContext);
this.applicationContext = null;
}
MutablePropertySources propertySources = applicationContext.getEnvironment().getPropertySources();
private ConfigurableApplicationContext newApplicationContext(Class<?>... componentClasses) {
MockPropertySource mockPropertySource = new MockPropertySource(getClass().getName().concat(".MockPropertySource"))
.withProperty(EXPORT_ENABLED_PROPERTY, exportEnabledSupplier.get())
.withProperty(EXPORT_RESOURCE_LOCATION_PROPERTY, resourceLocationSupplier.get())
.withProperty(IMPORT_ENABLED_PROPERTY, importEnabledSupplier.get())
.withProperty(IMPORT_RESOURCE_LOCATION_PROPERTY, resourceLocationSupplier.get());
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(componentClasses);
applicationContext.registerShutdownHook();
applicationContext.refresh();
this.applicationContext = applicationContext;
propertySources.addFirst(mockPropertySource);
return applicationContext;
}
private Class<?>[] withResource(String path) {
if (StringUtils.hasText(path)) {
resourceSupplier = () -> new ClassPathResource(path);
}
return new Class[] { TestGeodeConfiguration.class };
}
private <K, V> Region<K, V> assertExampleRegion(Region<K, V> example) {
assertThat(example).isNotNull();
@@ -168,7 +165,9 @@ public class JsonCacheDataImporterExporterIntegrationTests extends IntegrationTe
@Test
public void exampleRegionContainsJonDoe() {
Region<?, ?> example = getExampleRegion(newApplicationContext(withResource("data-example-jondoe.json")));
resourceLocationSupplier = () -> "classpath:data-#{#regionName}-jondoe.json";
Region<?, ?> example = getExampleRegion(newApplicationContext(TestGeodeConfiguration.class));
assertThat(example).hasSize(1);
@@ -194,8 +193,9 @@ public class JsonCacheDataImporterExporterIntegrationTests extends IntegrationTe
@Test
public void exampleRegionContainsDoeFamily() {
Region<?, ?> example =
getExampleRegion(newApplicationContext(withResource("data-example-doefamily.json")));
resourceLocationSupplier = () -> "classpath:data-#{#regionName}-doefamily.json";
Region<?, ?> example = getExampleRegion(newApplicationContext(TestGeodeConfiguration.class));
assertThat(example).hasSize(9);
@@ -319,8 +319,9 @@ public class JsonCacheDataImporterExporterIntegrationTests extends IntegrationTe
@Test
public void exampleRegionContainsComplexPurchaseOrderType() {
Region<?, ?> example =
getExampleRegion(newApplicationContext(withResource("data-example-purchaseorder.json")));
resourceLocationSupplier = () -> "classpath:data-#{#regionName}-purchaseorder.json";
Region<?, ?> example = getExampleRegion(newApplicationContext(TestGeodeConfiguration.class));
assertThat(example).hasSize(1);
@@ -345,14 +346,14 @@ public class JsonCacheDataImporterExporterIntegrationTests extends IntegrationTe
public void exportFromExampleRegionToJson() {
try {
System.setProperty(EXPORT_ENABLED_PROPERTY, Boolean.TRUE.toString());
StringWriter writer = new StringWriter();
writerSupplier = () -> writer;
exportEnabledSupplier = () -> true;
importEnabledSupplier = () -> false;
resourceWriterSupplier = () -> writer;
Region<Long, Customer> example =
getExampleRegion(newApplicationContext(withResource("data-example.json")));
Region<Long, Customer> example = getExampleRegion(newApplicationContext(TestGeodeConfiguration.class));
assertExampleRegion(example);
assertThat(example).isEmpty();
@@ -381,137 +382,125 @@ public class JsonCacheDataImporterExporterIntegrationTests extends IntegrationTe
@Test
public void exportFromExampleRegionImportsIntoExampleRegion() throws IOException {
try {
// EXPORT
System.setProperty(EXPORT_ENABLED_PROPERTY, Boolean.TRUE.toString());
// EXPORT
StringWriter writer = new StringWriter();
StringWriter writer = new StringWriter();
exportEnabledSupplier = () -> true;
importEnabledSupplier = () -> false;
resourceWriterSupplier = () -> writer;
writerSupplier = () -> writer;
Region<Long, PurchaseOrder> example = getExampleRegion(newApplicationContext(TestGeodeConfiguration.class));
Region<Long, PurchaseOrder> example =
getExampleRegion(newApplicationContext(withResource("data-example.json")));
assertExampleRegion(example);
assertThat(example).isEmpty();
assertExampleRegion(example);
assertThat(example).isEmpty();
Product golfBalls = Product.newProduct("Titliest ProV1x Golf Balls")
.havingPrice(BigDecimal.valueOf(34.99d))
.in(Product.Category.SPECIALTY);
Product golfBalls = Product.newProduct("Titliest ProV1x Golf Balls")
.havingPrice(BigDecimal.valueOf(34.99d))
.in(Product.Category.SPECIALTY);
LineItem lineItem = LineItem.newLineItem(golfBalls)
.withQuantity(1);
LineItem lineItem = LineItem.newLineItem(golfBalls)
.withQuantity(1);
PurchaseOrder purchaseOrder = new PurchaseOrder()
.identifiedAs(72L)
.add(lineItem);
PurchaseOrder purchaseOrder = new PurchaseOrder()
.identifiedAs(72L)
.add(lineItem);
assertThat(example.put(purchaseOrder.getId(), purchaseOrder)).isNull();
assertThat(example).hasSize(1);
assertPurchaseOrder(example.get(purchaseOrder.getId()), purchaseOrder.getId(),
Collections.singletonList(lineItem), golfBalls.getPrice());
assertThat(example.put(purchaseOrder.getId(), purchaseOrder)).isNull();
assertThat(example).hasSize(1);
assertPurchaseOrder(example.get(purchaseOrder.getId()), purchaseOrder.getId(),
Collections.singletonList(lineItem), golfBalls.getPrice());
//log("JSON from JSONFormatter '%s'%n",
// JSONFormatter.toJSON(serializeToPdx(example.getRegionService(), purchaseOrder)));
//log("JSON from JSONFormatter '%s'%n",
// JSONFormatter.toJSON(serializeToPdx(example.getRegionService(), purchaseOrder)));
closeApplicationContext();
closeApplicationContext();
String json = writer.toString();
String json = writer.toString();
assertThat(json).isNotEmpty();
assertThat(json).isNotEmpty();
//log("JSON '%s'%n", json);
//log("PurchaseOrder from JSON [%s]%n",
// newObjectMapper().readValue(json.substring(1, json.length() - 1), PurchaseOrder.class));
//log("JSON '%s'%n", json);
//log("PurchaseOrder from JSON [%s]%n",
// newObjectMapper().readValue(json.substring(1, json.length() - 1), PurchaseOrder.class));
// IMPORT
Resource mockResource = mock(Resource.class, withSettings().lenient());
// IMPORT
System.clearProperty(EXPORT_ENABLED_PROPERTY);
doReturn("MOCK").when(mockResource).getDescription();
doReturn(new ByteArrayInputStream(json.getBytes())).when(mockResource).getInputStream();
Resource mockResource = mock(Resource.class, withSettings().lenient());
exportEnabledSupplier = () -> false;
importEnabledSupplier = () -> true;
importResourceResolverSupplier = () -> (ImportResourceResolver) region -> Optional.of(mockResource);
doReturn(true).when(mockResource).exists();
doReturn("MOCK").when(mockResource).getDescription();
doReturn(new ByteArrayInputStream(json.getBytes())).when(mockResource).getInputStream();
example = getExampleRegion(newApplicationContext(TestGeodeConfiguration.class,
TestImportResourceResolverGeodeConfiguration.class));
resourceSupplier = () -> mockResource;
assertExampleRegion(example);
assertThat(example).hasSize(1);
example = getExampleRegion(newApplicationContext(withResource(null)));
Object value = example.values().stream().findFirst().orElse(null);
assertExampleRegion(example);
assertThat(example).hasSize(1);
assertThat(value).isInstanceOf(PdxInstance.class);
Object value = example.values().stream().findFirst().orElse(null);
assertThat(value).isInstanceOf(PdxInstance.class);
assertPurchaseOrder(ObjectUtils.asType(value, PurchaseOrder.class),
purchaseOrder.getId(), Collections.singletonList(lineItem), golfBalls.getPrice());
}
finally {
System.clearProperty(EXPORT_ENABLED_PROPERTY);
}
assertPurchaseOrder(ObjectUtils.asType(value, PurchaseOrder.class),
purchaseOrder.getId(), Collections.singletonList(lineItem), golfBalls.getPrice());
}
@Test
public void exportImportWithRegionContainingObjectsAndPdxInstances() throws IOException {
try {
// EXPORT
System.setProperty(EXPORT_ENABLED_PROPERTY, Boolean.TRUE.toString());
// EXPORT
StringWriter writer = new StringWriter();
StringWriter writer = new StringWriter();
exportEnabledSupplier = () -> true;
importEnabledSupplier = () -> false;
resourceWriterSupplier = () -> writer;
writerSupplier = () -> writer;
Region<Object, Object> example = getExampleRegion(newApplicationContext(TestGeodeConfiguration.class));
Region<Object, Object> example =
getExampleRegion(newApplicationContext(withResource("data-example.json")));
assertExampleRegion(example);
assertThat(example).isEmpty();
assertExampleRegion(example);
assertThat(example).isEmpty();
Customer jonDoe = Customer.newCustomer(1L, "Jon Doe");
Customer janeDoe = Customer.newCustomer(2L, "JaneDoe");
Customer jonDoe = Customer.newCustomer(1L, "Jon Doe");
Customer janeDoe = Customer.newCustomer(2L, "JaneDoe");
PdxInstance janeDoePdx = serializeToPdx(example.getRegionService(), janeDoe);
PdxInstance janeDoePdx = serializeToPdx(example.getRegionService(), janeDoe);
assertThat(example.put(jonDoe.getId(), jonDoe)).isNull();
assertThat(example.put(janeDoe.getId(), janeDoePdx)).isNull();
assertThat(example).hasSize(2);
assertThat(example.get(jonDoe.getId())).isEqualTo(jonDoe);
assertThat(example.get(janeDoe.getId())).isInstanceOf(PdxInstance.class);
assertThat(example.put(jonDoe.getId(), jonDoe)).isNull();
assertThat(example.put(janeDoe.getId(), janeDoePdx)).isNull();
assertThat(example).hasSize(2);
assertThat(example.get(jonDoe.getId())).isEqualTo(jonDoe);
assertThat(example.get(janeDoe.getId())).isInstanceOf(PdxInstance.class);
closeApplicationContext();
closeApplicationContext();
String json = writer.toString();
String json = writer.toString();
assertThat(json).isNotEmpty();
assertThat(json).isNotEmpty();
// IMPORT
Resource mockResource = mock(Resource.class, withSettings().lenient());
// IMPORT
System.clearProperty(EXPORT_ENABLED_PROPERTY);
doReturn("MOCK").when(mockResource).getDescription();
doReturn(new ByteArrayInputStream(json.getBytes())).when(mockResource).getInputStream();
Resource mockResource = mock(Resource.class, withSettings().lenient());
exportEnabledSupplier = () -> false;
importEnabledSupplier = () -> true;
importResourceResolverSupplier = () -> region -> Optional.of(mockResource);
doReturn(true).when(mockResource).exists();
doReturn("MOCK").when(mockResource).getDescription();
doReturn(new ByteArrayInputStream(json.getBytes())).when(mockResource).getInputStream();
example = getExampleRegion(newApplicationContext(TestGeodeConfiguration.class,
resourceSupplier = () -> mockResource;
TestImportResourceResolverGeodeConfiguration.class));
assertExampleRegion(example);
assertThat(example).hasSize(2);
example = getExampleRegion(newApplicationContext(withResource(null)));
for (Customer doe : Arrays.asList(jonDoe, janeDoe)) {
assertExampleRegion(example);
assertThat(example).hasSize(2);
Object value = example.get(doe.getId().byteValue());
for (Customer doe : Arrays.asList(jonDoe, janeDoe)) {
Object value = example.get(doe.getId().byteValue());
assertThat(value).isInstanceOf(PdxInstance.class);
assertThat(((PdxInstance) value).getObject()).isEqualTo(doe);
}
}
finally {
System.clearProperty(EXPORT_ENABLED_PROPERTY);
assertThat(value).isInstanceOf(PdxInstance.class);
assertThat(((PdxInstance) value).getObject()).isEqualTo(doe);
}
}
@@ -677,23 +666,40 @@ public class JsonCacheDataImporterExporterIntegrationTests extends IntegrationTe
}
@Bean
JsonCacheDataImporterExporter exampleRegionDataImporter() {
JsonCacheDataImporterExporter exampleRegionDataImporterExporter() {
return new JsonCacheDataImporterExporter();
}
return new JsonCacheDataImporterExporter() {
@Bean
ResourceWriter stringWriterResourceWriter() {
@Override @SuppressWarnings("rawtypes")
protected Optional<Resource> getResource(@NonNull Region region, String resourcePrefix) {
return Optional.ofNullable(resourceSupplier.get());
return (resource, data) -> {
String json = new String(data);
Writer writer = resourceWriterSupplier.get();
try {
writer.write(json, 0, data.length);
writer.flush();
}
@NonNull @Override
Writer newWriter(@NonNull Resource resource) {
return writerSupplier.get();
catch (IOException cause) {
throw new ResourceWriteException(String.format("Failed to write data [%s] to Resource [%s]",
json, resource.getDescription()), cause);
}
};
}
}
@Configuration
static class TestImportResourceResolverGeodeConfiguration {
@Bean
ImportResourceResolver testImportResourceResolver() {
return importResourceResolverSupplier.get();
}
}
public static class TimedType {
public static TimedType create() {

View File

@@ -17,42 +17,34 @@ package org.springframework.geode.data.json;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
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.verifyNoInteractions;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Optional;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import org.apache.geode.cache.Region;
import org.apache.geode.pdx.PdxInstance;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.data.gemfire.util.ArrayUtils;
import org.springframework.geode.core.io.ResourceReader;
import org.springframework.geode.core.io.ResourceWriter;
import org.springframework.geode.data.json.converter.JsonToPdxArrayConverter;
import org.springframework.geode.data.support.ResourceCapableCacheDataImporterExporter.ExportResourceResolver;
import org.springframework.geode.data.support.ResourceCapableCacheDataImporterExporter.ImportResourceResolver;
import org.springframework.lang.NonNull;
/**
* Unit Tests for {@link JsonCacheDataImporterExporter}.
@@ -63,19 +55,19 @@ import org.springframework.geode.data.json.converter.JsonToPdxArrayConverter;
* @see org.mockito.junit.MockitoJUnitRunner
* @see org.apache.geode.cache.Region
* @see org.apache.geode.pdx.PdxInstance
* @see org.springframework.context.ApplicationContext
* @see org.springframework.core.io.ClassPathResource
* @see org.springframework.core.io.Resource
* @see org.springframework.geode.core.io.ResourceReader
* @see org.springframework.geode.core.io.ResourceWriter
* @see org.springframework.geode.data.json.JsonCacheDataImporterExporter
* @see org.springframework.geode.data.json.converter.JsonToPdxArrayConverter
* @see org.springframework.geode.data.json.converter.ObjectToJsonConverter
* @see org.springframework.geode.data.support.ResourceCapableCacheDataImporterExporter.ExportResourceResolver
* @see org.springframework.geode.data.support.ResourceCapableCacheDataImporterExporter.ImportResourceResolver
* @since 1.3.0
*/
@RunWith(MockitoJUnitRunner.class)
public class JsonCacheDataImporterExporterUnitTests {
@Spy
private JsonCacheDataImporterExporter importer;
private TestJsonCacheDataImporterExporter importerExporter;
@Test
@SuppressWarnings("unchecked")
@@ -85,28 +77,56 @@ public class JsonCacheDataImporterExporterUnitTests {
Resource mockResource = mock(Resource.class);
ResourceWriter mockResourceWriter = mock(ResourceWriter.class);
Region<?, ?> mockRegion = mock(Region.class);
ExportResourceResolver mockExportResourceResolver = mock(ExportResourceResolver.class);
doReturn("TestRegion").when(mockRegion).getName();
doReturn(Optional.of(mockResource)).when(this.importer).getResource(eq(mockRegion), anyString());
doReturn( "file:///path/to/data.json").when(importer).getResourceLocation();
doNothing().when(this.importer).save(anyString(), any(Resource.class));
doReturn(json).when(this.importer).toJson(any());
doReturn(mockExportResourceResolver).when(this.importerExporter).getExportResourceResolver();
doReturn(mockResourceWriter).when(this.importerExporter).getResourceWriter();
doReturn(Optional.of(mockResource)).when(mockExportResourceResolver).resolve(eq(mockRegion));
doReturn(json).when(this.importerExporter).toJson(eq(mockRegion));
assertThat(this.importer.doExportFrom(mockRegion)).isEqualTo(mockRegion);
assertThat(this.importerExporter.doExportFrom(mockRegion)).isEqualTo(mockRegion);
verify(this.importer, times(1)).toJson(eq(mockRegion));
verify(this.importer, times(1)).getResource(eq(mockRegion),
eq("file:///path/to/data.json"));
verify(this.importer, times(1)).getResourceLocation();
verify(this.importer, times(1)).save(eq(json), eq(mockResource));
InOrder order = inOrder(this.importerExporter, mockRegion, mockExportResourceResolver, mockResourceWriter);
order.verify(this.importerExporter, times(1)).getExportResourceResolver();
order.verify(mockExportResourceResolver, times(1)).resolve(eq(mockRegion));
order.verify(this.importerExporter, times(1)).toJson(eq(mockRegion));
order.verify(mockRegion, times(1)).getName();
order.verify(this.importerExporter, times(1)).getResourceWriter();
order.verify(mockResourceWriter, times(1)).write(eq(mockResource), eq(json.getBytes()));
verifyNoMoreInteractions(mockRegion, mockExportResourceResolver, mockResourceWriter);
verifyNoInteractions(mockResource);
}
@Test
@SuppressWarnings("unchecked")
public void doExportFromWithNoResource() {
ExportResourceResolver mockExportResourceResolver = mock(ExportResourceResolver.class);
Region<?, ?> mockRegion = mock(Region.class);
doReturn(mockExportResourceResolver).when(this.importerExporter).getExportResourceResolver();
doReturn(Optional.empty()).when(mockExportResourceResolver).resolve(eq(mockRegion));
assertThat(this.importerExporter.doExportFrom(mockRegion)).isEqualTo(mockRegion);
verify(this.importerExporter, times(1)).getExportResourceResolver();
verify(mockExportResourceResolver, times(1)).resolve(eq(mockRegion));
verifyNoMoreInteractions(mockExportResourceResolver, mockRegion);
verifyNoInteractions(mockRegion);
}
@Test(expected = IllegalArgumentException.class)
public void doExportFromNullRegion() {
try {
this.importer.doExportFrom(null);
this.importerExporter.doExportFrom(null);
}
catch (IllegalArgumentException expected) {
@@ -117,222 +137,151 @@ public class JsonCacheDataImporterExporterUnitTests {
}
}
@Test
public void saveJsonToResource() throws IOException {
String json = "[{ \"name\": \"Jon Doe\"}, { \"name\": \"Jane Doe\"}]";
StringWriter writer = new StringWriter(json.length());
Resource mockResource = mock(Resource.class);
doReturn(writer).when(this.importer).newWriter(eq(mockResource));
this.importer.save(json, mockResource);
assertThat(writer.toString()).isEqualTo(json);
verify(this.importer, times(1)).newWriter(eq(mockResource));
verifyNoInteractions(mockResource);
}
@Test(expected = DataAccessResourceFailureException.class)
public void saveThrowsIoException() throws IOException {
Writer mockWriter = mock(Writer.class);
String json = "[{ \"name\": \"Jon Doe\"}, { \"name\": \"Jane Doe\"}"
+ ", { \"name\": \"Pie Doe\"}, { \"name\": \"Sour Doe\"}]";
Resource mockResource = mock(Resource.class);
doReturn("/path/to/data.json").when(mockResource).getDescription();
doReturn(mockWriter).when(this.importer).newWriter(eq(mockResource));
doThrow(new IOException("TEST")).when(mockWriter).write(anyString(), anyInt(), anyInt());
try {
this.importer.save(json, mockResource);
}
catch (DataAccessResourceFailureException expected) {
assertThat(expected)
.hasMessageStartingWith("Failed to save content '%s' to Resource [/path/to/data.json]",
this.importer.formatContentForPreview(json));
assertThat(expected).hasCauseInstanceOf(IOException.class);
assertThat(expected.getCause()).hasMessage("TEST");
assertThat(expected.getCause()).hasNoCause();
throw expected;
}
finally {
verify(this.importer, times(1)).newWriter(eq(mockResource));
verify(mockWriter, times(1)).write(eq(json), eq(0), eq(json.length()));
verify(mockWriter, never()).flush();
verify(mockWriter, times(1)).close();
}
}
@Test
public void saveWithNoContent() {
Resource mockResource = mock(Resource.class);
try {
this.importer.save(" ", mockResource);
}
finally {
verify(this.importer, times(1)).save(eq(" "), eq(mockResource));
verifyNoMoreInteractions(this.importer);
verifyNoInteractions(mockResource);
}
}
@Test(expected = IllegalArgumentException.class)
public void saveWithNullResource() {
try {
this.importer.save("{}", null);
}
catch (IllegalArgumentException expected) {
assertThat(expected).hasMessage("Resource must not be null");
assertThat(expected).hasNoCause();
throw expected;
}
finally {
verify(this.importer, times(1)).save(eq("{}"), isNull());
verifyNoMoreInteractions(this.importer);
}
}
@Test
@SuppressWarnings("unchecked")
public void doImportIntoPutsPdxIntoRegionForJson() {
Resource mockResource = mock(Resource.class);
ResourceReader mockResourceReader = mock(ResourceReader.class);
Region<Integer, PdxInstance> mockRegion = mock(Region.class);
PdxInstance mockPdxInstanceOne = mock(PdxInstance.class);
PdxInstance mockPdxInstanceTwo = mock(PdxInstance.class);
ImportResourceResolver mockImportResourceResolver = mock(ImportResourceResolver.class);
byte[] json = "[{ \"name\": \"Jon Doe\"}, { \"name\": \"Jane Doe\" }]".getBytes();
doReturn(Optional.of(mockResource)).when(this.importer).getResource(eq(mockRegion),eq("classpath:"));
doReturn(true).when(mockResource).exists();
doReturn(json).when(this.importer).getContent(eq(mockResource));
doReturn(ArrayUtils.asArray(mockPdxInstanceOne, mockPdxInstanceTwo)).when(this.importer).toPdx(eq(json));
doReturn(1).when(this.importer).resolveKey(eq(mockPdxInstanceOne));
doReturn(2).when(this.importer).resolveKey(eq(mockPdxInstanceTwo));
doReturn(mockImportResourceResolver).when(this.importerExporter).getImportResourceResolver();
doReturn(mockResourceReader).when(this.importerExporter).getResourceReader();
doReturn(Optional.of(mockResource)).when(mockImportResourceResolver).resolve(eq(mockRegion));
doReturn(json).when(mockResourceReader).read(eq(mockResource));
doReturn(ArrayUtils.asArray(mockPdxInstanceOne, mockPdxInstanceTwo)).when(this.importerExporter).toPdx(eq(json));
doReturn(1).when(this.importerExporter).resolveKey(eq(mockPdxInstanceOne));
doReturn(2).when(this.importerExporter).resolveKey(eq(mockPdxInstanceTwo));
assertThat(this.importer.doImportInto(mockRegion)).isEqualTo(mockRegion);
assertThat(this.importerExporter.doImportInto(mockRegion)).isEqualTo(mockRegion);
verify(this.importer, times(1)).getResource(eq(mockRegion), eq("classpath:"));
verify(this.importer, times(1)).getContent(eq(mockResource));
verify(this.importer, times(1)).toPdx(eq(json));
verify(this.importer, times(1)).resolveKey(eq(mockPdxInstanceOne));
verify(this.importer, times(1)).postProcess(eq(mockPdxInstanceOne));
verify(this.importer, times(1)).resolveValue(eq(mockPdxInstanceOne));
verify(this.importer, times(1)).resolveKey(eq(mockPdxInstanceTwo));
verify(this.importer, times(1)).postProcess(eq(mockPdxInstanceTwo));
verify(this.importer, times(1)).resolveValue(eq(mockPdxInstanceTwo));
verify(mockResource, times(1)).exists();
verify(mockRegion, times(1)).put(eq(1), eq(mockPdxInstanceOne));
verify(mockRegion, times(1)).put(eq(2), eq(mockPdxInstanceTwo));
InOrder order =
inOrder(this.importerExporter, mockRegion, mockResource, mockResourceReader, mockImportResourceResolver);
order.verify(this.importerExporter, times(1)).getImportResourceResolver();
order.verify(mockImportResourceResolver, times(1)).resolve(eq(mockRegion));
order.verify(this.importerExporter, times(1)).getResourceReader();
order.verify(mockResourceReader, times(1)).read(eq(mockResource));
order.verify(this.importerExporter, times(1)).toPdx(eq(json));
order.verify(this.importerExporter, times(1)).resolveKey(eq(mockPdxInstanceOne));
order.verify(this.importerExporter, times(1)).resolveValue(eq(mockPdxInstanceOne));
order.verify(this.importerExporter, times(1)).postProcess(eq(mockPdxInstanceOne));
order.verify(mockRegion, times(1)).put(eq(1), eq(mockPdxInstanceOne));
order.verify(this.importerExporter, times(1)).resolveKey(eq(mockPdxInstanceTwo));
order.verify(this.importerExporter, times(1)).resolveValue(eq(mockPdxInstanceTwo));
order.verify(this.importerExporter, times(1)).postProcess(eq(mockPdxInstanceTwo));
order.verify(mockRegion, times(1)).put(eq(2), eq(mockPdxInstanceTwo));
verifyNoMoreInteractions(mockRegion, mockImportResourceResolver, mockResourceReader);
verifyNoInteractions(mockResource, mockPdxInstanceOne, mockPdxInstanceTwo);
}
@Test
@SuppressWarnings("unchecked")
public void doImportIntoWithNoResource() {
Region<?, ?> mockRegion = mock(Region.class);
doReturn(Optional.empty()).when(this.importer).getResource(eq(mockRegion), eq("classpath:"));
assertThat(this.importer.doImportInto(mockRegion)).isEqualTo(mockRegion);
verify(this.importer, times(1)).doImportInto(eq(mockRegion));
verify(this.importer, times(1)).getResource(eq(mockRegion), eq("classpath:"));
verifyNoMoreInteractions(this.importer);
verifyNoInteractions(mockRegion);
}
@Test
@SuppressWarnings("unchecked")
public void doImportIntoWithNonExistingResource() {
Resource mockResource = mock(Resource.class);
ImportResourceResolver mockImportResourceResolver = mock(ImportResourceResolver.class);
Region<?, ?> mockRegion = mock(Region.class);
doReturn(Optional.of(mockResource)).when(this.importer).getResource(eq(mockRegion), eq("classpath:"));
doReturn(false).when(mockResource).exists();
ResourceReader mockResourceReader = mock(ResourceReader.class);
assertThat(this.importer.doImportInto(mockRegion)).isEqualTo(mockRegion);
doReturn(mockImportResourceResolver).when(this.importerExporter).getImportResourceResolver();
doReturn(mockResourceReader).when(this.importerExporter).getResourceReader();
doReturn(Optional.empty()).when(mockImportResourceResolver).resolve(eq(mockRegion));
verify(this.importer, times(1)).doImportInto(eq(mockRegion));
verify(this.importer, times(1)).getResource(eq(mockRegion), eq("classpath:"));
verify(mockResource, times(1)).exists();
verifyNoMoreInteractions(this.importer);
verifyNoMoreInteractions(mockResource);
verifyNoInteractions(mockRegion);
assertThat(this.importerExporter.doImportInto(mockRegion)).isEqualTo(mockRegion);
verify(this.importerExporter, times(1)).doImportInto(eq(mockRegion));
verify(this.importerExporter, times(1)).getImportResourceResolver();
verify(this.importerExporter, times(1)).getResourceReader();
verify(mockImportResourceResolver, times(1)).resolve(eq(mockRegion));
verifyNoMoreInteractions(this.importerExporter, mockImportResourceResolver);
verifyNoInteractions(mockRegion, mockResourceReader);
}
@Test
@SuppressWarnings("unchecked")
public void doImportIntoWithResourceContainingNoContent() {
Resource mockResource = mock(Resource.class);
byte[] json = {};
ImportResourceResolver mockImportResourceResolver = mock(ImportResourceResolver.class);
Region<?, ?> mockRegion = mock(Region.class);
doReturn(Optional.of(mockResource)).when(this.importer).getResource(eq(mockRegion), eq("classpath:"));
doReturn(true).when(mockResource).exists();
doReturn(null).when(this.importer).getContent(eq(mockResource));
Resource mockResource = mock(Resource.class);
assertThat(this.importer.doImportInto(mockRegion)).isEqualTo(mockRegion);
ResourceReader mockResourceReader = mock(ResourceReader.class);
verify(this.importer, times(1)).doImportInto(eq(mockRegion));
verify(this.importer, times(1)).getResource(eq(mockRegion), eq("classpath:"));
verify(this.importer, times(1)).getContent(eq(mockResource));
verify(mockResource, times(1)).exists();
verifyNoMoreInteractions(this.importer);
verifyNoMoreInteractions(mockResource);
verifyNoInteractions(mockRegion);
doReturn(mockImportResourceResolver).when(this.importerExporter).getImportResourceResolver();
doReturn(mockResourceReader).when(this.importerExporter).getResourceReader();
doReturn(JsonCacheDataImporterExporter.EMPTY_PDX_INSTANCE_ARRAY).when(this.importerExporter).toPdx(any());
doReturn(Optional.of(mockResource)).when(mockImportResourceResolver).resolve(eq(mockRegion));
doReturn(json).when(mockResourceReader).read(eq(mockResource));
assertThat(this.importerExporter.doImportInto(mockRegion)).isEqualTo(mockRegion);
verify(this.importerExporter, times(1)).doImportInto(eq(mockRegion));
verify(this.importerExporter, times(1)).getImportResourceResolver();
verify(this.importerExporter, times(1)).getResourceReader();
verify(this.importerExporter, times(1)).toPdx(eq(json));
verify(this.importerExporter, times(1))
.regionPutPdx(eq(mockRegion), eq(JsonCacheDataImporterExporter.EMPTY_PDX_INSTANCE_ARRAY));
verify(mockImportResourceResolver, times(1)).resolve(eq(mockRegion));
verify(mockResourceReader, times(1)).read(eq(mockResource));
verifyNoMoreInteractions(this.importerExporter, mockImportResourceResolver, mockResourceReader);
verifyNoInteractions(mockRegion, mockResource);
}
@Test
@SuppressWarnings("unchecked")
public void doImportIntoWithNoPdxInstance() {
public void doImportIntoWithNoPdx() {
Resource mockResource = mock(Resource.class);
byte[] json = "[{ \"name\":\"Jon Doe\" }]".getBytes();
ImportResourceResolver mockImportResourceResolver = mock(ImportResourceResolver.class);
Region<?, ?> mockRegion = mock(Region.class);
byte[] json = "[]".getBytes();
Resource mockResource = mock(Resource.class);
doReturn(Optional.of(mockResource)).when(this.importer).getResource(eq(mockRegion), eq("classpath:"));
doReturn(true).when(mockResource).exists();
doReturn(json).when(this.importer).getContent(eq(mockResource));
doReturn(new PdxInstance[0]).when(this.importer).toPdx(eq(json));
ResourceReader mockResourceReader = mock(ResourceReader.class);
assertThat(this.importer.doImportInto(mockRegion)).isEqualTo(mockRegion);
doReturn(mockImportResourceResolver).when(this.importerExporter).getImportResourceResolver();
doReturn(mockResourceReader).when(this.importerExporter).getResourceReader();
doReturn(JsonCacheDataImporterExporter.EMPTY_PDX_INSTANCE_ARRAY).when(this.importerExporter).toPdx(eq(json));
doReturn(Optional.of(mockResource)).when(mockImportResourceResolver).resolve(eq(mockRegion));
doReturn(json).when(mockResourceReader).read(eq(mockResource));
verify(this.importer, times(1)).doImportInto(eq(mockRegion));
verify(this.importer, times(1)).getResource(eq(mockRegion), eq("classpath:"));
verify(this.importer, times(1)).getContent(eq(mockResource));
verify(this.importer, times(1)).toPdx(eq(json));
verify(mockResource, times(1)).exists();
verifyNoMoreInteractions(this.importer);
verifyNoMoreInteractions(mockResource);
verifyNoInteractions(mockRegion);
assertThat(this.importerExporter.doImportInto(mockRegion)).isEqualTo(mockRegion);
verify(this.importerExporter, times(1)).doImportInto(eq(mockRegion));
verify(this.importerExporter, times(1)).getImportResourceResolver();
verify(this.importerExporter, times(1)).getResourceReader();
verify(this.importerExporter, times(1)).toPdx(eq(json));
verify(this.importerExporter, times(1)).regionPutPdx(eq(mockRegion),
eq(JsonCacheDataImporterExporter.EMPTY_PDX_INSTANCE_ARRAY));
verify(mockImportResourceResolver, times(1)).resolve(eq(mockRegion));
verify(mockResourceReader, times(1)).read(eq(mockResource));
verifyNoMoreInteractions(this.importerExporter, mockImportResourceResolver, mockResourceReader);
verifyNoInteractions(mockRegion, mockResource);
}
@Test(expected = IllegalArgumentException.class)
public void doImportIntoNullRegion() {
try {
this.importer.doImportInto(null);
this.importerExporter.doImportInto(null);
}
catch (IllegalArgumentException expected) {
@@ -343,144 +292,12 @@ public class JsonCacheDataImporterExporterUnitTests {
}
}
@Test
public void getContentFromResource() throws IOException {
byte[] json = "{ \"name\": \"Jon Doe\" }".getBytes();
ByteArrayInputStream in = spy(new ByteArrayInputStream(json));
Resource mockResource = mock(Resource.class);
doReturn(in).when(mockResource).getInputStream();
assertThat(this.importer.getContent(mockResource)).isEqualTo(json);
verify(mockResource, times(1)).getInputStream();
verify(in, times(1)).close();
}
@Test(expected = IllegalArgumentException.class)
public void getContentFromNullResource() {
try {
this.importer.getContent(null);
}
catch (IllegalArgumentException expected) {
assertThat(expected).hasMessage("Resource must not be null");
assertThat(expected).hasNoCause();
throw expected;
}
}
@Test(expected = DataAccessResourceFailureException.class)
public void getContentThrowsIoException() throws IOException {
Resource mockResource = mock(Resource.class);
doReturn("Test Resource").when(mockResource).getDescription();
doThrow(new IOException("TEST")).when(mockResource).getInputStream();
try {
this.importer.getContent(mockResource);
}
catch (DataAccessResourceFailureException expected) {
assertThat(expected).hasMessageStartingWith("Failed to read from Resource [Test Resource]");
assertThat(expected).hasCauseInstanceOf(IOException.class);
assertThat(expected.getCause()).hasMessage("TEST");
assertThat(expected.getCause()).hasNoCause();
throw expected;
}
}
@Test
public void getResourceFromRegionAndResourcePrefix() {
ApplicationContext mockApplicationContext = mock(ApplicationContext.class);
Region<?, ?> mockRegion = mock(Region.class);
Resource mockResource = mock(Resource.class);
doReturn(mockResource).when(mockApplicationContext).getResource(anyString());
doReturn("Example").when(mockRegion).getName();
doReturn(Optional.of(mockApplicationContext)).when(this.importer).getApplicationContext();
assertThat(this.importer.getResource(mockRegion, "sftp://host/resources/").orElse(null))
.isEqualTo(mockResource);
verify(mockApplicationContext, times(1))
.getResource(eq("sftp://host/resources/data-example.json"));
verify(mockRegion, times(1)).getName();
}
@Test
public void getResourceWhenApplicationContextIsNotPresent() {
Region<?, ?> mockRegion = mock(Region.class);
doReturn("TEST").when(mockRegion).getName();
Resource resource = this.importer.getResource(mockRegion, "file://").orElse(null);
assertThat(resource).isInstanceOf(ClassPathResource.class);
assertThat(((ClassPathResource) resource).getPath()).isEqualTo("data-test.json");
verify(mockRegion, times(1)).getName();
}
@Test
public void getResourceWhenApplicationContextReturnsNoResource() {
ApplicationContext mockApplicationContext = mock(ApplicationContext.class);
Region<?, ?> mockRegion = mock(Region.class);
doReturn(null).when(mockApplicationContext).getResource(anyString());
doReturn("MocK").when(mockRegion).getName();
doReturn(Optional.ofNullable(mockApplicationContext)).when(this.importer).getApplicationContext();
Resource resource = this.importer.getResource(mockRegion, null).orElse(null);
assertThat(resource).isInstanceOf(ClassPathResource.class);
assertThat(((ClassPathResource) resource).getPath()).isEqualTo("data-mock.json");
verify(mockApplicationContext, times(1))
.getResource(eq("classpath:data-mock.json"));
verify(mockRegion, times(1)).getName();
}
@Test(expected = IllegalArgumentException.class)
public void getResourceFromNullRegion() {
try {
this.importer.getResource(null, "classpath:");
}
catch (IllegalArgumentException expected) {
assertThat(expected).hasMessage("Region must not be null");
assertThat(expected).hasNoCause();
throw expected;
}
}
@Test
public void getResourceLocationIsInWorkingDirectory() {
assertThat(this.importer.getResourceLocation()).isEqualTo(String.format("file://%1$s%2$s",
System.getProperty("user.dir"), File.separator));
}
@Test
public void toJsonFromEmptyRegion() {
Region<?, ?> mockRegion = mock(Region.class);
assertThat(this.importer.toJson(mockRegion)).isEqualTo("[]");
assertThat(this.importerExporter.toJson(mockRegion)).isEqualTo("[]");
verify(mockRegion, times(1)).values();
}
@@ -489,7 +306,7 @@ public class JsonCacheDataImporterExporterUnitTests {
public void toJsonFromNullRegion() {
try {
this.importer.toJson(null);
this.importerExporter.toJson(null);
}
catch (IllegalArgumentException expected) {
@@ -512,13 +329,36 @@ public class JsonCacheDataImporterExporterUnitTests {
PdxInstance[] pdxArray = ArrayUtils.asArray(mockPdxInstanceOne, mockPdxInstanceTwo);
doReturn(mockConverter).when(this.importer).getJsonToPdxArrayConverter();
doReturn(mockConverter).when(this.importerExporter).getJsonToPdxArrayConverter();
doReturn(pdxArray).when(mockConverter).convert(eq(json));
assertThat(this.importer.toPdx(json)).isEqualTo(pdxArray);
assertThat(this.importerExporter.toPdx(json)).isEqualTo(pdxArray);
verify(this.importer, times(1)).getJsonToPdxArrayConverter();
verify(this.importerExporter, times(1)).getJsonToPdxArrayConverter();
verify(mockConverter, times(1)).convert(eq(json));
verifyNoMoreInteractions(mockConverter);
}
static class TestJsonCacheDataImporterExporter extends JsonCacheDataImporterExporter {
@Override
protected @NonNull ExportResourceResolver getExportResourceResolver() {
return super.getExportResourceResolver();
}
@Override
protected @NonNull ImportResourceResolver getImportResourceResolver() {
return super.getImportResourceResolver();
}
@Override
protected @NonNull ResourceReader getResourceReader() {
return super.getResourceReader();
}
@Override
protected @NonNull ResourceWriter getResourceWriter() {
return super.getResourceWriter();
}
}
}

View File

@@ -20,7 +20,6 @@ import static org.assertj.core.api.Assertions.assertThat;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -52,7 +51,7 @@ import org.springframework.data.gemfire.config.annotation.CacheServerApplication
import org.springframework.data.gemfire.config.annotation.ClientCacheApplication;
import org.springframework.data.gemfire.tests.integration.ForkingClientServerIntegrationTestsSupport;
import org.springframework.data.gemfire.util.PropertiesBuilder;
import org.springframework.lang.NonNull;
import org.springframework.geode.core.io.ResourceWriter;
import org.springframework.util.FileCopyUtils;
import example.app.crm.model.Customer;
@@ -89,7 +88,6 @@ import example.app.crm.model.Customer;
public class JsonClientCacheDataImporterExporterIntegrationTests extends ForkingClientServerIntegrationTestsSupport {
private static final AtomicBoolean applicationContextClosed = new AtomicBoolean(false);
private static final AtomicBoolean exportFromCalled = new AtomicBoolean(false);
private static ConfigurableApplicationContext applicationContext = null;
@@ -101,7 +99,6 @@ public class JsonClientCacheDataImporterExporterIntegrationTests extends Forking
public static void assetClientCacheDataExportWorksAsExpected() throws IOException {
assertThat(applicationContextClosed.get()).isTrue();
assertThat(exportFromCalled.get()).isTrue();
String actualJson = trimJson(writer.toString());
String expectedJson = trimJson(loadJson(CUSTOMERS_JSON_RESOURCE_PATH));
@@ -212,14 +209,18 @@ public class JsonClientCacheDataImporterExporterIntegrationTests extends Forking
@Bean
JsonCacheDataImporterExporter cacheDataImporterExporter() {
return new JsonCacheDataImporterExporter();
}
return new JsonCacheDataImporterExporter() {
@Bean
ResourceWriter testResourceWriter() {
@Override
@NonNull Writer newWriter(@NonNull org.springframework.core.io.Resource resource) {
exportFromCalled.set(true);
return writer;
}
return (resource, data) -> {
String json = new String(data);
writer.write(json);
writer.flush();
};
}