diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cassandra/CassandraProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cassandra/CassandraProperties.java index eeab6ec489..ddcab2bc74 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cassandra/CassandraProperties.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cassandra/CassandraProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-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. @@ -114,7 +114,7 @@ public class CassandraProperties { private int readTimeoutMillis = SocketOptions.DEFAULT_READ_TIMEOUT_MILLIS; /** - * Action to take at startup. + * Schema action to take at startup. */ private String schemaAction = "none"; diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraDataAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraDataAutoConfiguration.java index 280c8a7ffb..72772348cc 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraDataAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraDataAutoConfiguration.java @@ -101,13 +101,12 @@ public class CassandraDataAutoConfiguration { @ConditionalOnMissingBean(Session.class) public CassandraSessionFactoryBean session(CassandraConverter converter) throws Exception { - CassandraSessionFactoryBean session = new CassandraSessionFactoryBean(); session.setCluster(this.cluster); session.setConverter(converter); session.setKeyspaceName(this.properties.getKeyspaceName()); - - SchemaAction schemaAction = propertyResolver.getProperty("schemaAction", SchemaAction.class, SchemaAction.NONE); + SchemaAction schemaAction = this.propertyResolver + .getProperty("schemaAction", SchemaAction.class, SchemaAction.NONE); session.setSchemaAction(schemaAction); return session; } diff --git a/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 549db95ebc..808b135830 100644 --- a/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -325,6 +325,17 @@ } ] }, + { + "name": "spring.data.cassandra.schema-action", + "providers": [ + { + "name": "handle-as", + "parameters": { + "target": "org.springframework.data.cassandra.config.SchemaAction" + } + } + ] + }, { "name": "spring.data.mongodb.field-naming-strategy", "providers": [ diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraDataAutoConfigurationIntegrationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraDataAutoConfigurationIntegrationTests.java index 3b3b493de5..2c98e6f6f1 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraDataAutoConfigurationIntegrationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraDataAutoConfigurationIntegrationTests.java @@ -1,8 +1,98 @@ +/* + * Copyright 2012-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.boot.autoconfigure.data.cassandra; +import com.datastax.driver.core.Session; +import org.junit.After; +import org.junit.Rule; +import org.junit.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurationPackages; +import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; +import org.springframework.boot.autoconfigure.data.cassandra.city.City; +import org.springframework.boot.test.util.EnvironmentTestUtils; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.data.cassandra.config.CassandraSessionFactoryBean; +import org.springframework.data.cassandra.config.SchemaAction; + +import static org.assertj.core.api.Assertions.assertThat; + /** + * Tests for {@link CassandraDataAutoConfiguration} that require a Cassandra instance. * + * @author Mark Paluch * @author Stephane Nicoll */ public class CassandraDataAutoConfigurationIntegrationTests { + + @Rule + public final CassandraTestServer cassandra = new CassandraTestServer(); + + private AnnotationConfigApplicationContext context; + + @After + public void close() { + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void hasDefaultSchemaActionSet() { + this.context = new AnnotationConfigApplicationContext(); + String cityPackage = City.class.getPackage().getName(); + AutoConfigurationPackages.register(this.context, cityPackage); + this.context.register(CassandraAutoConfiguration.class, + CassandraDataAutoConfiguration.class); + this.context.refresh(); + + CassandraSessionFactoryBean bean = this.context + .getBean(CassandraSessionFactoryBean.class); + assertThat(bean.getSchemaAction()).isEqualTo(SchemaAction.NONE); + } + + @Test + public void hasRecreateSchemaActionSet() { + createTestKeyspaceIfNotExists(); + this.context = new AnnotationConfigApplicationContext(); + String cityPackage = City.class.getPackage().getName(); + AutoConfigurationPackages.register(this.context, cityPackage); + + EnvironmentTestUtils.addEnvironment(this.context, + "spring.data.cassandra.schemaAction:RECREATE_DROP_UNUSED", "spring.data.cassandra.keyspaceName:boot_test"); + + this.context.register(CassandraAutoConfiguration.class, + CassandraDataAutoConfiguration.class); + this.context.refresh(); + + CassandraSessionFactoryBean bean = this.context + .getBean(CassandraSessionFactoryBean.class); + assertThat(bean.getSchemaAction()).isEqualTo(SchemaAction.RECREATE_DROP_UNUSED); + } + + private void createTestKeyspaceIfNotExists() { + Session session = this.cassandra.getCluster().connect(); + try { + session.execute("CREATE KEYSPACE IF NOT EXISTS boot_test" + + " WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };"); + } + finally { + session.close(); + } + } + } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraDataAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraDataAutoConfigurationTests.java index 5a274f773f..faf46b1815 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraDataAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraDataAutoConfigurationTests.java @@ -18,26 +18,20 @@ package org.springframework.boot.autoconfigure.data.cassandra; import java.util.Set; -import com.datastax.driver.core.Cluster; import com.datastax.driver.core.Session; -import com.datastax.driver.core.exceptions.DriverException; import org.junit.After; import org.junit.Test; -import org.springframework.boot.autoconfigure.AutoConfigurationPackages; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; import org.springframework.boot.autoconfigure.data.cassandra.city.City; import org.springframework.boot.autoconfigure.domain.EntityScan; -import org.springframework.boot.test.util.EnvironmentTestUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; -import org.springframework.data.cassandra.config.CassandraSessionFactoryBean; -import org.springframework.data.cassandra.config.SchemaAction; import org.springframework.data.cassandra.core.CassandraTemplate; import org.springframework.data.cassandra.mapping.CassandraMappingContext; import org.springframework.test.util.ReflectionTestUtils; @@ -49,7 +43,6 @@ import static org.mockito.Mockito.mock; * Tests for {@link CassandraDataAutoConfiguration} * * @author Eddú Meléndez - * @author Mark Paluch */ public class CassandraDataAutoConfigurationTests { @@ -73,47 +66,6 @@ public class CassandraDataAutoConfigurationTests { .isEqualTo(1); } - @Test - public void hasDefaultSchemaActionSet() { - - if (isCassandraAvailable()) { - - this.context = new AnnotationConfigApplicationContext(); - String cityPackage = City.class.getPackage().getName(); - AutoConfigurationPackages.register(this.context, cityPackage); - this.context.register(CassandraAutoConfiguration.class, - CassandraDataAutoConfiguration.class); - this.context.refresh(); - - CassandraSessionFactoryBean bean = this.context - .getBean(CassandraSessionFactoryBean.class); - assertThat(bean.getSchemaAction()).isEqualTo(SchemaAction.NONE); - } - } - - @Test - public void hasRecreateSchemaActionSet() { - - if (isCassandraAvailable()) { - createTestKeyspaceIfNotExists(); - - this.context = new AnnotationConfigApplicationContext(); - String cityPackage = City.class.getPackage().getName(); - AutoConfigurationPackages.register(this.context, cityPackage); - - EnvironmentTestUtils.addEnvironment(this.context, - "spring.data.cassandra.schemaAction:RECREATE_DROP_UNUSED", "spring.data.cassandra.keyspaceName:boot_test"); - - this.context.register(CassandraAutoConfiguration.class, - CassandraDataAutoConfiguration.class); - this.context.refresh(); - - CassandraSessionFactoryBean bean = this.context - .getBean(CassandraSessionFactoryBean.class); - assertThat(bean.getSchemaAction()).isEqualTo(SchemaAction.RECREATE_DROP_UNUSED); - } - } - @Test @SuppressWarnings("unchecked") public void entityScanShouldSetInitialEntitySet() throws Exception { @@ -129,42 +81,6 @@ public class CassandraDataAutoConfigurationTests { assertThat(initialEntitySet).containsOnly(City.class); } - /** - * @return {@literal true} if Cassandra is available - */ - private static boolean isCassandraAvailable() { - - Cluster cluster = newCluster(); - try { - cluster.connect().close(); - return true; - } - catch (DriverException exception) { - return false; - } - finally { - cluster.closeAsync(); - } - } - - private static void createTestKeyspaceIfNotExists() { - - Cluster cluster = newCluster(); - try { - Session session = cluster.connect(); - session.execute("CREATE KEYSPACE IF NOT EXISTS boot_test" - + " WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };"); - session.close(); - } - finally { - cluster.closeAsync(); - } - } - - private static Cluster newCluster() { - return Cluster.builder().addContactPoint("localhost").build(); - } - @Configuration @ComponentScan(excludeFilters = @ComponentScan.Filter(classes = { Session.class }, type = FilterType.ASSIGNABLE_TYPE)) diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraRepositoriesAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraRepositoriesAutoConfigurationTests.java index ea00553868..9db24e6b18 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraRepositoriesAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraRepositoriesAutoConfigurationTests.java @@ -48,6 +48,7 @@ import static org.mockito.Mockito.mock; * * @author Eddú Meléndez * @author Mark Paluch + * @author Stephane Nicoll */ public class CassandraRepositoriesAutoConfigurationTests { @@ -68,39 +69,29 @@ public class CassandraRepositoriesAutoConfigurationTests { addConfigurations(TestConfiguration.class); assertThat(this.context.getBean(CityRepository.class)).isNotNull(); assertThat(this.context.getBean(Cluster.class)).isNotNull(); - - BasicCassandraMappingContext mappingContext = this.context - .getBean(BasicCassandraMappingContext.class); - @SuppressWarnings("unchecked") - Set> entities = (Set>) ReflectionTestUtils - .getField(mappingContext, "initialEntitySet"); - assertThat(entities).hasSize(1); + assertThat(getInitialEntitySet()).hasSize(1); } @Test public void testNoRepositoryConfiguration() { addConfigurations(TestExcludeConfiguration.class, EmptyConfiguration.class); assertThat(this.context.getBean(Cluster.class)).isNotNull(); - - BasicCassandraMappingContext mappingContext = this.context - .getBean(BasicCassandraMappingContext.class); - @SuppressWarnings("unchecked") - Set> entities = (Set>) ReflectionTestUtils - .getField(mappingContext, "initialEntitySet"); - assertThat(entities).hasSize(1).containsOnly(City.class); + assertThat(getInitialEntitySet()).hasSize(1).containsOnly(City.class); } @Test public void doesNotTriggerDefaultRepositoryDetectionIfCustomized() { addConfigurations(TestExcludeConfiguration.class, CustomizedConfiguration.class); assertThat(this.context.getBean(CityCassandraRepository.class)).isNotNull(); + assertThat(getInitialEntitySet()).hasSize(1).containsOnly(City.class); + } + @SuppressWarnings("unchecked") + private Set> getInitialEntitySet() { BasicCassandraMappingContext mappingContext = this.context .getBean(BasicCassandraMappingContext.class); - @SuppressWarnings("unchecked") - Set> entities = (Set>) ReflectionTestUtils + return (Set>) ReflectionTestUtils .getField(mappingContext, "initialEntitySet"); - assertThat(entities).hasSize(1).containsOnly(City.class); } private void addConfigurations(Class... configurations) { diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraTestServer.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraTestServer.java index 1762f4a6a2..5fcb6a0b33 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraTestServer.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraTestServer.java @@ -1,8 +1,99 @@ +/* + * Copyright 2012-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.boot.autoconfigure.data.cassandra; +import com.datastax.driver.core.Cluster; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assume; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + /** + * {@link TestRule} for working with an optional Cassandra server. * * @author Stephane Nicoll */ -public class CassandraTestServer { +public class CassandraTestServer implements TestRule { + + private static final Log logger = LogFactory.getLog(CassandraTestServer.class); + + private Cluster cluster; + + @Override + public Statement apply(Statement base, Description description) { + try { + this.cluster = newCluster(); + return new CassandraStatement(base, this.cluster); + } + catch (Exception ex) { + logger.error("No Cassandra server available", ex); + return new SkipStatement(); + } + } + + private Cluster newCluster() { + Cluster cluster = Cluster.builder().addContactPoint("localhost").build(); + testCluster(cluster); + return cluster; + } + + private void testCluster(Cluster cluster) { + cluster.connect().close(); + } + + /** + * @return the cluster if any + */ + public Cluster getCluster() { + return this.cluster; + } + + private static class CassandraStatement extends Statement { + + private final Statement base; + + private final Cluster cluster; + + CassandraStatement(Statement base, Cluster cluster) { + this.base = base; + this.cluster = cluster; + } + + @Override + public void evaluate() throws Throwable { + try { + this.base.evaluate(); + } + finally { + this.cluster.closeAsync(); + } + } + + } + + private static class SkipStatement extends Statement { + + @Override + public void evaluate() throws Throwable { + Assume.assumeTrue("Skipping test due to Cassandra not being available", false); + } + + } + } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/city/City.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/city/City.java index fd9436bedb..2ddbe1c7b6 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/city/City.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/city/City.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-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. diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 9cb3bc07a1..b1f34a86b0 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -548,7 +548,7 @@ content into your application; rather pick only the properties that you need. spring.data.cassandra.reconnection-policy= # Reconnection policy class. spring.data.cassandra.retry-policy= # Class name of the retry policy. spring.data.cassandra.serial-consistency-level= # Queries serial consistency level. - spring.data.cassandra.schema-action= # Action to take at starup. Default: NONE. + spring.data.cassandra.schema-action= # Schema action to take at startup. spring.data.cassandra.ssl=false # Enable SSL support. spring.data.cassandra.username= # Login user of the server.