/* * Copyright 2016-2017 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.data.cassandra.config; import static org.assertj.core.api.Assertions.*; import java.util.Collections; import java.util.List; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.springframework.beans.factory.BeanCreationException; import org.springframework.cassandra.config.CassandraCqlClusterFactoryBean; import org.springframework.cassandra.core.SessionCallback; import org.springframework.cassandra.test.integration.AbstractEmbeddedCassandraIntegrationTest; import org.springframework.cassandra.test.integration.KeyspaceRule; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.cassandra.config.java.AbstractCassandraConfiguration; import org.springframework.data.cassandra.test.integration.repository.querymethods.declared.Person; import com.datastax.driver.core.Cluster; import com.datastax.driver.core.KeyspaceMetadata; import com.datastax.driver.core.Metadata; import com.datastax.driver.core.Session; import com.datastax.driver.core.TableMetadata; /** * The SchemaActionIntegrationTests class is a test suite of test cases testing the contract and behavior of various * {@link SchemaAction}s on startup of a Spring configured, Cassandra application client. * * @author John Blum * @author Mark Paluch */ public class SchemaActionIntegrationTests extends AbstractEmbeddedCassandraIntegrationTest { protected static final String KEYSPACE_NAME = SchemaActionIntegrationTests.class.getSimpleName().toLowerCase(); protected static final String PERSON_TABLE_DEFINITION_CQL = String .format("CREATE TABLE %s.person (id int, firstName text, lastName text, PRIMARY KEY(id));", KEYSPACE_NAME); @Rule public ExpectedException exception = ExpectedException.none(); @Rule public KeyspaceRule KEYSPACE_RULE = new KeyspaceRule(cassandraEnvironment, KEYSPACE_NAME); protected ConfigurableApplicationContext newApplicationContext(Class<?>... annotatedClasses) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(annotatedClasses); applicationContext.registerShutdownHook(); return applicationContext; } protected <T> T doInSessionWithConfiguration(Class<?> annotatedClass, SessionCallback<T> sessionCallback) { ConfigurableApplicationContext applicationContext = null; try { applicationContext = newApplicationContext(annotatedClass); return sessionCallback.doInSession(applicationContext.getBean(Session.class)); } finally { if (applicationContext != null) { applicationContext.close(); } } } protected void assertHasTableWithColumns(Session session, String tableName, String... columns) { Metadata clusterMetadata = session.getCluster().getMetadata(); KeyspaceMetadata keyspaceMetadata = clusterMetadata.getKeyspace(KEYSPACE_NAME); assertThat(keyspaceMetadata).isNotNull(); TableMetadata tableMetadata = keyspaceMetadata.getTable(tableName); assertThat(tableMetadata).isNotNull(); assertThat(tableMetadata.getColumns()).hasSize(columns.length); for (String columnName : columns) { assertThat(tableMetadata.getColumn(columnName)).isNotNull(); } assertThat(tableMetadata.getColumns()).hasSize(columns.length); } @Test public void createWithNoExistingTableCreatesTableFromEntity() { doInSessionWithConfiguration(CreateWithNoExistingTableConfiguration.class, (SessionCallback<Void>) session -> { assertHasTableWithColumns(session, "person", "firstName", "lastName", "nickname", "birthDate", "numberOfChildren", "cool", "createdDate", "zoneId", "mainAddress", "alternativeAddresses"); return null; }); } @Test public void createWithExistingTableThrowsErrorWhenCreatingTableFromEntity() { try { doInSessionWithConfiguration(CreateWithExistingTableConfiguration.class, s -> { fail(String.format("%s should have failed!", CreateWithExistingTableConfiguration.class.getSimpleName())); return null; }); fail("Missing BeanCreationException"); } catch (BeanCreationException e) { assertThat(e).hasMessageContaining(String.format("Table %s.person already exists", KEYSPACE_NAME)); } } @Test public void createIfNotExistsWithNoExistingTableCreatesTableFromEntity() { doInSessionWithConfiguration(CreateIfNotExistsWithNoExistingTableConfiguration.class, (SessionCallback<Void>) session -> { assertHasTableWithColumns(session, "person", "firstName", "lastName", "nickname", "birthDate", "numberOfChildren", "cool", "createdDate", "zoneId", "mainAddress", "alternativeAddresses"); return null; }); } @Test public void createIfNotExistsWithExistingTableUsesExistingTable() { doInSessionWithConfiguration(CreateIfNotExistsWithExistingTableConfiguration.class, (SessionCallback<Void>) session -> { assertHasTableWithColumns(session, "person", "id", "firstName", "lastName"); return null; }); } @Test public void recreateTableFromEntityDropsExistingTable() { doInSessionWithConfiguration(RecreateSchemaActionWithExistingTableConfiguration.class, (SessionCallback<Void>) session -> { assertHasTableWithColumns(session, "person", "firstName", "lastName", "nickname", "birthDate", "numberOfChildren", "cool", "createdDate", "zoneId", "mainAddress", "alternativeAddresses"); return null; }); } @Configuration static class CreateWithNoExistingTableConfiguration extends CassandraConfiguration { @Override public SchemaAction getSchemaAction() { return SchemaAction.CREATE; } } @Configuration static class CreateWithExistingTableConfiguration extends CassandraConfiguration { @Override public SchemaAction getSchemaAction() { return SchemaAction.CREATE; } @Override protected List<String> getStartupScripts() { return Collections.singletonList(PERSON_TABLE_DEFINITION_CQL); } } @Configuration static class CreateIfNotExistsWithNoExistingTableConfiguration extends CassandraConfiguration { @Override public SchemaAction getSchemaAction() { return SchemaAction.CREATE_IF_NOT_EXISTS; } } @Configuration static class CreateIfNotExistsWithExistingTableConfiguration extends CassandraConfiguration { @Override public SchemaAction getSchemaAction() { return SchemaAction.CREATE_IF_NOT_EXISTS; } @Override protected List<String> getStartupScripts() { return Collections.singletonList(PERSON_TABLE_DEFINITION_CQL); } } @Configuration static class RecreateSchemaActionWithExistingTableConfiguration extends CassandraConfiguration { @Override public SchemaAction getSchemaAction() { return SchemaAction.RECREATE; } @Override protected List<String> getStartupScripts() { return Collections.singletonList(PERSON_TABLE_DEFINITION_CQL); } } @Configuration static abstract class CassandraConfiguration extends AbstractCassandraConfiguration { @Bean @Override public CassandraCqlClusterFactoryBean cluster() { return new CassandraCqlClusterFactoryBean() { @Override public void afterPropertiesSet() throws Exception { // avoid Cassandra Cluster creation; use embedded } @Override public Cluster getObject() { return cassandraEnvironment.getCluster(); } }; } @Override public String[] getEntityBasePackages() { return new String[] { Person.class.getPackage().getName() }; } @Override protected String getKeyspaceName() { return KEYSPACE_NAME; } } }