Skip to content

Commit 9cdeaf0

Browse files
committed
Apply addiitional polishing to the Inline Caching with Apache Cassandra Integration Tests.
The refactorings and code changes are based on feedback from Mark Paluch regarding Apache Cassandra and Spring Data for Apache Cassandra. Note: a developer must quote the CqlIdentifier (e.g. table names) when the case is mixed.
1 parent 1740f16 commit 9cdeaf0

File tree

6 files changed

+83
-70
lines changed

6 files changed

+83
-70
lines changed

spring-geode-project/spring-geode/src/test/java/example/app/crm/config/TestCassandraConfiguration.java

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.beans.factory.config.BeanPostProcessor;
2828
import org.springframework.context.ApplicationListener;
2929
import org.springframework.context.annotation.Bean;
30+
import org.springframework.context.annotation.Profile;
3031
import org.springframework.context.event.ContextRefreshedEvent;
3132
import org.springframework.core.io.ClassPathResource;
3233
import org.springframework.core.io.Resource;
@@ -38,6 +39,7 @@
3839
import org.springframework.data.cassandra.core.cql.session.init.KeyspacePopulator;
3940
import org.springframework.data.cassandra.core.cql.session.init.ResourceKeyspacePopulator;
4041
import org.springframework.data.cassandra.core.cql.session.init.SessionFactoryInitializer;
42+
import org.springframework.lang.NonNull;
4143

