From 22b01985b7afe7dbefb7ba8345d16f37265dd2f2 Mon Sep 17 00:00:00 2001 From: John Blum Date: Mon, 11 May 2020 00:04:43 -0700 Subject: [PATCH] Add Integration Tests for JsonCacheDataImporterExporter asserting the functionality in a client/server topology with a ClientCache. Resolves gh-67. --- ...eDataImporterExporterIntegrationTests.java | 254 ++++++++++++++++++ .../src/test/resources/data-customers.json | 12 + 2 files changed, 266 insertions(+) create mode 100644 spring-geode/src/test/java/org/springframework/geode/data/json/JsonClientCacheDataImporterExporterIntegrationTests.java create mode 100644 spring-geode/src/test/resources/data-customers.json diff --git a/spring-geode/src/test/java/org/springframework/geode/data/json/JsonClientCacheDataImporterExporterIntegrationTests.java b/spring-geode/src/test/java/org/springframework/geode/data/json/JsonClientCacheDataImporterExporterIntegrationTests.java new file mode 100644 index 00000000..ca13cedc --- /dev/null +++ b/spring-geode/src/test/java/org/springframework/geode/data/json/JsonClientCacheDataImporterExporterIntegrationTests.java @@ -0,0 +1,254 @@ +/* + * Copyright 2020 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 + * + * https://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.geode.data.json; + +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; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import org.apache.geode.cache.DataPolicy; +import org.apache.geode.cache.GemFireCache; +import org.apache.geode.cache.Region; +import org.apache.geode.cache.client.ClientCache; +import org.apache.geode.cache.client.ClientRegionShortcut; +import org.apache.geode.pdx.PdxInstance; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.event.ContextClosedEvent; +import org.springframework.context.event.EventListener; +import org.springframework.core.io.ClassPathResource; +import org.springframework.data.gemfire.LocalRegionFactoryBean; +import org.springframework.data.gemfire.client.ClientRegionFactoryBean; +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.util.FileCopyUtils; + +import example.app.crm.model.Customer; + +/** + * Integration Tests for {@link JsonCacheDataImporterExporter} using a GemFire/Geode {@link ClientCache}. + * + * @author John Blum + * @see java.util.Properties + * @see org.junit.Test + * @see org.apache.geode.cache.GemFireCache + * @see org.apache.geode.cache.Region + * @see org.apache.geode.cache.client.ClientCache + * @see org.apache.geode.pdx.PdxInstance + * @see org.springframework.boot.SpringApplication + * @see org.springframework.boot.builder.SpringApplicationBuilder + * @see org.springframework.context.ApplicationContext + * @see org.springframework.context.ConfigurableApplicationContext + * @see org.springframework.context.annotation.AnnotationConfigApplicationContext + * @see org.springframework.context.annotation.Bean + * @see org.springframework.context.event.ContextClosedEvent + * @see org.springframework.context.event.EventListener + * @see org.springframework.core.io.ClassPathResource + * @see org.springframework.data.gemfire.LocalRegionFactoryBean + * @see org.springframework.data.gemfire.client.ClientRegionFactoryBean + * @see org.springframework.data.gemfire.config.annotation.CacheServerApplication + * @see org.springframework.data.gemfire.config.annotation.ClientCacheApplication + * @see org.springframework.data.gemfire.tests.integration.ForkingClientServerIntegrationTestsSupport + * @see org.springframework.data.gemfire.util.PropertiesBuilder + * @see org.springframework.geode.data.json.JsonCacheDataImporterExporter + * @since 1.3.0 + */ +@SuppressWarnings("unused") +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; + + private static final String CUSTOMERS_JSON_RESOURCE_PATH = "data-customers.json"; + + private static final StringWriter writer = new StringWriter(); + + @AfterClass + 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)); + + assertThat(actualJson).isEqualTo(expectedJson); + } + + private static String loadJson(String resourcePath) throws IOException { + return FileCopyUtils.copyToString(new InputStreamReader(new ClassPathResource(resourcePath).getInputStream())); + } + + private static String trimJson(String json) { + + StringBuilder buffer = new StringBuilder(); + + for (char character : String.valueOf(json).toCharArray()) { + if (!Character.isWhitespace(character)) { + buffer.append(character); + } + } + + return buffer.toString(); + } + + private static void closeApplicationContext() { + SpringApplication.exit(applicationContext); + } + + private static ApplicationContext newApplicationContext() { + + Properties configuration = PropertiesBuilder.create() + .setProperty("spring.boot.data.gemfire.cache.data.export.enabled", Boolean.TRUE.toString()) + .setProperty("spring.boot.data.gemfire.cache.data.import.active-profiles", "DEV") + .build(); + + ConfigurableApplicationContext applicationContext = + new SpringApplicationBuilder(TestGeodeClientConfiguration.class) + .profiles("DEV") + .properties(configuration) + .web(WebApplicationType.NONE) + .build() + .run(); + + JsonClientCacheDataImporterExporterIntegrationTests.applicationContext = applicationContext; + + return applicationContext; + } + + @BeforeClass + public static void startGeodeServer() throws IOException { + startGemFireServer(TestGeodeServerConfiguration.class); + } + + public void assertCustomersRegion(Region customers) { + + assertThat(customers).isNotNull(); + assertThat(customers.getName()).isEqualTo("Customers"); + assertThat(customers.getAttributes()).isNotNull(); + assertThat(customers.getAttributes().getDataPolicy()).isEqualTo(DataPolicy.EMPTY); + assertThat(customers).hasSize(0); + } + + @Test + @SuppressWarnings("unchecked") + public void clientCacheDataImportWorksAsExpected() { + + try { + Region customers = + newApplicationContext().getBean("Customers", Region.class); + + assertCustomersRegion(customers); + + Set keys = customers.keySetOnServer(); + + assertThat(keys).hasSize(2); + assertThat(keys).containsExactlyInAnyOrder((byte) 1, (byte) 2); + + Object jonDoeValue = customers.get((byte) 1); + + assertThat(jonDoeValue).isInstanceOf(PdxInstance.class); + assertThat(((PdxInstance) jonDoeValue).getObject()) + .isEqualTo(Customer.newCustomer(1L, "Jon Doe")); + + Object janeDoeValue = customers.get((byte) 2); + + assertThat(janeDoeValue).isInstanceOf(PdxInstance.class); + assertThat(((PdxInstance) janeDoeValue).getObject()) + .isEqualTo(Customer.newCustomer(2L, "Jane Doe")); + } + finally { + closeApplicationContext(); + } + } + + @ClientCacheApplication(name = "JsonClientCacheDataImporterExporterIntegrationTestsClient") + static class TestGeodeClientConfiguration { + + @Bean("Customers") + ClientRegionFactoryBean customersRegion(GemFireCache cache) { + + ClientRegionFactoryBean customersRegion = new ClientRegionFactoryBean<>(); + + customersRegion.setCache(cache); + customersRegion.setShortcut(ClientRegionShortcut.PROXY); + + return customersRegion; + } + + @Bean + JsonCacheDataImporterExporter cacheDataImporterExporter() { + + return new JsonCacheDataImporterExporter() { + + @Override + @NonNull Writer newWriter(@NonNull org.springframework.core.io.Resource resource) { + exportFromCalled.set(true); + return writer; + } + }; + } + + @EventListener(classes = ContextClosedEvent.class) + void applicationContextClosedListener(ContextClosedEvent event) { + applicationContextClosed.set(true); + } + } + + @CacheServerApplication(name = "JsonClientCacheDataImporterExporterIntegrationTestsServer") + static class TestGeodeServerConfiguration { + + public static void main(String[] args) { + + AnnotationConfigApplicationContext applicationContext = + new AnnotationConfigApplicationContext(TestGeodeServerConfiguration.class); + + applicationContext.registerShutdownHook(); + } + + @Bean("Customers") + LocalRegionFactoryBean customersRegion(GemFireCache cache) { + + LocalRegionFactoryBean customersRegion = new LocalRegionFactoryBean<>(); + + customersRegion.setCache(cache); + customersRegion.setPersistent(false); + + return customersRegion; + } + } +} diff --git a/spring-geode/src/test/resources/data-customers.json b/spring-geode/src/test/resources/data-customers.json new file mode 100644 index 00000000..0e540014 --- /dev/null +++ b/spring-geode/src/test/resources/data-customers.json @@ -0,0 +1,12 @@ +[ + { + "@type": "example.app.crm.model.Customer", + "id": 1, + "name": "Jon Doe" + }, + { + "@type": "example.app.crm.model.Customer", + "id": 2, + "name": "Jane Doe" + } +]