From bc1c259fb7d245495deef2de32279e65c260525a Mon Sep 17 00:00:00 2001 From: John Blum Date: Thu, 13 Jun 2019 01:20:16 -0700 Subject: [PATCH] Add Integration Tests testing the Inline Caching support using Apache Cassandra. --- .../crm/config/CassandraConfiguration.java | 65 +++++++++++ .../config/TestCassandraConfiguration.java | 101 ++++++++++++++++++ ...eCachingWithCassandraIntegrationTests.java | 90 ++++++++++++++++ .../src/test/resources/cassandra-data.cql | 1 + .../src/test/resources/cassandra-schema.cql | 4 + 5 files changed, 261 insertions(+) create mode 100644 spring-geode/src/test/java/example/app/crm/config/CassandraConfiguration.java create mode 100644 spring-geode/src/test/java/example/app/crm/config/TestCassandraConfiguration.java create mode 100644 spring-geode/src/test/java/org/springframework/geode/cache/inline/cassandra/InlineCachingWithCassandraIntegrationTests.java create mode 100644 spring-geode/src/test/resources/cassandra-data.cql create mode 100644 spring-geode/src/test/resources/cassandra-schema.cql diff --git a/spring-geode/src/test/java/example/app/crm/config/CassandraConfiguration.java b/spring-geode/src/test/java/example/app/crm/config/CassandraConfiguration.java new file mode 100644 index 00000000..e5e7f362 --- /dev/null +++ b/spring-geode/src/test/java/example/app/crm/config/CassandraConfiguration.java @@ -0,0 +1,65 @@ +/* + * Copyright 2019 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 example.app.crm.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +import org.testcontainers.containers.GenericContainer; + +/** + * Spring {@link @Configuration} for Apache Cassandra. + * + * @author John Blum + * @see org.springframework.context.annotation.Bean + * @see org.springframework.context.annotation.Configuration + * @see org.springframework.context.annotation.Profile + * @see org.testcontainers.containers.GenericContainer + * @since 1.1.0 + */ +@Configuration +@Profile("inline-caching-cassandra") +@SuppressWarnings("unused") +public class CassandraConfiguration extends TestCassandraConfiguration { + + private static final String CASSANDRA_DOCKER_IMAGE_NAME = "cassandra:latest"; + + @Bean + GenericContainer cassandraContainer() { + + GenericContainer cassandraContainer = newCassandraContainer() + .withExposedPorts(CASSANDRA_DEFAULT_PORT); + + cassandraContainer.start(); + + return cassandraContainer; + } + + private GenericContainer newCassandraContainer() { + return new GenericContainer(CASSANDRA_DOCKER_IMAGE_NAME); + } + + @Override + protected String getContactPoints() { + return cassandraContainer().getContainerIpAddress(); + } + + @Override + protected int getPort() { + return cassandraContainer().getFirstMappedPort(); + } +} diff --git a/spring-geode/src/test/java/example/app/crm/config/TestCassandraConfiguration.java b/spring-geode/src/test/java/example/app/crm/config/TestCassandraConfiguration.java new file mode 100644 index 00000000..00006c60 --- /dev/null +++ b/spring-geode/src/test/java/example/app/crm/config/TestCassandraConfiguration.java @@ -0,0 +1,101 @@ +/* + * Copyright 2019 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 example.app.crm.config; + +import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newRuntimeException; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.data.cassandra.config.AbstractCassandraConfiguration; +import org.springframework.data.cassandra.config.CassandraClusterFactoryBean; +import org.springframework.data.gemfire.tests.util.IOUtils; +import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; +import org.springframework.util.StringUtils; + +/** + * Base test configuration used to configure and bootstrap an Apache Cassandra database with a schema and data. + * + * @author John Blum + * @see org.springframework.core.io.Resource + * @see org.springframework.data.cassandra.config.AbstractCassandraConfiguration + * @see org.springframework.data.cassandra.config.CassandraClusterFactoryBean + * @since 1.1.0 + */ +public abstract class TestCassandraConfiguration extends AbstractCassandraConfiguration { + + private static final boolean CASSANDRA_METRICS_ENABLED = false; + + protected static final int CASSANDRA_DEFAULT_PORT = CassandraClusterFactoryBean.DEFAULT_PORT; + + private static final String CASSANDRA_DATA_CQL = "cassandra-data.cql"; + private static final String CASSANDRA_SCHEMA_CQL = "cassandra-schema.cql"; + private static final String CLUSTER_NAME = "CustomerServiceCluster"; + private static final String KEYSPACE_NAME = "CustomerService"; + + @Nullable @Override + protected String getClusterName() { + return CLUSTER_NAME; + } + + @NonNull @Override + protected String getKeyspaceName() { + return KEYSPACE_NAME; + } + + @Override + protected boolean getMetricsEnabled() { + return CASSANDRA_METRICS_ENABLED; + } + + @Override + protected List getStartupScripts() { + + List startupScripts = new ArrayList<>(super.getStartupScripts()); + + startupScripts.addAll(readLines(new ClassPathResource(CASSANDRA_SCHEMA_CQL))); + startupScripts.addAll(readLines(new ClassPathResource(CASSANDRA_DATA_CQL))); + + return startupScripts; + } + + private List readLines(Resource resource) { + + BufferedReader resourceReader = null; + + try { + + resourceReader = new BufferedReader(new InputStreamReader(resource.getInputStream())); + + return resourceReader.lines() + .filter(StringUtils::hasText) + .collect(Collectors.toList()); + } + catch (IOException cause) { + throw newRuntimeException(cause, "Failed to read from Resource [%s]", resource); + } + finally { + IOUtils.close(resourceReader); + } + } +} diff --git a/spring-geode/src/test/java/org/springframework/geode/cache/inline/cassandra/InlineCachingWithCassandraIntegrationTests.java b/spring-geode/src/test/java/org/springframework/geode/cache/inline/cassandra/InlineCachingWithCassandraIntegrationTests.java new file mode 100644 index 00000000..646139ce --- /dev/null +++ b/spring-geode/src/test/java/org/springframework/geode/cache/inline/cassandra/InlineCachingWithCassandraIntegrationTests.java @@ -0,0 +1,90 @@ +/* + * Copyright 2019 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.cache.inline.cassandra; + +import java.util.function.Predicate; + +import org.junit.runner.RunWith; + +import org.apache.geode.cache.GemFireCache; +import org.apache.geode.cache.client.ClientRegionShortcut; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.DependsOn; +import org.springframework.context.annotation.Import; +import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories; +import org.springframework.data.gemfire.GemfireTemplate; +import org.springframework.data.gemfire.config.annotation.ClientCacheApplication; +import org.springframework.data.gemfire.config.annotation.EnableEntityDefinedRegions; +import org.springframework.geode.cache.InlineCachingRegionConfigurer; +import org.springframework.geode.cache.inline.AbstractInlineCachingWithExternalDataSourceIntegrationTests; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +import example.app.crm.config.CassandraConfiguration; +import example.app.crm.model.Customer; +import example.app.crm.repo.CustomerRepository; + +/** + * Spring Boot Integration Tests testing the Inline Caching support using Apache Cassandra. + * + * @author John Blum + * @see org.junit.Test + * @see org.apache.geode.cache.GemFireCache + * @see org.springframework.boot.autoconfigure.SpringBootApplication + * @see org.springframework.boot.test.context.SpringBootTest + * @see org.springframework.context.annotation.Bean + * @see org.springframework.context.annotation.Import + * @see org.springframework.data.cassandra.repository.config.EnableCassandraRepositories + * @see org.springframework.data.gemfire.GemfireTemplate + * @see org.springframework.data.gemfire.config.annotation.ClientCacheApplication + * @see org.springframework.data.gemfire.config.annotation.EnableEntityDefinedRegions + * @see org.springframework.geode.cache.InlineCachingRegionConfigurer + * @see org.springframework.geode.cache.inline.AbstractInlineCachingWithExternalDataSourceIntegrationTests + * @see org.springframework.test.context.junit4.SpringRunner + * @since 1.1.0 + */ +@SpringBootTest +@RunWith(SpringRunner.class) +@ActiveProfiles("inline-caching-cassandra") +@SuppressWarnings("unused") +public class InlineCachingWithCassandraIntegrationTests + extends AbstractInlineCachingWithExternalDataSourceIntegrationTests { + + @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) + @ClientCacheApplication(logLevel = GEMFIRE_LOG_LEVEL) + @EnableEntityDefinedRegions(basePackageClasses = Customer.class, clientRegionShortcut = ClientRegionShortcut.LOCAL) + @EnableCassandraRepositories(basePackageClasses = CustomerRepository.class) + @Import(CassandraConfiguration.class) + static class TestGeodeClientConfiguration { + + @Bean + @DependsOn("Customers") + GemfireTemplate customersTemplate(GemFireCache gemfireCache) { + return new GemfireTemplate(gemfireCache.getRegion("/Customers")); + } + + @Bean + InlineCachingRegionConfigurer inlineCachingForCustomersRegionConfigurer( + CustomerRepository customerRepository) { + + return new InlineCachingRegionConfigurer<>(customerRepository, Predicate.isEqual("Customers")); + } + } +} diff --git a/spring-geode/src/test/resources/cassandra-data.cql b/spring-geode/src/test/resources/cassandra-data.cql new file mode 100644 index 00000000..9c64b2f2 --- /dev/null +++ b/spring-geode/src/test/resources/cassandra-data.cql @@ -0,0 +1 @@ +INSERT INTO customers (id, name) VALUES (16, 'Pie Doe'); diff --git a/spring-geode/src/test/resources/cassandra-schema.cql b/spring-geode/src/test/resources/cassandra-schema.cql new file mode 100644 index 00000000..89ddcf17 --- /dev/null +++ b/spring-geode/src/test/resources/cassandra-schema.cql @@ -0,0 +1,4 @@ +CREATE KEYSPACE IF NOT EXISTS CustomerService WITH replication = { 'class':'SimpleStrategy', 'replication_factor':1 }; +USE CustomerService; +CREATE TABLE IF NOT EXISTS customers (id BIGINT PRIMARY KEY, name TEXT); +CREATE INDEX IF NOT EXISTS CustomerNameIdx ON customers(name);