diff --git a/spring-geode-project/spring-geode/src/test/java/example/app/crm/config/TestCassandraConfiguration.java b/spring-geode-project/spring-geode/src/test/java/example/app/crm/config/TestCassandraConfiguration.java index 3233d2d5..7335da18 100644 --- a/spring-geode-project/spring-geode/src/test/java/example/app/crm/config/TestCassandraConfiguration.java +++ b/spring-geode-project/spring-geode/src/test/java/example/app/crm/config/TestCassandraConfiguration.java @@ -27,6 +27,7 @@ import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.context.ApplicationListener; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Profile; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; @@ -38,6 +39,7 @@ import org.springframework.data.cassandra.core.cql.RowMapper; import org.springframework.data.cassandra.core.cql.session.init.KeyspacePopulator; import org.springframework.data.cassandra.core.cql.session.init.ResourceKeyspacePopulator; import org.springframework.data.cassandra.core.cql.session.init.SessionFactoryInitializer; +import org.springframework.lang.NonNull; import example.app.crm.model.Customer; import example.app.crm.repo.CustomerRepository; @@ -64,6 +66,8 @@ public abstract class TestCassandraConfiguration { private static final boolean CONTINUE_ON_ERROR = false; private static final boolean IGNORE_FAILED_DROPS = true; + private static final Customer pieDoe = Customer.newCustomer(16L, "Pie Doe"); + private static final String CQL_SCRIPT_ENCODING = null; protected static final int CASSANDRA_DEFAULT_PORT = CqlSessionFactoryBean.DEFAULT_PORT; @@ -71,8 +75,21 @@ public abstract class TestCassandraConfiguration { protected static final String CASSANDRA_DATA_CQL = "cassandra-data.cql"; protected static final String CASSANDRA_INIT_CQL = "cassandra-init.cql"; protected static final String CASSANDRA_SCHEMA_CQL = "cassandra-schema.cql"; - protected static final String LOCAL_DATA_CENTER = "datacenter1"; + protected static final String DEBUGGING_PROFILE = "debugging"; protected static final String KEYSPACE_NAME = "CustomerService"; + protected static final String TABLE_NAME = "Customers"; + + protected @NonNull Resource newCassandraDataCqlScriptResource() { + return new ClassPathResource(CASSANDRA_DATA_CQL); + } + + protected @NonNull Resource newCassandraInitCqlScriptResource() { + return new ClassPathResource(CASSANDRA_INIT_CQL); + } + + protected @NonNull Resource newCassandraSchemaCqlScriptResource() { + return new ClassPathResource(CASSANDRA_SCHEMA_CQL); + } @Bean SessionFactoryInitializer sessionFactoryInitializer(SessionFactory sessionFactory) { @@ -87,24 +104,12 @@ public abstract class TestCassandraConfiguration { return sessionFactoryInitializer; } - protected Resource newCassandraDataCqlScriptResource() { - return new ClassPathResource(CASSANDRA_DATA_CQL); - } - - protected Resource newCassandraInitCqlScriptResource() { - return new ClassPathResource(CASSANDRA_INIT_CQL); - } - - protected Resource newCassandraSchemaCqlScriptResource() { - return new ClassPathResource(CASSANDRA_SCHEMA_CQL); - } - - protected KeyspacePopulator newKeyspacePopulator(Resource... cqlScripts) { + protected @NonNull KeyspacePopulator newKeyspacePopulator(Resource... cqlScripts) { return new ResourceKeyspacePopulator(CONTINUE_ON_ERROR, IGNORE_FAILED_DROPS, CQL_SCRIPT_ENCODING, cqlScripts); - //return cqlScript -> {}; } @Bean + @Profile(DEBUGGING_PROFILE) BeanPostProcessor cassandraTemplatePostProcessor() { return new BeanPostProcessor() { @@ -114,11 +119,12 @@ public abstract class TestCassandraConfiguration { if (bean instanceof CassandraTemplate cassandraTemplate) { - Consumer cassandraTemplateConsumer = noopCassandraTemplateConsumer(); - //.andThen(entityObjectInsertingCassandraTemplateConsumer()) - //.andThen(entityObjectAssertingCassandraTemplateConsumer()); - //.andThen(keyspaceNameAssertingCassandraTemplateConsumer()) - //.andThen(tableNameAssertingCassandraTemplateConsumer()); + Consumer cassandraTemplateConsumer = noopCassandraTemplateConsumer() + .andThen(insertEntityObjectCassandraTemplateConsumer()) + .andThen(assertEntityCountCassandraTemplateConsumer()) + .andThen(assertEntityObjectCassandraTemplateConsumer()) + .andThen(assertKeyspaceNameCassandraTemplateConsumer()) + .andThen(assertTableNameCassandraTemplateConsumer()); cassandraTemplateConsumer.accept(cassandraTemplate); } @@ -132,35 +138,32 @@ public abstract class TestCassandraConfiguration { return cassandraTemplate -> {}; } - private Consumer entityCountAssertingCassandraTemplateConsumer() { + private Consumer assertEntityCountCassandraTemplateConsumer() { return cassandraTemplate -> assertThat(cassandraTemplate.count(Customer.class)).isOne(); } - private Consumer entityObjectAssertingCassandraTemplateConsumer() { + private Consumer assertEntityObjectCassandraTemplateConsumer() { return cassandraTemplate -> { - String cql = "SELECT id, name FROM Customers"; + String cql = "SELECT id, name FROM \"Customers\""; RowMapper customerRowMapper = (row, rowNumber) -> Customer.newCustomer(row.getLong("id"), row.getString("name")); Customer actualCustomer = cassandraTemplate.getCqlOperations().queryForObject(cql, customerRowMapper); - Customer expectedCustomer = Customer.newCustomer(16L, "Pie Doe"); - assertThat(actualCustomer).isEqualTo(expectedCustomer); - //assertThat(cassandraTemplate.selectOneById(16L, Customer.class)).isEqualTo(expectedCustomer); - //assertThat(cassandraTemplate.query(Customer.class).stream().findFirst().orElse(null)) - // .isEqualTo(expectedCustomer); + assertThat(actualCustomer).isEqualTo(pieDoe); + assertThat(cassandraTemplate.selectOneById(16L, Customer.class)).isEqualTo(pieDoe); + assertThat(cassandraTemplate.query(Customer.class).stream().findFirst().orElse(null)).isEqualTo(pieDoe); }; } - // TODO: Why does this work and the CQL data script not work! - private Consumer entityObjectInsertingCassandraTemplateConsumer() { - return cassandraTemplate -> cassandraTemplate.insert(Customer.newCustomer(16L, "Pie Doe")); + private Consumer insertEntityObjectCassandraTemplateConsumer() { + return cassandraTemplate -> cassandraTemplate.insert(pieDoe); } - private Consumer keyspaceNameAssertingCassandraTemplateConsumer() { + private Consumer assertKeyspaceNameCassandraTemplateConsumer() { return cassandraTemplate -> { @@ -177,7 +180,7 @@ public abstract class TestCassandraConfiguration { }; } - private Consumer tableNameAssertingCassandraTemplateConsumer() { + private Consumer assertTableNameCassandraTemplateConsumer() { return cassandraTemplate -> { @@ -198,7 +201,10 @@ public abstract class TestCassandraConfiguration { } @Bean - ApplicationListener populateCassandraDatabaseUsingRepository(CustomerRepository customerRepository) { - return event -> customerRepository.save(Customer.newCustomer(16L, "Pie Doe")); + @Profile(DEBUGGING_PROFILE) + ApplicationListener populateCassandraDatabaseUsingRepository( + CustomerRepository customerRepository) { + + return event -> customerRepository.save(pieDoe); } } diff --git a/spring-geode-project/spring-geode/src/test/java/example/app/crm/config/TestcontainersCassandraConfiguration.java b/spring-geode-project/spring-geode/src/test/java/example/app/crm/config/TestcontainersCassandraConfiguration.java index 43953417..336acc75 100644 --- a/spring-geode-project/spring-geode/src/test/java/example/app/crm/config/TestcontainersCassandraConfiguration.java +++ b/spring-geode-project/spring-geode/src/test/java/example/app/crm/config/TestcontainersCassandraConfiguration.java @@ -18,15 +18,18 @@ package example.app.crm.config; import static org.assertj.core.api.Assertions.assertThat; import java.net.InetSocketAddress; +import java.util.Arrays; import com.datastax.oss.driver.api.core.CqlSession; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.cassandra.CassandraProperties; import org.springframework.boot.autoconfigure.cassandra.CqlSessionBuilderCustomizer; import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; +import org.springframework.core.env.Environment; import org.springframework.data.cassandra.core.CassandraTemplate; import org.springframework.lang.NonNull; @@ -57,29 +60,29 @@ import example.app.crm.model.Customer; public class TestcontainersCassandraConfiguration extends TestCassandraConfiguration { private static final String CASSANDRA_DOCKER_IMAGE_NAME = "cassandra:latest"; + private static final String LOCAL_DATACENTER_NAME = "datacenter1"; @Bean("CassandraContainer") - @SuppressWarnings("rawtypes") - GenericContainer cassandraContainer() { + GenericContainer cassandraContainer(Environment environment) { - GenericContainer cassandraContainer = newEnvironmentTunedCassandraContainer(); + GenericContainer cassandraContainer = newEnvironmentOptimizedCassandraContainer(); cassandraContainer.start(); - return withCassandraServer(cassandraContainer); + return withCassandraServer(cassandraContainer, environment); } - @SuppressWarnings("rawtypes") - private @NonNull GenericContainer newCassandraContainer() { - return new CassandraContainer(CASSANDRA_DOCKER_IMAGE_NAME) + private @NonNull GenericContainer newCassandraContainer() { + + return new CassandraContainer<>(CASSANDRA_DOCKER_IMAGE_NAME) .withInitScript(CASSANDRA_SCHEMA_CQL) //.withInitScript(CASSANDRA_INIT_CQL) .withExposedPorts(CASSANDRA_DEFAULT_PORT) .withReuse(true); } - @SuppressWarnings("rawtypes") - private @NonNull GenericContainer newEnvironmentTunedCassandraContainer() { + // Information (feedback) received from Sergei Egorov. + private @NonNull GenericContainer newEnvironmentOptimizedCassandraContainer() { return newCassandraContainer() .withEnv("CASSANDRA_SNITCH", "GossipingPropertyFileSnitch") @@ -96,19 +99,22 @@ public class TestcontainersCassandraConfiguration extends TestCassandraConfigura return CqlSession.builder() .addContactPoint(resolveContactPoint(cassandraContainer)) - .withLocalDatacenter(LOCAL_DATA_CENTER) + .withLocalDatacenter(LOCAL_DATACENTER_NAME) .build(); } - private @NonNull GenericContainer withCassandraServer(@NonNull GenericContainer cassandraContainer) { + private @NonNull GenericContainer withCassandraServer(@NonNull GenericContainer cassandraContainer, + @NonNull Environment environment) { - //cassandraContainer = initializeCassandraServer(cassandraContainer); - cassandraContainer = assertCassandraServerSetup(cassandraContainer); + if (Arrays.asList(environment.getActiveProfiles()).contains(DEBUGGING_PROFILE)) { + cassandraContainer = initializeCassandraServer(cassandraContainer); + cassandraContainer = assertCassandraServerSetup(cassandraContainer); + } return cassandraContainer; } - private GenericContainer initializeCassandraServer(GenericContainer cassandraContainer) { + private @NonNull GenericContainer initializeCassandraServer(@NonNull GenericContainer cassandraContainer) { try (CqlSession session = newCqlSession(cassandraContainer)) { newKeyspacePopulator(newCassandraSchemaCqlScriptResource()).populate(session); @@ -117,7 +123,7 @@ public class TestcontainersCassandraConfiguration extends TestCassandraConfigura return cassandraContainer; } - private GenericContainer assertCassandraServerSetup(GenericContainer cassandraContainer) { + private @NonNull GenericContainer assertCassandraServerSetup(@NonNull GenericContainer cassandraContainer) { try (CqlSession session = newCqlSession(cassandraContainer)) { @@ -126,16 +132,16 @@ public class TestcontainersCassandraConfiguration extends TestCassandraConfigura assertThat(keyspaceMetadata.getName().toString()).isEqualToIgnoringCase(KEYSPACE_NAME); - keyspaceMetadata.getTable("Customers") + keyspaceMetadata.getTable(TABLE_NAME) .map(tableMetadata -> { - assertThat(tableMetadata.getName().toString()).isEqualToIgnoringCase("Customers"); + assertThat(tableMetadata.getName().toString()).isEqualTo(TABLE_NAME); assertThat(tableMetadata.getKeyspace().toString()).isEqualToIgnoringCase(KEYSPACE_NAME); //assertCustomersTableHasSizeOne(session); return tableMetadata; }) - .orElseThrow(() -> new IllegalStateException("Table [Customers] not found")); + .orElseThrow(() -> new IllegalStateException(String.format("Table [%s] not found", TABLE_NAME))); return keyspaceMetadata; }) @@ -145,25 +151,26 @@ public class TestcontainersCassandraConfiguration extends TestCassandraConfigura return cassandraContainer; } - private void assertCustomersTableHasSizeOne(CqlSession session) { + private void assertCustomersTableHasSizeOne(@NonNull CqlSession session) { CassandraTemplate template = newCassandraTemplate(session); assertThat(template.getCqlOperations().execute(String.format("USE %s;", KEYSPACE_NAME))).isTrue(); - assertThat(template.getCqlOperations().queryForObject("SELECT count(*) FROM Customers", Long.class)).isOne(); + assertThat(template.getCqlOperations().queryForObject("SELECT count(*) FROM \"Customers\"", Long.class)).isOne(); //assertThat(template.count(Customer.class)).isOne(); // Table Customers not found; needs to use the Keyspace } @Bean - CqlSessionBuilderCustomizer cqlSessionBuilderCustomizer( + CqlSessionBuilderCustomizer cqlSessionBuilderCustomizer(CassandraProperties properties, @Qualifier("CassandraContainer") GenericContainer cassandraContainer) { - return cqlSessionBuilder -> cqlSessionBuilder.addContactPoint(resolveContactPoint(cassandraContainer)) - .withLocalDatacenter(LOCAL_DATA_CENTER) - .withKeyspace(KEYSPACE_NAME); + return cqlSessionBuilder -> cqlSessionBuilder + .addContactPoint(resolveContactPoint(cassandraContainer)) + .withLocalDatacenter(properties.getLocalDatacenter()) + .withKeyspace(properties.getKeyspaceName()); } - private InetSocketAddress resolveContactPoint(GenericContainer cassandraContainer) { + private @NonNull InetSocketAddress resolveContactPoint(@NonNull GenericContainer cassandraContainer) { return new InetSocketAddress(cassandraContainer.getHost(), cassandraContainer.getMappedPort(CASSANDRA_DEFAULT_PORT)); } diff --git a/spring-geode-project/spring-geode/src/test/java/example/app/crm/model/Customer.java b/spring-geode-project/spring-geode/src/test/java/example/app/crm/model/Customer.java index 249bc0bc..36dcdd80 100644 --- a/spring-geode-project/spring-geode/src/test/java/example/app/crm/model/Customer.java +++ b/spring-geode-project/spring-geode/src/test/java/example/app/crm/model/Customer.java @@ -18,7 +18,6 @@ package example.app.crm.model; import jakarta.persistence.Entity; import jakarta.persistence.Table; -import org.springframework.data.annotation.Id; import org.springframework.data.cassandra.core.mapping.Indexed; import org.springframework.data.cassandra.core.mapping.PrimaryKey; import org.springframework.data.gemfire.mapping.annotation.Region; @@ -34,7 +33,8 @@ import lombok.NoArgsConstructor; * @author John Blum * @see jakarta.persistence.Entity * @see jakarta.persistence.Table - * @see org.springframework.data.annotation.Id + * @see org.springframework.data.cassandra.core.mapping.Indexed + * @see org.springframework.data.cassandra.core.mapping.PrimaryKey * @see org.springframework.data.cassandra.core.mapping.Table * @see org.springframework.data.gemfire.mapping.annotation.Region * @since 1.1.0 @@ -48,9 +48,8 @@ import lombok.NoArgsConstructor; @AllArgsConstructor(staticName = "newCustomer") public class Customer { - @Id - @jakarta.persistence.Id @PrimaryKey + @jakarta.persistence.Id private Long id; @Indexed diff --git a/spring-geode-project/spring-geode/src/test/resources/cassandra-data.cql b/spring-geode-project/spring-geode/src/test/resources/cassandra-data.cql index 732dfb2f..2b682ebb 100644 --- a/spring-geode-project/spring-geode/src/test/resources/cassandra-data.cql +++ b/spring-geode-project/spring-geode/src/test/resources/cassandra-data.cql @@ -1 +1 @@ -INSERT INTO Customers (id, name) VALUES (16, 'Pie Doe'); +INSERT INTO "Customers" (id, name) VALUES (16, 'Pie Doe'); diff --git a/spring-geode-project/spring-geode/src/test/resources/cassandra-init.cql b/spring-geode-project/spring-geode/src/test/resources/cassandra-init.cql index 8349aebb..c0f63a65 100644 --- a/spring-geode-project/spring-geode/src/test/resources/cassandra-init.cql +++ b/spring-geode-project/spring-geode/src/test/resources/cassandra-init.cql @@ -1,4 +1,5 @@ CREATE KEYSPACE IF NOT EXISTS CustomerService WITH replication = { 'class':'SimpleStrategy', 'replication_factor':1 }; -CREATE TABLE IF NOT EXISTS CustomerService.Customers (id BIGINT PRIMARY KEY, name TEXT); -CREATE INDEX IF NOT EXISTS CustomerNameIdx ON CustomerService.Customers(name); -INSERT INTO CustomerService.Customers (id, name) VALUES (16, 'Pie Doe'); +USE CustomerService; +CREATE TABLE IF NOT EXISTS "Customers" (id BIGINT PRIMARY KEY, name TEXT); +CREATE INDEX IF NOT EXISTS CustomerNameIdx ON "Customers"(name); +INSERT INTO "Customers" (id, name) VALUES (16, 'Pie Doe'); diff --git a/spring-geode-project/spring-geode/src/test/resources/cassandra-schema.cql b/spring-geode-project/spring-geode/src/test/resources/cassandra-schema.cql index 5e5b3b6c..80d7a04e 100644 --- a/spring-geode-project/spring-geode/src/test/resources/cassandra-schema.cql +++ b/spring-geode-project/spring-geode/src/test/resources/cassandra-schema.cql @@ -1,4 +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); +CREATE TABLE IF NOT EXISTS "Customers" (id BIGINT PRIMARY KEY, name TEXT); +CREATE INDEX IF NOT EXISTS CustomerNameIdx ON "Customers"(name);