4244
import example.app.crm.model.Customer;
4345
import example.app.crm.repo.CustomerRepository;
@@ -64,15 +66,30 @@ public abstract class TestCassandraConfiguration {
6466
private static final boolean CONTINUE_ON_ERROR = false;
6567
private static final boolean IGNORE_FAILED_DROPS = true;
6668

69+
private static final Customer pieDoe = Customer.newCustomer(16L, "Pie Doe");
70+
6771
private static final String CQL_SCRIPT_ENCODING = null;
6872

6973
protected static final int CASSANDRA_DEFAULT_PORT = CqlSessionFactoryBean.DEFAULT_PORT;
7074

7175
protected static final String CASSANDRA_DATA_CQL = "cassandra-data.cql";
7276
protected static final String CASSANDRA_INIT_CQL = "cassandra-init.cql";
7377
protected static final String CASSANDRA_SCHEMA_CQL = "cassandra-schema.cql";
74-
protected static final String LOCAL_DATA_CENTER = "datacenter1";
78+
protected static final String DEBUGGING_PROFILE = "debugging";
7579
protected static final String KEYSPACE_NAME = "CustomerService";
80+
protected static final String TABLE_NAME = "Customers";
81+
82+
protected @NonNull Resource newCassandraDataCqlScriptResource() {
83+
return new ClassPathResource(CASSANDRA_DATA_CQL);
84+
}
85+
86+
protected @NonNull Resource newCassandraInitCqlScriptResource() {
87+
return new ClassPathResource(CASSANDRA_INIT_CQL);
88+
}
89+
90+
protected @NonNull Resource newCassandraSchemaCqlScriptResource() {
91+
return new ClassPathResource(CASSANDRA_SCHEMA_CQL);
92+
}
7693

7794
@Bean
7895
SessionFactoryInitializer sessionFactoryInitializer(SessionFactory sessionFactory) {
@@ -87,24 +104,12 @@ SessionFactoryInitializer sessionFactoryInitializer(SessionFactory sessionFactor
87104
return sessionFactoryInitializer;
88105
}
89106

90-
protected Resource newCassandraDataCqlScriptResource() {
91-
return new ClassPathResource(CASSANDRA_DATA_CQL);
92-
}
93-
94-
protected Resource newCassandraInitCqlScriptResource() {
95-
return new ClassPathResource(CASSANDRA_INIT_CQL);
96-
}
97-
98-
protected Resource newCassandraSchemaCqlScriptResource() {
99-
return new ClassPathResource(CASSANDRA_SCHEMA_CQL);
100-
}
101-
102-
protected KeyspacePopulator newKeyspacePopulator(Resource... cqlScripts) {
107+
protected @NonNull KeyspacePopulator newKeyspacePopulator(Resource... cqlScripts) {
103108
return new ResourceKeyspacePopulator(CONTINUE_ON_ERROR, IGNORE_FAILED_DROPS, CQL_SCRIPT_ENCODING, cqlScripts);
104-
//return cqlScript -> {};
105109
}
106110

107111
@Bean
112+
@Profile(DEBUGGING_PROFILE)
108113
BeanPostProcessor cassandraTemplatePostProcessor() {
109114

110115
return new BeanPostProcessor() {
@@ -114,11 +119,12 @@ public Object postProcessAfterInitialization(Object bean, String beanName) throw
114119

115120
if (bean instanceof CassandraTemplate cassandraTemplate) {
116121

117-
Consumer<CassandraTemplate> cassandraTemplateConsumer = noopCassandraTemplateConsumer();
118-
//.andThen(entityObjectInsertingCassandraTemplateConsumer())
119-
//.andThen(entityObjectAssertingCassandraTemplateConsumer());
120-
//.andThen(keyspaceNameAssertingCassandraTemplateConsumer())
121-
//.andThen(tableNameAssertingCassandraTemplateConsumer());
122+
Consumer<CassandraTemplate> cassandraTemplateConsumer = noopCassandraTemplateConsumer()
123+
.andThen(insertEntityObjectCassandraTemplateConsumer())
124+
.andThen(assertEntityCountCassandraTemplateConsumer())
125+
.andThen(assertEntityObjectCassandraTemplateConsumer())
126+
.andThen(assertKeyspaceNameCassandraTemplateConsumer())
127+
.andThen(assertTableNameCassandraTemplateConsumer());
122128

123129
cassandraTemplateConsumer.accept(cassandraTemplate);
124130
}
@@ -132,35 +138,32 @@ private Consumer<CassandraTemplate> noopCassandraTemplateConsumer() {
132138
return cassandraTemplate -> {};
133139
}
134140

135-
private Consumer<CassandraTemplate> entityCountAssertingCassandraTemplateConsumer() {
141+
private Consumer<CassandraTemplate> assertEntityCountCassandraTemplateConsumer() {
136142
return cassandraTemplate -> assertThat(cassandraTemplate.count(Customer.class)).isOne();
137143
}
138144

139-
private Consumer<CassandraTemplate> entityObjectAssertingCassandraTemplateConsumer() {
145+
private Consumer<CassandraTemplate> assertEntityObjectCassandraTemplateConsumer() {
140146

141147
return cassandraTemplate -> {
142148

143-
String cql = "SELECT id, name FROM Customers";
149+
String cql = "SELECT id, name FROM \"Customers\"";
144150

145151
RowMapper<Customer> customerRowMapper = (row, rowNumber) ->
146152
Customer.newCustomer(row.getLong("id"), row.getString("name"));
147153

148154
Customer actualCustomer = cassandraTemplate.getCqlOperations().queryForObject(cql, customerRowMapper);
149-
Customer expectedCustomer = Customer.newCustomer(16L, "Pie Doe");
150155

151-
assertThat(actualCustomer).isEqualTo(expectedCustomer);
152-
//assertThat(cassandraTemplate.selectOneById(16L, Customer.class)).isEqualTo(expectedCustomer);
153-
//assertThat(cassandraTemplate.query(Customer.class).stream().findFirst().orElse(null))
154-
// .isEqualTo(expectedCustomer);
156+
assertThat(actualCustomer).isEqualTo(pieDoe);
157+
assertThat(cassandraTemplate.selectOneById(16L, Customer.class)).isEqualTo(pieDoe);
158+
assertThat(cassandraTemplate.query(Customer.class).stream().findFirst().orElse(null)).isEqualTo(pieDoe);
155159
};
156160
}
157161

158-
// TODO: Why does this work and the CQL data script not work!
159-
private Consumer<CassandraTemplate> entityObjectInsertingCassandraTemplateConsumer() {
160-
return cassandraTemplate -> cassandraTemplate.insert(Customer.newCustomer(16L, "Pie Doe"));
162+
private Consumer<CassandraTemplate> insertEntityObjectCassandraTemplateConsumer() {
163+
return cassandraTemplate -> cassandraTemplate.insert(pieDoe);
161164
}
162165

163-
private Consumer<CassandraTemplate> keyspaceNameAssertingCassandraTemplateConsumer() {
166+
private Consumer<CassandraTemplate> assertKeyspaceNameCassandraTemplateConsumer() {
164167

165168
return cassandraTemplate -> {
166169

@@ -177,7 +180,7 @@ private Consumer<CassandraTemplate> keyspaceNameAssertingCassandraTemplateConsum
177180
};
178181
}
179182

180-
private Consumer<CassandraTemplate> tableNameAssertingCassandraTemplateConsumer() {
183+
private Consumer<CassandraTemplate> assertTableNameCassandraTemplateConsumer() {
181184

182185
return cassandraTemplate -> {
183186

@@ -198,7 +201,10 @@ private Consumer<CassandraTemplate> tableNameAssertingCassandraTemplateConsumer(
198201
}
199202

200203
@Bean
201-
ApplicationListener<ContextRefreshedEvent> populateCassandraDatabaseUsingRepository(CustomerRepository customerRepository) {
202-
return event -> customerRepository.save(Customer.newCustomer(16L, "Pie Doe"));
204+
@Profile(DEBUGGING_PROFILE)
205+
ApplicationListener<ContextRefreshedEvent> populateCassandraDatabaseUsingRepository(
206+
CustomerRepository customerRepository) {
207+
208+
return event -> customerRepository.save(pieDoe);
203209
}
204210
}

spring-geode-project/spring-geode/src/test/java/example/app/crm/config/TestcontainersCassandraConfiguration.java

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,18 @@
1818
import static org.assertj.core.api.Assertions.assertThat;
1919

2020
import java.net.InetSocketAddress;
21+
import java.util.Arrays;
2122

2223
import com.datastax.oss.driver.api.core.CqlSession;
2324

2425
import org.springframework.beans.factory.annotation.Qualifier;
26+
import org.springframework.boot.autoconfigure.cassandra.CassandraProperties;
2527
import org.springframework.boot.autoconfigure.cassandra.CqlSessionBuilderCustomizer;
2628
import org.springframework.boot.autoconfigure.domain.EntityScan;
2729
import org.springframework.context.annotation.Bean;
2830
import org.springframework.context.annotation.Configuration;
2931
import org.springframework.context.annotation.Profile;
32+
import org.springframework.core.env.Environment;
3033
import org.springframework.data.cassandra.core.CassandraTemplate;
3134
import org.springframework.lang.NonNull;
3235

@@ -57,29 +60,29 @@
5760
public class TestcontainersCassandraConfiguration extends TestCassandraConfiguration {
5861

5962
private static final String CASSANDRA_DOCKER_IMAGE_NAME = "cassandra:latest";
63+
private static final String LOCAL_DATACENTER_NAME = "datacenter1";
6064

6165
@Bean("CassandraContainer")
62-
@SuppressWarnings("rawtypes")
63-
GenericContainer cassandraContainer() {
66+
GenericContainer<?> cassandraContainer(Environment environment) {
6467

65-
GenericContainer cassandraContainer = newEnvironmentTunedCassandraContainer();
68+
GenericContainer<?> cassandraContainer = newEnvironmentOptimizedCassandraContainer();
6669

6770
cassandraContainer.start();
6871

69-
return withCassandraServer(cassandraContainer);
72+
return withCassandraServer(cassandraContainer, environment);
7073
}
7174

72-
@SuppressWarnings("rawtypes")
73-
private @NonNull GenericContainer newCassandraContainer() {
74-
return new CassandraContainer(CASSANDRA_DOCKER_IMAGE_NAME)
75+
private @NonNull GenericContainer<?> newCassandraContainer() {
76+
77+
return new CassandraContainer<>(CASSANDRA_DOCKER_IMAGE_NAME)
7578
.withInitScript(CASSANDRA_SCHEMA_CQL)
7679
//.withInitScript(CASSANDRA_INIT_CQL)
7780
.withExposedPorts(CASSANDRA_DEFAULT_PORT)
7881
.withReuse(true);
7982
}
8083

81-
@SuppressWarnings("rawtypes")
82-
private @NonNull GenericContainer newEnvironmentTunedCassandraContainer() {
84+
// Information (feedback) received from Sergei Egorov.
85+
private @NonNull GenericContainer<?> newEnvironmentOptimizedCassandraContainer() {
8386

8487
return newCassandraContainer()
8588
.withEnv("CASSANDRA_SNITCH", "GossipingPropertyFileSnitch")
@@ -96,19 +99,22 @@ GenericContainer cassandraContainer() {
9699

97100
return CqlSession.builder()
98101
.addContactPoint(resolveContactPoint(cassandraContainer))
99-
.withLocalDatacenter(LOCAL_DATA_CENTER)
102+
.withLocalDatacenter(LOCAL_DATACENTER_NAME)
100103
.build();
101104
}
102105

103-
private @NonNull GenericContainer<?> withCassandraServer(@NonNull GenericContainer<?> cassandraContainer) {
106+
private @NonNull GenericContainer<?> withCassandraServer(@NonNull GenericContainer<?> cassandraContainer,
107+
@NonNull Environment environment) {
104108

105-
//cassandraContainer = initializeCassandraServer(cassandraContainer);
106-
cassandraContainer = assertCassandraServerSetup(cassandraContainer);
109+
if (Arrays.asList(environment.getActiveProfiles()).contains(DEBUGGING_PROFILE)) {
110+
cassandraContainer = initializeCassandraServer(cassandraContainer);
111+
cassandraContainer = assertCassandraServerSetup(cassandraContainer);
112+
}
107113

108114
return cassandraContainer;
109115
}
110116

111-
private GenericContainer<?> initializeCassandraServer(GenericContainer<?> cassandraContainer) {
117+
private @NonNull GenericContainer<?> initializeCassandraServer(@NonNull GenericContainer<?> cassandraContainer) {
112118

113119
try (CqlSession session = newCqlSession(cassandraContainer)) {
114120
newKeyspacePopulator(newCassandraSchemaCqlScriptResource()).populate(session);
@@ -117,7 +123,7 @@ private GenericContainer<?> initializeCassandraServer(GenericContainer<?> cassan
117123
return cassandraContainer;
118124
}
119125

120-
private GenericContainer<?> assertCassandraServerSetup(GenericContainer<?> cassandraContainer) {
126+
private @NonNull GenericContainer<?> assertCassandraServerSetup(@NonNull GenericContainer<?> cassandraContainer) {
121127

122128
try (CqlSession session = newCqlSession(cassandraContainer)) {
123129

@@ -126,16 +132,16 @@ private GenericContainer<?> assertCassandraServerSetup(GenericContainer<?> cassa
126132

127133
assertThat(keyspaceMetadata.getName().toString()).isEqualToIgnoringCase(KEYSPACE_NAME);
128134

129-
keyspaceMetadata.getTable("Customers")
135+
keyspaceMetadata.getTable(TABLE_NAME)
130136
.map(tableMetadata -> {
131137

132-
assertThat(tableMetadata.getName().toString()).isEqualToIgnoringCase("Customers");
138+
assertThat(tableMetadata.getName().toString()).isEqualTo(TABLE_NAME);
133139
assertThat(tableMetadata.getKeyspace().toString()).isEqualToIgnoringCase(KEYSPACE_NAME);
134140
//assertCustomersTableHasSizeOne(session);
135141

136142
return tableMetadata;
137143
})
138-
.orElseThrow(() -> new IllegalStateException("Table [Customers] not found"));
144+
.orElseThrow(() -> new IllegalStateException(String.format("Table [%s] not found", TABLE_NAME)));
139145

140146
return keyspaceMetadata;
141147
})
@@ -145,25 +151,26 @@ private GenericContainer<?> assertCassandraServerSetup(GenericContainer<?> cassa
145151
return cassandraContainer;
146152
}
147153

148-
private void assertCustomersTableHasSizeOne(CqlSession session) {
154+
private void assertCustomersTableHasSizeOne(@NonNull CqlSession session) {
149155

150156
CassandraTemplate template = newCassandraTemplate(session);
151157

152158
assertThat(template.getCqlOperations().execute(String.format("USE %s;", KEYSPACE_NAME))).isTrue();
153-
assertThat(template.getCqlOperations().queryForObject("SELECT count(*) FROM Customers", Long.class)).isOne();
159+
assertThat(template.getCqlOperations().queryForObject("SELECT count(*) FROM \"Customers\"", Long.class)).isOne();
154160
//assertThat(template.count(Customer.class)).isOne(); // Table Customers not found; needs to use the Keyspace
155161
}
156162

157163
@Bean
158-
CqlSessionBuilderCustomizer cqlSessionBuilderCustomizer(
164+
CqlSessionBuilderCustomizer cqlSessionBuilderCustomizer(CassandraProperties properties,
159165
@Qualifier("CassandraContainer") GenericContainer<?> cassandraContainer) {
160166

161-
return cqlSessionBuilder -> cqlSessionBuilder.addContactPoint(resolveContactPoint(cassandraContainer))
162-
.withLocalDatacenter(LOCAL_DATA_CENTER)
163-
.withKeyspace(KEYSPACE_NAME);
167+
return cqlSessionBuilder -> cqlSessionBuilder
168+
.addContactPoint(resolveContactPoint(cassandraContainer))
169+
.withLocalDatacenter(properties.getLocalDatacenter())
170+
.withKeyspace(properties.getKeyspaceName());
164171
}
165172

166-
private InetSocketAddress resolveContactPoint(GenericContainer<?> cassandraContainer) {
173+
private @NonNull InetSocketAddress resolveContactPoint(@NonNull GenericContainer<?> cassandraContainer) {
167174
return new InetSocketAddress(cassandraContainer.getHost(),
168175
cassandraContainer.getMappedPort(CASSANDRA_DEFAULT_PORT));
169176
}

spring-geode-project/spring-geode/src/test/java/example/app/crm/model/Customer.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import jakarta.persistence.Entity;
1919
import jakarta.persistence.Table;
2020

21-
import org.springframework.data.annotation.Id;
2221
import org.springframework.data.cassandra.core.mapping.Indexed;
2322
import org.springframework.data.cassandra.core.mapping.PrimaryKey;
2423
import org.springframework.data.gemfire.mapping.annotation.Region;
@@ -34,7 +33,8 @@
3433
* @author John Blum
3534
* @see jakarta.persistence.Entity
3635
* @see jakarta.persistence.Table
37-
* @see org.springframework.data.annotation.Id
36+
* @see org.springframework.data.cassandra.core.mapping.Indexed
37+
* @see org.springframework.data.cassandra.core.mapping.PrimaryKey
3838
* @see org.springframework.data.cassandra.core.mapping.Table
3939
* @see org.springframework.data.gemfire.mapping.annotation.Region
4040
* @since 1.1.0
@@ -48,9 +48,8 @@
4848
@AllArgsConstructor(staticName = "newCustomer")
4949
public class Customer {
5050

51-
@Id
52-
@jakarta.persistence.Id
5351
@PrimaryKey
52+
@jakarta.persistence.Id
5453
private Long id;
5554

5655
@Indexed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
INSERT INTO Customers (id, name) VALUES (16, 'Pie Doe');
1+
INSERT INTO "Customers" (id, name) VALUES (16, 'Pie Doe');
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
CREATE KEYSPACE IF NOT EXISTS CustomerService WITH replication = { 'class':'SimpleStrategy', 'replication_factor':1 };
2-
CREATE TABLE IF NOT EXISTS CustomerService.Customers (id BIGINT PRIMARY KEY, name TEXT);
3-
CREATE INDEX IF NOT EXISTS CustomerNameIdx ON CustomerService.Customers(name);
4-
INSERT INTO CustomerService.Customers (id, name) VALUES (16, 'Pie Doe');
2+
USE CustomerService;
3+
CREATE TABLE IF NOT EXISTS "Customers" (id BIGINT PRIMARY KEY, name TEXT);
4+
CREATE INDEX IF NOT EXISTS CustomerNameIdx ON "Customers"(name);
5+
INSERT INTO "Customers" (id, name) VALUES (16, 'Pie Doe');
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
CREATE KEYSPACE IF NOT EXISTS CustomerService WITH replication = { 'class':'SimpleStrategy', 'replication_factor':1 };
22
USE CustomerService;
3-
CREATE TABLE IF NOT EXISTS Customers (id BIGINT PRIMARY KEY, name TEXT);
4-
CREATE INDEX IF NOT EXISTS CustomerNameIdx ON Customers(name);
3+
CREATE TABLE IF NOT EXISTS "Customers" (id BIGINT PRIMARY KEY, name TEXT);
4+
CREATE INDEX IF NOT EXISTS CustomerNameIdx ON "Customers"(name);

0 commit comments

Comments
 (0)