From be495728d9162f7f35b23cbb0b40eb472d1a925f Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 4 May 2016 15:33:35 +0200 Subject: [PATCH] DATACASS-271 - Polishing. Add author tags. Add/update license headers where needed. Remove calls to deprecated methods. Adopt pooling options after the driver update. Add hints_directory for Cassandra 3. Reduce driver baseline to core driver 3.0.1. The DSE driver requires the core driver itself and can be added as dependency to user projects while retaining full compatibility. As of now the DSE driver is rc1 hence it requires core rc1. Use getTimestamp for timestamp type methods as the driver aligned the method to the type. Support short, byte and time. Enable LocalDate return type and add tests for native supported types. Change long to bigint type as long was mapped to the counter type when creating tables. Align the default to bigint as bigint is the better choice since table creation uses mostly regular tables and not counter tables. Type can be overriden using @CassandraType. We now support setting NettyOptions on CassandraCqlClusterFactoryBean and AbstractClusterConfiguration. The cassandra driver 2.1.9 changed its default shutdown behavior by introducing a 2 second quiet period when shutting down Cluster instances. This change was retained throughout the 3.0 driver which slow the test down by an order of magnitude. Configure QueryOptions on tests to prevent delays caused by the asynchronous schema refresh. Original pull request: #56. Related pull request: #52. Related ticket: DATACASS-169. --- pom.xml | 87 ++-- spring-cql/pom.xml | 14 +- .../CassandraCqlClusterFactoryBean.java | 30 +- .../config/PoolingOptionsFactoryBean.java | 15 +- .../java/AbstractClusterConfiguration.java | 12 + .../AbstractCqlTemplateConfiguration.java | 26 ++ .../cassandra/core/CqlTemplate.java | 1 + .../core/converter/RowToListConverter.java | 9 +- .../core/converter/RowToMapConverter.java | 11 +- ...ssandraCqlClusterFactoryBeanUnitTests.java | 5 +- ...AbstractClusterConfigurationUnitTests.java | 2 +- .../CassandraExceptionTranslatorTest.java | 6 +- .../test/integration/CassandraRule.java | 15 +- .../EmbeddedCassandraServerHelper.java | 7 +- ...CqlClusterFactoryBeanIntegrationTests.java | 21 +- .../CqlTemplateConfigIntegrationTests.java | 13 +- .../java/KeyspaceCreatingJavaConfig.java | 12 +- .../config/xml/TestHostStateListener.java | 24 +- .../config/xml/TestLatencyTracker.java | 31 +- .../CqlIndexSpecificationAssertions.java | 31 +- .../CqlTableSpecificationAssertions.java | 5 +- .../support/AbstractTestJavaConfig.java | 24 +- .../support/FastShutdownNettyOptions.java | 38 ++ ...atingXmlConfigIntegrationTests-context.xml | 7 +- spring-data-cassandra/pom.xml | 12 - .../convert/CassandraConverters.java | 17 + .../data/cassandra/convert/ColumnReader.java | 124 +++--- .../convert/MappingCassandraConverter.java | 1 + .../convert/RowReaderPropertyAccessor.java | 11 +- .../BasicCassandraPersistentProperty.java | 26 +- .../mapping/CassandraSimpleTypeHolder.java | 28 +- .../CassandraNamespaceIntegrationTests.java | 96 +++++ .../MappingCassandraConverterUnitTests.java | 24 +- .../cassandra/domain/AllPossibleTypes.java | 91 +++++ ...RepositoryReturnTypesIntegrationTests.java | 380 ++++++++++++++++++ ...tRepositoryJavaConfigIntegrationTests.java | 8 +- .../CassandraNamespaceIntegrationTests.java | 41 -- .../CassandraTypeMappingIntegrationTest.java | 213 ++++++---- .../mapping/types/CounterEntity.java | 40 ++ .../integration/mapping/types/TimeEntity.java | 40 ++ ...rRepositoryJavaConfigIntegrationTests.java | 5 - .../support/IntegrationTestConfig.java | 20 +- .../test/resources/embedded-cassandra.yaml | 25 +- ...andraNamespaceIntegrationTests-context.xml | 6 +- .../xml}/cassandra.properties | 0 45 files changed, 1269 insertions(+), 385 deletions(-) create mode 100644 spring-cql/src/test/java/org/springframework/cassandra/test/integration/support/FastShutdownNettyOptions.java create mode 100644 spring-data-cassandra/src/test/java/org/springframework/data/cassandra/config/xml/CassandraNamespaceIntegrationTests.java create mode 100644 spring-data-cassandra/src/test/java/org/springframework/data/cassandra/domain/AllPossibleTypes.java create mode 100644 spring-data-cassandra/src/test/java/org/springframework/data/cassandra/repository/isolated/RepositoryReturnTypesIntegrationTests.java delete mode 100644 spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/config/CassandraNamespaceIntegrationTests.java create mode 100644 spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/mapping/types/CounterEntity.java create mode 100644 spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/integration/mapping/types/TimeEntity.java rename spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/{test/integration/config => config/xml}/CassandraNamespaceIntegrationTests-context.xml (89%) rename spring-data-cassandra/src/test/resources/org/springframework/data/cassandra/{test/integration/config => config/xml}/cassandra.properties (100%) diff --git a/pom.xml b/pom.xml index 08270dfb1..02877e232 100644 --- a/pom.xml +++ b/pom.xml @@ -21,25 +21,6 @@ Spring Data Cassandra http://projects.spring.io/spring-data-cassandra/ - - multi - spring-data-cassandra - 1.13.0.BUILD-SNAPSHOT - 3.0.0.1 - 1.0 - 2.16 - 0.3.1 - 3.0.0 - 3.0.0-rc1 - - embedded - localhost - 19042 - 19160 - 17000 - 17001 - - madams @@ -83,6 +64,22 @@ spring-data-cassandra-distribution + + localhost + embedded + 19042 + 19160 + 17001 + 17000 + 3.0.0 + 3.0.1 + spring-data-cassandra + 1.0 + 2.16 + multi + 1.13.0.BUILD-SNAPSHOT + + spring-libs-snapshot @@ -99,38 +96,24 @@ + + com.datastax.cassandra - cassandra-driver-dse - ${cassandra-driver-dse.version} + cassandra-driver-core + ${cassandra-driver.version} - slf4j-log4j12 - org.slf4j - - - log4j - log4j - - - guava - com.google.guava - - - netty-handler io.netty + netty-handler + + + com.google.guava + guava - - - org.slf4j - jul-to-slf4j - ${slf4j} - test - - javax.enterprise @@ -140,6 +123,24 @@ true + + + org.apache.cassandra + cassandra-all + ${cassandra.version} + test + + + ch.qos.logback + logback-core + + + guava + com.google.guava + + + + org.xerial.snappy snappy-java @@ -194,7 +195,7 @@ com.datastax.cassandra - cassandra-driver-dse + cassandra-driver-core diff --git a/spring-cql/pom.xml b/spring-cql/pom.xml index 97eb9341f..d37c3e33d 100644 --- a/spring-cql/pom.xml +++ b/spring-cql/pom.xml @@ -50,7 +50,7 @@ com.datastax.cassandra - cassandra-driver-dse + cassandra-driver-core javax.enterprise @@ -76,18 +76,6 @@ org.apache.cassandra cassandra-all - ${cassandra.version} - test - - - ch.qos.logback - logback-core - - - guava - com.google.guava - - com.google.guava diff --git a/spring-cql/src/main/java/org/springframework/cassandra/config/CassandraCqlClusterFactoryBean.java b/spring-cql/src/main/java/org/springframework/cassandra/config/CassandraCqlClusterFactoryBean.java index aae08bdce..901e2192a 100644 --- a/spring-cql/src/main/java/org/springframework/cassandra/config/CassandraCqlClusterFactoryBean.java +++ b/spring-cql/src/main/java/org/springframework/cassandra/config/CassandraCqlClusterFactoryBean.java @@ -42,6 +42,7 @@ import com.datastax.driver.core.AuthProvider; import com.datastax.driver.core.Cluster; import com.datastax.driver.core.Host; import com.datastax.driver.core.LatencyTracker; +import com.datastax.driver.core.NettyOptions; import com.datastax.driver.core.PoolingOptions; import com.datastax.driver.core.ProtocolOptions.Compression; import com.datastax.driver.core.ProtocolVersion; @@ -93,6 +94,7 @@ public class CassandraCqlClusterFactoryBean private AuthProvider authProvider; private String username; private String password; + private NettyOptions nettyOptions; private ProtocolVersion protocolVersion; // Policies @@ -189,6 +191,10 @@ public class CassandraCqlClusterFactoryBean } } + if (nettyOptions != null) { + builder.withNettyOptions(nettyOptions); + } + if (loadBalancingPolicy != null) { builder.withLoadBalancingPolicy(loadBalancingPolicy); } @@ -275,8 +281,8 @@ public class CassandraCqlClusterFactoryBean for (Object spec : specs) { String cql = (spec instanceof CreateKeyspaceSpecification) - ? new CreateKeyspaceCqlGenerator((CreateKeyspaceSpecification) spec).toCql() - : new DropKeyspaceCqlGenerator((DropKeyspaceSpecification) spec).toCql(); + ? new CreateKeyspaceCqlGenerator((CreateKeyspaceSpecification) spec).toCql() + : new DropKeyspaceCqlGenerator((DropKeyspaceSpecification) spec).toCql(); if (log.isDebugEnabled()) { log.debug("executing raw CQL [{}]", cql); @@ -329,7 +335,7 @@ public class CassandraCqlClusterFactoryBean } /** - * Set the {@link PoolingOptions}. + * Set the {@link PoolingOptions} to configure the connection pooling behavior. */ public void setPoolingOptions(PoolingOptions poolingOptions) { this.poolingOptions = poolingOptions; @@ -352,7 +358,7 @@ public class CassandraCqlClusterFactoryBean } /** - * Set the {@link QueryOptions}. + * Set the {@link QueryOptions} to tune to defaults for individual queries. */ public void setQueryOptions(QueryOptions queryOptions) { this.queryOptions = queryOptions; @@ -366,21 +372,31 @@ public class CassandraCqlClusterFactoryBean } /** - * Set the {@link LoadBalancingPolicy}. + * Set the {@link NettyOptions} used by a client to customize the driver's underlying Netty layer. + * + * @param nettyOptions + * @since 1.5 + */ + public void setNettyOptions(NettyOptions nettyOptions) { + this.nettyOptions = nettyOptions; + } + + /** + * Set the {@link LoadBalancingPolicy} that decides which Cassandra hosts to contact for each new query. */ public void setLoadBalancingPolicy(LoadBalancingPolicy loadBalancingPolicy) { this.loadBalancingPolicy = loadBalancingPolicy; } /** - * Set the {@link ReconnectionPolicy}. + * Set the {@link ReconnectionPolicy} that decides how often the reconnection to a dead node is attempted. */ public void setReconnectionPolicy(ReconnectionPolicy reconnectionPolicy) { this.reconnectionPolicy = reconnectionPolicy; } /** - * Set the {@link RetryPolicy}. + * Set the {@link RetryPolicy} that defines a default behavior to adopt when a request fails. */ public void setRetryPolicy(RetryPolicy retryPolicy) { this.retryPolicy = retryPolicy; diff --git a/spring-cql/src/main/java/org/springframework/cassandra/config/PoolingOptionsFactoryBean.java b/spring-cql/src/main/java/org/springframework/cassandra/config/PoolingOptionsFactoryBean.java index a2dde2f44..e332e92fe 100644 --- a/spring-cql/src/main/java/org/springframework/cassandra/config/PoolingOptionsFactoryBean.java +++ b/spring-cql/src/main/java/org/springframework/cassandra/config/PoolingOptionsFactoryBean.java @@ -1,12 +1,12 @@ /* - * Copyright 2013-2014 the original author or authors. - * + * Copyright 2013-2016 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 - * + * * http://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. @@ -24,9 +24,10 @@ import com.datastax.driver.core.PoolingOptions; /** * Pooling Options Factory Bean. - * + * * @author Matthew T. Adams * @author David Webb + * @author Mark Paluch */ public class PoolingOptionsFactoryBean implements FactoryBean, InitializingBean, DisposableBean { @@ -79,7 +80,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I } if (localMaxSimultaneousRequests != null) { - poolingOptions.setNewConnectionThreshold(HostDistance.LOCAL, localMaxSimultaneousRequests); + poolingOptions.setMaxRequestsPerConnection(HostDistance.LOCAL, localMaxSimultaneousRequests); } if (remoteMaxConnections != null) { @@ -103,7 +104,7 @@ public class PoolingOptionsFactoryBean implements FactoryBean, I } if (remoteMaxSimultaneousRequests != null) { - poolingOptions.setNewConnectionThreshold(HostDistance.REMOTE, + poolingOptions.setMaxRequestsPerConnection(HostDistance.REMOTE, remoteMaxSimultaneousRequests); } diff --git a/spring-cql/src/main/java/org/springframework/cassandra/config/java/AbstractClusterConfiguration.java b/spring-cql/src/main/java/org/springframework/cassandra/config/java/AbstractClusterConfiguration.java index b5c5c7663..a7d895119 100644 --- a/spring-cql/src/main/java/org/springframework/cassandra/config/java/AbstractClusterConfiguration.java +++ b/spring-cql/src/main/java/org/springframework/cassandra/config/java/AbstractClusterConfiguration.java @@ -26,6 +26,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.datastax.driver.core.AuthProvider; +import com.datastax.driver.core.NettyOptions; import com.datastax.driver.core.PoolingOptions; import com.datastax.driver.core.ProtocolVersion; import com.datastax.driver.core.QueryOptions; @@ -61,6 +62,7 @@ public abstract class AbstractClusterConfiguration { bean.setReconnectionPolicy(getReconnectionPolicy()); bean.setRetryPolicy(getRetryPolicy()); bean.setMetricsEnabled(getMetricsEnabled()); + bean.setNettyOptions(getNettyOptions()); bean.setPoolingOptions(getPoolingOptions()); bean.setQueryOptions(getQueryOptions()); @@ -158,6 +160,16 @@ public abstract class AbstractClusterConfiguration { return CassandraCqlClusterFactoryBean.DEFAULT_METRICS_ENABLED; } + /** + * Returns the {@link NettyOptions}. Defaults to {@link NettyOptions#DEFAULT_INSTANCE}. + * + * @return + * @since 1.5 + */ + protected NettyOptions getNettyOptions() { + return NettyOptions.DEFAULT_INSTANCE; + } + /** * Returns the {@link PoolingOptions}. * diff --git a/spring-cql/src/main/java/org/springframework/cassandra/config/java/AbstractCqlTemplateConfiguration.java b/spring-cql/src/main/java/org/springframework/cassandra/config/java/AbstractCqlTemplateConfiguration.java index 433fd06b9..1b26b22f7 100644 --- a/spring-cql/src/main/java/org/springframework/cassandra/config/java/AbstractCqlTemplateConfiguration.java +++ b/spring-cql/src/main/java/org/springframework/cassandra/config/java/AbstractCqlTemplateConfiguration.java @@ -1,8 +1,34 @@ +/* + * Copyright 2016 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 + * + * http://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.cassandra.config.java; import org.springframework.cassandra.core.CqlTemplate; import org.springframework.context.annotation.Bean; +/** + * Abstract configuration class to create a {@link CqlTemplate} and inheriting {@link com.datastax.driver.core.Session} + * and {@link com.datastax.driver.core.Cluster} creation. This class is usually extended by user configuration classes. + * + * @author Matthew T. Adams + * @see org.springframework.cassandra.config.java.AbstractClusterConfiguration + * @see org.springframework.cassandra.config.java.AbstractSessionConfiguration + * @see com.datastax.driver.core.Session + * @see com.datastax.driver.core.Cluster + * @see CqlTemplate + */ public abstract class AbstractCqlTemplateConfiguration extends AbstractSessionConfiguration { @Bean diff --git a/spring-cql/src/main/java/org/springframework/cassandra/core/CqlTemplate.java b/spring-cql/src/main/java/org/springframework/cassandra/core/CqlTemplate.java index ea9441b7e..1cd145a67 100644 --- a/spring-cql/src/main/java/org/springframework/cassandra/core/CqlTemplate.java +++ b/spring-cql/src/main/java/org/springframework/cassandra/core/CqlTemplate.java @@ -89,6 +89,7 @@ import com.datastax.driver.core.querybuilder.Update; * @author David Webb * @author Matthew Adams * @author Ryan Scheidter + * @author Antoine Toulme */ public class CqlTemplate extends CassandraAccessor implements CqlOperations { diff --git a/spring-cql/src/main/java/org/springframework/cassandra/core/converter/RowToListConverter.java b/spring-cql/src/main/java/org/springframework/cassandra/core/converter/RowToListConverter.java index e572e063f..f3ca6fe40 100644 --- a/spring-cql/src/main/java/org/springframework/cassandra/core/converter/RowToListConverter.java +++ b/spring-cql/src/main/java/org/springframework/cassandra/core/converter/RowToListConverter.java @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.cassandra.core.converter; import java.util.ArrayList; @@ -34,6 +33,7 @@ import com.datastax.driver.core.Row; * @author Matthew T. Adams * @author Stefan Birkner * @author Mark Paluch + * @author Antoine Toulme */ @ReadingConverter public class RowToListConverter implements Converter> { @@ -47,13 +47,16 @@ public class RowToListConverter implements Converter> { return null; } + CodecRegistry codecRegistry = CodecRegistry.DEFAULT_INSTANCE; ColumnDefinitions cols = row.getColumnDefinitions(); List list = new ArrayList(cols.size()); for (Definition def : cols.asList()) { String name = def.getName(); - list.add(row.isNull(name) ? null : CodecRegistry.DEFAULT_INSTANCE.codecFor(def.getType()).deserialize( - row.getBytesUnsafe(name), ProtocolVersion.NEWEST_SUPPORTED)); + + list.add(row.isNull(name) ? null + : codecRegistry.codecFor(def.getType()).deserialize(row.getBytesUnsafe(name), + ProtocolVersion.NEWEST_SUPPORTED)); } return list; diff --git a/spring-cql/src/main/java/org/springframework/cassandra/core/converter/RowToMapConverter.java b/spring-cql/src/main/java/org/springframework/cassandra/core/converter/RowToMapConverter.java index 161898fbe..d0cdcb7c8 100644 --- a/spring-cql/src/main/java/org/springframework/cassandra/core/converter/RowToMapConverter.java +++ b/spring-cql/src/main/java/org/springframework/cassandra/core/converter/RowToMapConverter.java @@ -34,6 +34,7 @@ import com.datastax.driver.core.Row; * @author Matthew T. Adams * @author David Webb * @author Mark Paluch + * @author Antoine Toulme */ @ReadingConverter public class RowToMapConverter implements Converter> { @@ -47,16 +48,18 @@ public class RowToMapConverter implements Converter> { return null; } + CodecRegistry codecRegistry = CodecRegistry.DEFAULT_INSTANCE; ColumnDefinitions cols = row.getColumnDefinitions(); Map map = new HashMap(cols.size()); for (Definition def : cols.asList()) { String name = def.getName(); - map.put( - name, - row.isNull(name) ? null : CodecRegistry.DEFAULT_INSTANCE.codecFor(def.getType()) - .deserialize(row.getBytesUnsafe(name), ProtocolVersion.NEWEST_SUPPORTED)); + + map.put(name, + row.isNull(name) ? null + : codecRegistry.codecFor(def.getType()).deserialize(row.getBytesUnsafe(name), + ProtocolVersion.NEWEST_SUPPORTED)); } return map; diff --git a/spring-cql/src/test/java/org/springframework/cassandra/config/CassandraCqlClusterFactoryBeanUnitTests.java b/spring-cql/src/test/java/org/springframework/cassandra/config/CassandraCqlClusterFactoryBeanUnitTests.java index 0679c7865..4e5490445 100644 --- a/spring-cql/src/test/java/org/springframework/cassandra/config/CassandraCqlClusterFactoryBeanUnitTests.java +++ b/spring-cql/src/test/java/org/springframework/cassandra/config/CassandraCqlClusterFactoryBeanUnitTests.java @@ -24,6 +24,7 @@ import org.springframework.test.util.ReflectionTestUtils; import com.datastax.driver.core.AuthProvider; import com.datastax.driver.core.Configuration; +import com.datastax.driver.core.JdkSSLOptions; import com.datastax.driver.core.PlainTextAuthProvider; import com.datastax.driver.core.PoolingOptions; import com.datastax.driver.core.ProtocolOptions.Compression; @@ -257,7 +258,7 @@ public class CassandraCqlClusterFactoryBeanUnitTests { @Test public void shouldSetSslOptions() throws Exception { - SSLOptions sslOptions = new SSLOptions(); + SSLOptions sslOptions = JdkSSLOptions.builder().build(); CassandraCqlClusterFactoryBean bean = new CassandraCqlClusterFactoryBean(); bean.setSslEnabled(true); @@ -278,7 +279,7 @@ public class CassandraCqlClusterFactoryBeanUnitTests { bean.setMetricsEnabled(false); bean.afterPropertiesSet(); - assertThat(getConfiguration(bean).getMetricsOptions(), is(nullValue())); + assertThat(getConfiguration(bean).getMetricsOptions().isEnabled(), is(false)); } /** diff --git a/spring-cql/src/test/java/org/springframework/cassandra/config/java/AbstractClusterConfigurationUnitTests.java b/spring-cql/src/test/java/org/springframework/cassandra/config/java/AbstractClusterConfigurationUnitTests.java index 8f26da188..894d81ff6 100644 --- a/spring-cql/src/test/java/org/springframework/cassandra/config/java/AbstractClusterConfigurationUnitTests.java +++ b/spring-cql/src/test/java/org/springframework/cassandra/config/java/AbstractClusterConfigurationUnitTests.java @@ -245,7 +245,7 @@ public class AbstractClusterConfigurationUnitTests { }; Cluster cluster = getCluster(clusterConfiguration); - assertThat(getConfiguration(cluster).getMetricsOptions(), is(nullValue())); + assertThat(getConfiguration(cluster).getMetricsOptions().isEnabled(), is(false)); } /** diff --git a/spring-cql/src/test/java/org/springframework/cassandra/support/CassandraExceptionTranslatorTest.java b/spring-cql/src/test/java/org/springframework/cassandra/support/CassandraExceptionTranslatorTest.java index b846cb993..ed01b7714 100644 --- a/spring-cql/src/test/java/org/springframework/cassandra/support/CassandraExceptionTranslatorTest.java +++ b/spring-cql/src/test/java/org/springframework/cassandra/support/CassandraExceptionTranslatorTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2013-2016 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 * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://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, @@ -73,7 +73,7 @@ public class CassandraExceptionTranslatorTest { @Test public void testInvalidConfigurationInQueryException() { String msg = "msg"; - InvalidQueryException cx = new InvalidConfigurationInQueryException(msg); + InvalidQueryException cx = new InvalidConfigurationInQueryException(null, msg); DataAccessException dax = tx.translateExceptionIfPossible(cx); assertNotNull(dax); assertTrue(dax instanceof CassandraInvalidConfigurationInQueryException); diff --git a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/CassandraRule.java b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/CassandraRule.java index dec262852..97a527039 100644 --- a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/CassandraRule.java +++ b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/CassandraRule.java @@ -27,11 +27,13 @@ import org.junit.rules.ExternalResource; import org.springframework.cassandra.core.SessionCallback; import org.springframework.cassandra.test.integration.support.CassandraConnectionProperties; import org.springframework.cassandra.test.integration.support.CqlDataSet; +import org.springframework.cassandra.test.integration.support.FastShutdownNettyOptions; import org.springframework.dao.DataAccessException; import org.springframework.util.Assert; import org.springframework.util.SocketUtils; import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.QueryOptions; import com.datastax.driver.core.Session; /** @@ -48,6 +50,7 @@ import com.datastax.driver.core.Session; * * * @author Mark Paluch + * @since 1.5 */ public class CassandraRule extends ExternalResource { @@ -70,7 +73,7 @@ public class CassandraRule extends ExternalResource { * @param yamlConfigurationResource name of the configuration resource, must not be {@literal null} and not empty */ public CassandraRule(String yamlConfigurationResource) { - this(yamlConfigurationResource, EmbeddedCassandraServerHelper.DEFAULT_STARTUP_TIMEOUT); + this(yamlConfigurationResource, EmbeddedCassandraServerHelper.DEFAULT_STARTUP_TIMEOUT_MS); } /** @@ -310,7 +313,15 @@ public class CassandraRule extends ExternalResource { port = properties.getCassandraPort(); } cassandraPort = port; - cluster = new Cluster.Builder().addContactPoints(hostIp).withPort(port).build(); + + QueryOptions queryOptions = new QueryOptions(); + queryOptions.setRefreshSchemaIntervalMillis(0); + + cluster = new Cluster.Builder().addContactPoints(hostIp).// + withPort(port).// + withQueryOptions(queryOptions).// + withNettyOptions(FastShutdownNettyOptions.INSTANCE).// + build(); } else { cluster = parent.cluster; cassandraPort = parent.cassandraPort; diff --git a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/EmbeddedCassandraServerHelper.java b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/EmbeddedCassandraServerHelper.java index 1d41185f7..0924ac3b7 100644 --- a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/EmbeddedCassandraServerHelper.java +++ b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/EmbeddedCassandraServerHelper.java @@ -22,10 +22,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; +import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicReference; import org.apache.cassandra.config.DatabaseDescriptor; @@ -45,7 +42,7 @@ class EmbeddedCassandraServerHelper { private static Logger log = LoggerFactory.getLogger(EmbeddedCassandraServerHelper.class); - public static final long DEFAULT_STARTUP_TIMEOUT = 10000; + public static final long DEFAULT_STARTUP_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(20); public static final String DEFAULT_TMP_DIR = "target/embeddedCassandra"; private final static AtomicReference sync = new AtomicReference(); diff --git a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/config/CassandraCqlClusterFactoryBeanIntegrationTests.java b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/config/CassandraCqlClusterFactoryBeanIntegrationTests.java index 4f762e895..aaf9d9999 100644 --- a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/config/CassandraCqlClusterFactoryBeanIntegrationTests.java +++ b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/config/CassandraCqlClusterFactoryBeanIntegrationTests.java @@ -15,13 +15,16 @@ */ package org.springframework.cassandra.test.integration.config; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.springframework.cassandra.config.CassandraCqlClusterFactoryBean; -import org.springframework.cassandra.test.integration.AbstractEmbeddedCassandraIntegrationTest; +import org.springframework.cassandra.test.integration.support.FastShutdownNettyOptions; +import org.springframework.test.util.ReflectionTestUtils; import com.datastax.driver.core.ProtocolVersion; @@ -29,8 +32,9 @@ import com.datastax.driver.core.ProtocolVersion; * Unit tests for {@link CassandraCqlClusterFactoryBean}. * * @author Kirk Clemens + * @author Mark Paluch */ -public class CassandraCqlClusterFactoryBeanIntegrationTests extends AbstractEmbeddedCassandraIntegrationTest { +public class CassandraCqlClusterFactoryBeanIntegrationTests { private CassandraCqlClusterFactoryBean cassandraCqlClusterFactoryBean; @@ -47,27 +51,26 @@ public class CassandraCqlClusterFactoryBeanIntegrationTests extends AbstractEmbe @Test public void configuredProtocolVersionShouldBeSet() throws Exception { - cassandraCqlClusterFactoryBean.setProtocolVersion(ProtocolVersion.V4); - cassandraCqlClusterFactoryBean.setPort(cassandraEnvironment.getPort()); + cassandraCqlClusterFactoryBean.setNettyOptions(FastShutdownNettyOptions.INSTANCE); + cassandraCqlClusterFactoryBean.setProtocolVersion(ProtocolVersion.V2); cassandraCqlClusterFactoryBean.afterPropertiesSet(); - assertEquals(ProtocolVersion.V4, getProtocolVersionEnum(cassandraCqlClusterFactoryBean)); + assertEquals(ProtocolVersion.V2, getProtocolVersionEnum(cassandraCqlClusterFactoryBean)); } @Test public void defaultProtocolVersionShouldBeSet() throws Exception { - cassandraCqlClusterFactoryBean.setPort(cassandraEnvironment.getPort()); cassandraCqlClusterFactoryBean.afterPropertiesSet(); - assertEquals(ProtocolVersion.NEWEST_SUPPORTED, getProtocolVersionEnum(cassandraCqlClusterFactoryBean)); + assertThat(getProtocolVersionEnum(cassandraCqlClusterFactoryBean), is(nullValue())); } private ProtocolVersion getProtocolVersionEnum(CassandraCqlClusterFactoryBean cassandraCqlClusterFactoryBean) throws Exception { // initialize connection factory - cassandraCqlClusterFactoryBean.getObject().init(); - return cassandraCqlClusterFactoryBean.getObject().getConfiguration().getProtocolOptions().getProtocolVersion(); + return (ProtocolVersion) ReflectionTestUtils.getField( + cassandraCqlClusterFactoryBean.getObject().getConfiguration().getProtocolOptions(), "initialProtocolVersion"); } } diff --git a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/config/java/CqlTemplateConfigIntegrationTests.java b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/config/java/CqlTemplateConfigIntegrationTests.java index 9cc0bda2d..99295da00 100644 --- a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/config/java/CqlTemplateConfigIntegrationTests.java +++ b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/config/java/CqlTemplateConfigIntegrationTests.java @@ -23,23 +23,24 @@ import org.junit.Before; import org.junit.Test; import org.springframework.cassandra.config.java.AbstractCqlTemplateConfiguration; import org.springframework.cassandra.core.CqlTemplate; -import org.springframework.cassandra.support.RandomKeySpaceName; import org.springframework.cassandra.test.integration.AbstractEmbeddedCassandraIntegrationTest; +import org.springframework.cassandra.test.integration.support.FastShutdownNettyOptions; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Configuration; +import com.datastax.driver.core.NettyOptions; import com.datastax.driver.core.Session; /** + * Integration tests for {@link AbstractCqlTemplateConfiguration}. + * * @author Matthews T. Adams * @author Oliver Gierke * @author Mark Paluch */ public class CqlTemplateConfigIntegrationTests extends AbstractEmbeddedCassandraIntegrationTest { - public static final String KEYSPACE_NAME = RandomKeySpaceName.create(); - @Configuration public static class Config extends AbstractCqlTemplateConfiguration { @@ -52,6 +53,11 @@ public class CqlTemplateConfigIntegrationTests extends AbstractEmbeddedCassandra protected int getPort() { return cassandraEnvironment.getPort(); } + + @Override + protected NettyOptions getNettyOptions() { + return FastShutdownNettyOptions.INSTANCE; + } } Session session; @@ -59,6 +65,7 @@ public class CqlTemplateConfigIntegrationTests extends AbstractEmbeddedCassandra @Before public void setUp() { + this.context = new AnnotationConfigApplicationContext(Config.class); this.session = context.getBean(Session.class); } diff --git a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/config/java/KeyspaceCreatingJavaConfig.java b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/config/java/KeyspaceCreatingJavaConfig.java index d00a368a3..06d96b182 100644 --- a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/config/java/KeyspaceCreatingJavaConfig.java +++ b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/config/java/KeyspaceCreatingJavaConfig.java @@ -1,12 +1,12 @@ /* - * Copyright 2013-2014 the original author or authors. - * + * Copyright 2013-2016 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 - * + * * http://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. @@ -24,6 +24,10 @@ import org.springframework.cassandra.core.keyspace.KeyspaceOption; import org.springframework.cassandra.test.integration.support.AbstractTestJavaConfig; import org.springframework.context.annotation.Configuration; +/** + * @author Matthew T. Adams + * @author Mark Paluch + */ @Configuration public class KeyspaceCreatingJavaConfig extends AbstractTestJavaConfig { diff --git a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/config/xml/TestHostStateListener.java b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/config/xml/TestHostStateListener.java index a756a5fa9..6c767f9d7 100644 --- a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/config/xml/TestHostStateListener.java +++ b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/config/xml/TestHostStateListener.java @@ -1,12 +1,12 @@ /* - * Copyright 2013-2014 the original author or authors. - * + * Copyright 2013-2016 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 - * + * * http://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. @@ -23,7 +23,11 @@ import com.datastax.driver.core.Host; import com.datastax.driver.core.Host.StateListener; /** + * {@link StateListener} that logs latency events and their payload. This class can be considered a test dummy and is + * suitable for mocking. + * * @author David Webb + * @author Antoine Toulme */ public class TestHostStateListener implements StateListener { @@ -31,32 +35,32 @@ public class TestHostStateListener implements StateListener { @Override public void onAdd(Host host) { - log.info("Host Added: " + host.getAddress()); + log.info("Host Added: {}", host.getAddress()); } @Override public void onUp(Host host) { - log.info("Host Up: " + host.getAddress()); + log.info("Host Up: {}", host.getAddress()); } @Override public void onDown(Host host) { - log.info("Host Down: " + host.getAddress()); + log.info("Host Down: {}", host.getAddress()); } @Override public void onRemove(Host host) { - log.info("Host Removed: " + host.getAddress()); + log.info("Host Removed: {}", host.getAddress()); } @Override public void onRegister(Cluster cluster) { - log.info("Cluster registered: " + cluster.getClusterName()); + log.info("Cluster registered: {}", cluster.getClusterName()); } @Override public void onUnregister(Cluster cluster) { - log.info("Cluster unregistered: " + cluster.getClusterName()); + log.info("Cluster unregistered: {}", cluster.getClusterName()); } } diff --git a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/config/xml/TestLatencyTracker.java b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/config/xml/TestLatencyTracker.java index 656cac26f..07a282557 100644 --- a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/config/xml/TestLatencyTracker.java +++ b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/config/xml/TestLatencyTracker.java @@ -1,12 +1,12 @@ /* - * Copyright 2013-2015 the original author or authors. - * + * Copyright 2013-2016 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 - * + * * http://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. @@ -24,8 +24,12 @@ import com.datastax.driver.core.LatencyTracker; import com.datastax.driver.core.Statement; /** + * {@link LatencyTracker} that logs latency events and their payload. This class can be considered a test dummy and is suitable for + * mocking. + * * @author David Webb * @author Oliver Gierke + * @author Antoine Toulme */ public class TestLatencyTracker implements LatencyTracker { @@ -33,15 +37,16 @@ public class TestLatencyTracker implements LatencyTracker { @Override public void update(Host host, Statement statement, Exception exception, long newLatencyNanos) { - LOG.info("Latency Tracker: " + host.getAddress() + ", " + newLatencyNanos + " nanoseconds."); - } - - @Override - public void onRegister(Cluster cluster) { - } - - @Override - public void onUnregister(Cluster cluster) { + LOG.info("Latency Tracker update: {}, {} nanoseconds.", host.getAddress(), newLatencyNanos); } + @Override + public void onRegister(Cluster cluster) { + LOG.info("Latency Tracker onRegister: {}", cluster); + } + + @Override + public void onUnregister(Cluster cluster) { + LOG.info("Latency Tracker onUnregister: {}", cluster); + } } diff --git a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/core/cql/generator/CqlIndexSpecificationAssertions.java b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/core/cql/generator/CqlIndexSpecificationAssertions.java index 627b98a4c..a912913de 100644 --- a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/core/cql/generator/CqlIndexSpecificationAssertions.java +++ b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/core/cql/generator/CqlIndexSpecificationAssertions.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2013-2016 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. @@ -15,6 +15,7 @@ */ package org.springframework.cassandra.test.integration.core.cql.generator; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import org.springframework.cassandra.core.keyspace.IndexDescriptor; @@ -26,24 +27,40 @@ import com.datastax.driver.core.TableMetadata; /** * @author David Webb * @author Matthew T. Adams + * @author Antoine Toulme */ public class CqlIndexSpecificationAssertions { + /** + * Assert the existence of an index using the index name. + * + * @param expected + * @param keyspace + * @param session + */ public static void assertIndex(IndexDescriptor expected, String keyspace, Session session) { TableMetadata tableMetadata = session.getCluster().getMetadata().getKeyspace(keyspace.toLowerCase()) .getTable(expected.getTableName().toCql()); - - IndexMetadata imd = tableMetadata.getIndex(expected.getName().toCql()); - assertEquals(expected.getName(), imd == null ? null : imd.getName()); + IndexMetadata indexMetadata = tableMetadata.getIndex(expected.getName().toCql()); + + assertThat(indexMetadata, is(not(nullValue()))); + assertThat(indexMetadata.getName(), is(equalTo(expected.getName().toCql()))); } + /** + * Assert the absence of an index using the index name. + * + * @param expected + * @param keyspace + * @param session + */ public static void assertNoIndex(IndexDescriptor expected, String keyspace, Session session) { TableMetadata tableMetadata = session.getCluster().getMetadata().getKeyspace(keyspace.toLowerCase()) .getTable(expected.getTableName().toCql()); - - IndexMetadata imd = tableMetadata.getIndex(expected.getName().toCql()); - assertNull(imd); + IndexMetadata indexMetadata = tableMetadata.getIndex(expected.getName().toCql()); + + assertThat(indexMetadata, is(nullValue())); } } diff --git a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/core/cql/generator/CqlTableSpecificationAssertions.java b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/core/cql/generator/CqlTableSpecificationAssertions.java index 8a839018b..7d879340b 100644 --- a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/core/cql/generator/CqlTableSpecificationAssertions.java +++ b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/core/cql/generator/CqlTableSpecificationAssertions.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2013-2016 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. @@ -35,8 +35,9 @@ import com.datastax.driver.core.TableOptionsMetadata; /** * @author Matthew T. Adams - * @author Matthew T. Adams + * @author David Webb * @author Alex Shvid + * @author Antoine Toulme */ public class CqlTableSpecificationAssertions { diff --git a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/support/AbstractTestJavaConfig.java b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/support/AbstractTestJavaConfig.java index c30fc9852..a72bcb7eb 100644 --- a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/support/AbstractTestJavaConfig.java +++ b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/support/AbstractTestJavaConfig.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2014 the original author or authors. + * Copyright 2013-2016 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. @@ -18,8 +18,14 @@ package org.springframework.cassandra.test.integration.support; import org.springframework.cassandra.config.java.AbstractSessionConfiguration; import org.springframework.context.annotation.Configuration; +import com.datastax.driver.core.NettyOptions; +import com.datastax.driver.core.QueryOptions; + /** + * Java-based configuration for integration tests using defaults for a smooth test run. + * * @author Matthew T. Adams + * @author Mark Paluch */ @Configuration public abstract class AbstractTestJavaConfig extends AbstractSessionConfiguration { @@ -30,4 +36,20 @@ public abstract class AbstractTestJavaConfig extends AbstractSessionConfiguratio protected int getPort() { return PROPERTIES.getCassandraPort(); } + + @Override + protected NettyOptions getNettyOptions() { + return FastShutdownNettyOptions.INSTANCE; + } + + @Override + protected QueryOptions getQueryOptions() { + + // The driver blocks otherwise up to 1 sec on schema refreshes. + // see also https://datastax-oss.atlassian.net/browse/JAVA-1120 + // ideally, this issue will be resolved with Cassandra Java Driver 3.0.2 + QueryOptions queryOptions = new QueryOptions(); + queryOptions.setRefreshSchemaIntervalMillis(0); + return queryOptions; + } } diff --git a/spring-cql/src/test/java/org/springframework/cassandra/test/integration/support/FastShutdownNettyOptions.java b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/support/FastShutdownNettyOptions.java new file mode 100644 index 000000000..0dedb3272 --- /dev/null +++ b/spring-cql/src/test/java/org/springframework/cassandra/test/integration/support/FastShutdownNettyOptions.java @@ -0,0 +1,38 @@ +/* + * Copyright 2016 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 + * + * http://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.cassandra.test.integration.support; + +import java.util.concurrent.TimeUnit; + +import com.datastax.driver.core.NettyOptions; + +import io.netty.channel.EventLoopGroup; + +/** + * {@link NettyOptions} to shutdown a {@link com.datastax.driver.core.Cluster} instance without wait time. + * + * @author Mark Paluch + * @since 1.5 + */ +public class FastShutdownNettyOptions extends NettyOptions { + + public final static FastShutdownNettyOptions INSTANCE = new FastShutdownNettyOptions(); + + @Override + public void onClusterClose(EventLoopGroup eventLoopGroup) { + eventLoopGroup.shutdownGracefully(0, 0, TimeUnit.MILLISECONDS); + } +} diff --git a/spring-cql/src/test/resources/org/springframework/cassandra/test/integration/config/xml/PropertyPlaceholderNamespaceCreatingXmlConfigIntegrationTests-context.xml b/spring-cql/src/test/resources/org/springframework/cassandra/test/integration/config/xml/PropertyPlaceholderNamespaceCreatingXmlConfigIntegrationTests-context.xml index 4b17b0902..f15ff72f3 100644 --- a/spring-cql/src/test/resources/org/springframework/cassandra/test/integration/config/xml/PropertyPlaceholderNamespaceCreatingXmlConfigIntegrationTests-context.xml +++ b/spring-cql/src/test/resources/org/springframework/cassandra/test/integration/config/xml/PropertyPlaceholderNamespaceCreatingXmlConfigIntegrationTests-context.xml @@ -9,9 +9,12 @@ - + + + + -