diff --git a/cassandra/example/src/test/java/example/springdata/cassandra/auditing/AuditedPersonRepositoryTests.java b/cassandra/example/src/test/java/example/springdata/cassandra/auditing/AuditedPersonRepositoryTests.java index 99b54fc4..0b24aa44 100644 --- a/cassandra/example/src/test/java/example/springdata/cassandra/auditing/AuditedPersonRepositoryTests.java +++ b/cassandra/example/src/test/java/example/springdata/cassandra/auditing/AuditedPersonRepositoryTests.java @@ -22,30 +22,25 @@ import example.springdata.cassandra.util.CassandraKeyspace; import java.time.Duration; import java.time.Instant; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; /** * Integration test showing the basic usage of Auditing through {@link AuditedPersonRepository}. * * @author Mark Paluch */ -@RunWith(SpringRunner.class) @SpringBootTest(classes = BasicConfiguration.class) -public class AuditedPersonRepositoryTests { - - @ClassRule public final static CassandraKeyspace CASSANDRA_KEYSPACE = CassandraKeyspace.onLocalhost(); +@CassandraKeyspace +class AuditedPersonRepositoryTests { @Autowired AuditedPersonRepository repository; - @Before - public void setUp() { + @BeforeEach + void setUp() { repository.deleteAll(); } @@ -53,7 +48,7 @@ public class AuditedPersonRepositoryTests { * Saving an object using the Cassandra Repository will create a persistent representation of the object in Cassandra. */ @Test - public void insertShouldSetCreatedDate() { + void insertShouldSetCreatedDate() { AuditedPerson person = new AuditedPerson(); person.setId(42L); @@ -73,7 +68,7 @@ public class AuditedPersonRepositoryTests { * Modifying an existing object will update the last modified fields. */ @Test - public void updateShouldSetLastModifiedDate() { + void updateShouldSetLastModifiedDate() { AuditedPerson person = new AuditedPerson(); person.setId(42L); diff --git a/cassandra/example/src/test/java/example/springdata/cassandra/basic/BasicUserRepositoryTests.java b/cassandra/example/src/test/java/example/springdata/cassandra/basic/BasicUserRepositoryTests.java index 37b6a434..fb63006d 100644 --- a/cassandra/example/src/test/java/example/springdata/cassandra/basic/BasicUserRepositoryTests.java +++ b/cassandra/example/src/test/java/example/springdata/cassandra/basic/BasicUserRepositoryTests.java @@ -16,20 +16,17 @@ package example.springdata.cassandra.basic; import static org.assertj.core.api.Assertions.*; -import static org.junit.Assume.*; +import static org.assertj.core.api.Assumptions.*; import example.springdata.cassandra.util.CassandraKeyspace; import example.springdata.cassandra.util.CassandraVersion; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.util.Version; -import org.springframework.test.context.junit4.SpringRunner; import com.datastax.oss.driver.api.core.CqlSession; @@ -41,20 +38,18 @@ import com.datastax.oss.driver.api.core.CqlSession; * @author Christoph Strobl * @author Mark Paluch */ -@RunWith(SpringRunner.class) @SpringBootTest(classes = BasicConfiguration.class) -public class BasicUserRepositoryTests { +@CassandraKeyspace +class BasicUserRepositoryTests { - public final static Version CASSANDRA_3_4 = Version.parse("3.4"); - - @ClassRule public final static CassandraKeyspace CASSANDRA_KEYSPACE = CassandraKeyspace.onLocalhost(); + private final static Version CASSANDRA_3_4 = Version.parse("3.4"); @Autowired BasicUserRepository repository; @Autowired CqlSession session; - User user; + private User user; - @Before - public void setUp() { + @BeforeEach + void setUp() { user = new User(); user.setId(42L); @@ -67,7 +62,7 @@ public class BasicUserRepositoryTests { * Saving an object using the Cassandra Repository will create a persistent representation of the object in Cassandra. */ @Test - public void findSavedUserById() { + void findSavedUserById() { user = repository.save(user); @@ -78,7 +73,7 @@ public class BasicUserRepositoryTests { * Cassandra can be queries by using query methods annotated with {@link @Query}. */ @Test - public void findByAnnotatedQueryMethod() { + void findByAnnotatedQueryMethod() { repository.save(user); @@ -92,7 +87,7 @@ public class BasicUserRepositoryTests { * key requires a secondary index. */ @Test - public void findByDerivedQueryMethod() throws InterruptedException { + void findByDerivedQueryMethod() throws InterruptedException { session.execute("CREATE INDEX IF NOT EXISTS user_username ON users (uname);"); /* @@ -110,9 +105,9 @@ public class BasicUserRepositoryTests { * Spring Data Cassandra supports {@code LIKE} and {@code CONTAINS} query keywords to for SASI indexes. */ @Test - public void findByDerivedQueryMethodWithSASI() throws InterruptedException { + void findByDerivedQueryMethodWithSASI() throws InterruptedException { - assumeTrue(CassandraVersion.getReleaseVersion(session).isGreaterThanOrEqualTo(CASSANDRA_3_4)); + assumeThat(CassandraVersion.getReleaseVersion(session).isGreaterThanOrEqualTo(CASSANDRA_3_4)).isTrue(); session.execute("CREATE CUSTOM INDEX ON users (lname) USING 'org.apache.cassandra.index.sasi.SASIIndex';"); /* diff --git a/cassandra/example/src/test/java/example/springdata/cassandra/basic/CassandraOperationsIntegrationTests.java b/cassandra/example/src/test/java/example/springdata/cassandra/basic/CassandraOperationsIntegrationTests.java index 05744ba8..3cc34831 100644 --- a/cassandra/example/src/test/java/example/springdata/cassandra/basic/CassandraOperationsIntegrationTests.java +++ b/cassandra/example/src/test/java/example/springdata/cassandra/basic/CassandraOperationsIntegrationTests.java @@ -24,17 +24,14 @@ import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.cassandra.core.AsyncCassandraTemplate; import org.springframework.data.cassandra.core.CassandraOperations; import org.springframework.data.cassandra.core.CassandraTemplate; -import org.springframework.test.context.junit4.SpringRunner; import org.springframework.util.concurrent.ListenableFuture; import com.datastax.oss.driver.api.core.CqlSession; @@ -47,16 +44,15 @@ import com.datastax.oss.driver.api.querybuilder.insert.Insert; * * @author Mark Paluch */ -@RunWith(SpringRunner.class) @SpringBootTest(classes = BasicConfiguration.class) +@CassandraKeyspace public class CassandraOperationsIntegrationTests { - @ClassRule public final static CassandraKeyspace CASSANDRA_KEYSPACE = CassandraKeyspace.onLocalhost(); @Autowired CqlSession session; @Autowired CassandraOperations template; - @Before + @BeforeEach public void setUp() throws Exception { template.getCqlOperations().execute("TRUNCATE users"); } diff --git a/cassandra/example/src/test/java/example/springdata/cassandra/convert/ConversionIntegrationTests.java b/cassandra/example/src/test/java/example/springdata/cassandra/convert/ConversionIntegrationTests.java index 1e9411c0..7ef24cba 100644 --- a/cassandra/example/src/test/java/example/springdata/cassandra/convert/ConversionIntegrationTests.java +++ b/cassandra/example/src/test/java/example/springdata/cassandra/convert/ConversionIntegrationTests.java @@ -17,9 +17,6 @@ package example.springdata.cassandra.convert; import static org.assertj.core.api.Assertions.*; -import com.datastax.oss.driver.api.core.cql.Row; -import com.datastax.oss.driver.api.core.data.TupleValue; -import com.datastax.oss.driver.api.querybuilder.QueryBuilder; import example.springdata.cassandra.util.CassandraKeyspace; import java.util.Arrays; @@ -27,29 +24,29 @@ import java.util.Currency; import java.util.HashMap; import java.util.Map; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.cassandra.core.CassandraOperations; -import org.springframework.test.context.junit4.SpringRunner; + +import com.datastax.oss.driver.api.core.cql.Row; +import com.datastax.oss.driver.api.core.data.TupleValue; +import com.datastax.oss.driver.api.querybuilder.QueryBuilder; /** * @author Mark Paluch */ -@RunWith(SpringRunner.class) +@CassandraKeyspace @SpringBootTest(classes = ConverterConfiguration.class) -public class ConversionIntegrationTests { - - @ClassRule public final static CassandraKeyspace CASSANDRA_KEYSPACE = CassandraKeyspace.onLocalhost(); +class ConversionIntegrationTests { @Autowired CassandraOperations operations; - @Before - public void setUp() { + @BeforeEach + void setUp() { operations.truncate(Addressbook.class); } @@ -58,7 +55,7 @@ public class ConversionIntegrationTests { * custom {@link example.springdata.cassandra.convert.ConverterConfiguration.PersonWriteConverter}. */ @Test - public void shouldCreateAddressbook() { + void shouldCreateAddressbook() { Addressbook addressbook = new Addressbook(); addressbook.setId("private"); @@ -82,7 +79,7 @@ public class ConversionIntegrationTests { * custom {@link example.springdata.cassandra.convert.ConverterConfiguration.PersonReadConverter}. */ @Test - public void shouldReadAddressbook() { + void shouldReadAddressbook() { Addressbook addressbook = new Addressbook(); addressbook.setId("private"); @@ -104,7 +101,7 @@ public class ConversionIntegrationTests { * {@link example.springdata.cassandra.convert.ConverterConfiguration.CustomAddressbookReadConverter}. */ @Test - public void shouldReadCustomAddressbook() { + void shouldReadCustomAddressbook() { Addressbook addressbook = new Addressbook(); addressbook.setId("private"); @@ -124,7 +121,7 @@ public class ConversionIntegrationTests { * Creates and stores a new {@link Addressbook} inside of Cassandra writing map and tuple columns. */ @Test - public void shouldWriteConvertedMapsAndTuples() { + void shouldWriteConvertedMapsAndTuples() { Addressbook addressbook = new Addressbook(); addressbook.setId("private"); diff --git a/cassandra/example/src/test/java/example/springdata/cassandra/events/LifecycleEventsTests.java b/cassandra/example/src/test/java/example/springdata/cassandra/events/LifecycleEventsTests.java index 6fdb4ac0..84c266e8 100644 --- a/cassandra/example/src/test/java/example/springdata/cassandra/events/LifecycleEventsTests.java +++ b/cassandra/example/src/test/java/example/springdata/cassandra/events/LifecycleEventsTests.java @@ -20,14 +20,12 @@ import example.springdata.cassandra.util.CassandraKeyspace; import java.util.List; import java.util.stream.Stream; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.cassandra.core.CassandraOperations; import org.springframework.data.cassandra.core.query.Query; -import org.springframework.test.context.junit4.SpringRunner; /** * Test showing differences between fetching results as {@link List} and {@link Stream streaming} results using @@ -35,12 +33,10 @@ import org.springframework.test.context.junit4.SpringRunner; * * @author Mark Paluch */ -@RunWith(SpringRunner.class) @SpringBootTest(classes = BasicConfiguration.class) +@CassandraKeyspace public class LifecycleEventsTests { - @ClassRule public final static CassandraKeyspace CASSANDRA_KEYSPACE = CassandraKeyspace.onLocalhost(); - @Autowired CassandraOperations operations; @Test diff --git a/cassandra/example/src/test/java/example/springdata/cassandra/optimisticlocking/OptimisticPersonRepositoryTests.java b/cassandra/example/src/test/java/example/springdata/cassandra/optimisticlocking/OptimisticPersonRepositoryTests.java index e081c641..d194ac2a 100644 --- a/cassandra/example/src/test/java/example/springdata/cassandra/optimisticlocking/OptimisticPersonRepositoryTests.java +++ b/cassandra/example/src/test/java/example/springdata/cassandra/optimisticlocking/OptimisticPersonRepositoryTests.java @@ -17,12 +17,8 @@ package example.springdata.cassandra.optimisticlocking; import static org.assertj.core.api.Assertions.*; -import example.springdata.cassandra.util.CassandraKeyspace; - -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -31,23 +27,19 @@ import org.springframework.data.cassandra.core.CassandraOperations; import org.springframework.data.cassandra.core.EntityWriteResult; import org.springframework.data.cassandra.core.UpdateOptions; import org.springframework.data.cassandra.core.query.Criteria; -import org.springframework.test.context.junit4.SpringRunner; /** * Integration test showing the basic usage of Optimistic Locking through {@link OptimisticPersonRepository}. * * @author Mark Paluch */ -@RunWith(SpringRunner.class) @SpringBootTest(classes = BasicConfiguration.class) public class OptimisticPersonRepositoryTests { - @ClassRule public final static CassandraKeyspace CASSANDRA_KEYSPACE = CassandraKeyspace.onLocalhost(); - @Autowired OptimisticPersonRepository repository; @Autowired CassandraOperations operations; - @Before + @BeforeEach public void setUp() { repository.deleteAll(); } diff --git a/cassandra/example/src/test/java/example/springdata/cassandra/projection/CustomerRepositoryIntegrationTest.java b/cassandra/example/src/test/java/example/springdata/cassandra/projection/CustomerRepositoryIntegrationTest.java index cc5eb8f1..85cc14dc 100644 --- a/cassandra/example/src/test/java/example/springdata/cassandra/projection/CustomerRepositoryIntegrationTest.java +++ b/cassandra/example/src/test/java/example/springdata/cassandra/projection/CustomerRepositoryIntegrationTest.java @@ -21,32 +21,28 @@ import example.springdata.cassandra.util.CassandraKeyspace; import java.util.Collection; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.projection.TargetAware; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * Integration tests for {@link CustomerRepository} to show projection capabilities. * * @author Mark Paluch */ -@RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = ProjectionConfiguration.class) -public class CustomerRepositoryIntegrationTest { - - @ClassRule public final static CassandraKeyspace CASSANDRA_KEYSPACE = CassandraKeyspace.onLocalhost(); +@CassandraKeyspace +class CustomerRepositoryIntegrationTest { @Autowired CustomerRepository customers; - Customer dave, carter; + private Customer dave, carter; - @Before - public void setUp() { + @BeforeEach + void setUp() { customers.deleteAll(); @@ -55,7 +51,7 @@ public class CustomerRepositoryIntegrationTest { } @Test - public void projectsEntityIntoInterface() { + void projectsEntityIntoInterface() { Collection result = customers.findAllProjectedBy(); @@ -64,7 +60,7 @@ public class CustomerRepositoryIntegrationTest { } @Test - public void projectsDynamically() { + void projectsDynamically() { Collection result = customers.findById("d", CustomerProjection.class); @@ -73,7 +69,7 @@ public class CustomerRepositoryIntegrationTest { } @Test - public void projectsIndividualDynamically() { + void projectsIndividualDynamically() { CustomerSummary result = customers.findProjectedById(dave.getId(), CustomerSummary.class); @@ -85,7 +81,7 @@ public class CustomerRepositoryIntegrationTest { } @Test - public void projectIndividualInstance() { + void projectIndividualInstance() { CustomerProjection result = customers.findProjectedById(dave.getId()); diff --git a/cassandra/example/src/test/java/example/springdata/cassandra/udt/UserDefinedTypeIntegrationTest.java b/cassandra/example/src/test/java/example/springdata/cassandra/udt/UserDefinedTypeIntegrationTest.java index e1b47662..cbccf32c 100644 --- a/cassandra/example/src/test/java/example/springdata/cassandra/udt/UserDefinedTypeIntegrationTest.java +++ b/cassandra/example/src/test/java/example/springdata/cassandra/udt/UserDefinedTypeIntegrationTest.java @@ -21,10 +21,8 @@ import example.springdata.cassandra.util.CassandraKeyspace; import java.util.Collections; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -33,7 +31,6 @@ import org.springframework.data.cassandra.config.AbstractCassandraConfiguration; import org.springframework.data.cassandra.config.SchemaAction; import org.springframework.data.cassandra.core.CassandraAdminOperations; import org.springframework.data.cassandra.core.CassandraOperations; -import org.springframework.test.context.junit4.SpringRunner; import com.datastax.oss.driver.api.core.data.UdtValue; import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; @@ -45,11 +42,9 @@ import com.datastax.oss.driver.api.core.type.UserDefinedType; * @author Mark Paluch * @author Oliver Gierke */ -@RunWith(SpringRunner.class) @SpringBootTest -public class UserDefinedTypeIntegrationTest { - - @ClassRule public final static CassandraKeyspace CASSANDRA_KEYSPACE = CassandraKeyspace.onLocalhost(); +@CassandraKeyspace +class UserDefinedTypeIntegrationTest { @Configuration static class Config extends AbstractCassandraConfiguration { @@ -78,8 +73,8 @@ public class UserDefinedTypeIntegrationTest { @Autowired CassandraOperations operations; @Autowired CassandraAdminOperations adminOperations; - @Before - public void before() throws Exception { + @BeforeEach + void before() throws Exception { operations.getCqlOperations().execute("TRUNCATE person"); } @@ -87,7 +82,7 @@ public class UserDefinedTypeIntegrationTest { * Insert a row with a mapped User-defined type. */ @Test - public void insertMappedUdt() { + void insertMappedUdt() { Person person = new Person(); person.setId(42); @@ -109,7 +104,7 @@ public class UserDefinedTypeIntegrationTest { * Insert a row with a raw User-defined type. */ @Test - public void insertRawUdt() { + void insertRawUdt() { KeyspaceMetadata keyspaceMetadata = adminOperations.getKeyspaceMetadata(); UserDefinedType address = keyspaceMetadata.getUserDefinedType("address").get(); diff --git a/cassandra/java8/src/test/java/example/springdata/cassandra/java8/Java8IntegrationTests.java b/cassandra/java8/src/test/java/example/springdata/cassandra/java8/Java8IntegrationTests.java index fb4d1dd8..cb6ab717 100755 --- a/cassandra/java8/src/test/java/example/springdata/cassandra/java8/Java8IntegrationTests.java +++ b/cassandra/java8/src/test/java/example/springdata/cassandra/java8/Java8IntegrationTests.java @@ -23,36 +23,30 @@ import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.util.Version; -import org.springframework.test.context.junit4.SpringRunner; /** * Integration test to show the usage of Java 8 features with Spring Data Cassandra. * * @author Mark Paluch */ -@RunWith(SpringRunner.class) +@CassandraKeyspace @SpringBootTest(classes = CassandraConfiguration.class) -public class Java8IntegrationTests { - - @ClassRule public final static CassandraKeyspace CASSANDRA_KEYSPACE = CassandraKeyspace.onLocalhost() - .atLeast(Version.parse("3.0")); +class Java8IntegrationTests { @Autowired PersonRepository repository; - @Before - public void setUp() throws Exception { + @BeforeEach + void setUp() throws Exception { repository.deleteAll(); } @Test - public void providesFindOneWithOptional() { + void providesFindOneWithOptional() { Person homer = repository.save(new Person("1", "Homer", "Simpson")); @@ -61,7 +55,7 @@ public class Java8IntegrationTests { } @Test - public void invokesDefaultMethod() { + void invokesDefaultMethod() { Person homer = repository.save(new Person("1", "Homer", "Simpson")); Optional result = repository.findByPerson(homer); @@ -75,7 +69,7 @@ public class Java8IntegrationTests { * resulting {@link Stream} contains state it needs to be closed explicitly after use! */ @Test - public void useJava8StreamsWithCustomQuery() { + void useJava8StreamsWithCustomQuery() { Person homer = repository.save(new Person("1", "Homer", "Simpson")); Person bart = repository.save(new Person("2", "Bart", "Simpson")); diff --git a/cassandra/java8/src/test/java/example/springdata/cassandra/java8/Jsr310IntegrationTests.java b/cassandra/java8/src/test/java/example/springdata/cassandra/java8/Jsr310IntegrationTests.java index ce3b766b..02b1fac5 100755 --- a/cassandra/java8/src/test/java/example/springdata/cassandra/java8/Jsr310IntegrationTests.java +++ b/cassandra/java8/src/test/java/example/springdata/cassandra/java8/Jsr310IntegrationTests.java @@ -22,36 +22,30 @@ import example.springdata.cassandra.util.CassandraKeyspace; import java.time.LocalDate; import java.time.ZoneId; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.util.Version; -import org.springframework.test.context.junit4.SpringRunner; /** * Integration test to show the usage of JSR-310 date/time types with Spring Data Cassandra. * * @author Mark Paluch */ -@RunWith(SpringRunner.class) +@CassandraKeyspace @SpringBootTest(classes = CassandraConfiguration.class) -public class Jsr310IntegrationTests { - - @ClassRule public final static CassandraKeyspace CASSANDRA_KEYSPACE = CassandraKeyspace.onLocalhost() - .atLeast(Version.parse("3.0")); +class Jsr310IntegrationTests { @Autowired OrderRepository repository; - @Before - public void setUp() throws Exception { + @BeforeEach + void setUp() throws Exception { repository.deleteAll(); } @Test - public void findOneByJsr310Types() { + void findOneByJsr310Types() { Order order = new Order("42", LocalDate.now(), ZoneId.systemDefault()); diff --git a/cassandra/kotlin/src/test/kotlin/example/springdata/cassandra/kotlin/RepositoryTests.kt b/cassandra/kotlin/src/test/kotlin/example/springdata/cassandra/kotlin/RepositoryTests.kt index e416e16e..68c8a54a 100644 --- a/cassandra/kotlin/src/test/kotlin/example/springdata/cassandra/kotlin/RepositoryTests.kt +++ b/cassandra/kotlin/src/test/kotlin/example/springdata/cassandra/kotlin/RepositoryTests.kt @@ -18,37 +18,25 @@ package example.springdata.cassandra.kotlin import example.springdata.cassandra.util.CassandraKeyspace import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatThrownBy -import org.junit.Before -import org.junit.ClassRule -import org.junit.Test -import org.junit.runner.RunWith +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.dao.EmptyResultDataAccessException -import org.springframework.data.util.Version -import org.springframework.test.context.junit4.SpringRunner /** * Tests showing Kotlin usage of Spring Data Repositories. * * @author Mark Paluch */ -@RunWith(SpringRunner::class) +@CassandraKeyspace @SpringBootTest class RepositoryTests { - companion object { - - @JvmField - @ClassRule - val CASSANDRA_KEYSPACE = CassandraKeyspace.onLocalhost() - .atLeast(Version.parse("3.0")) - } - @Autowired lateinit var repository: PersonRepository - @Before + @BeforeEach fun before() { repository.deleteAll() } diff --git a/cassandra/kotlin/src/test/kotlin/example/springdata/cassandra/kotlin/TemplateTests.kt b/cassandra/kotlin/src/test/kotlin/example/springdata/cassandra/kotlin/TemplateTests.kt index b6f7942a..cbff1000 100644 --- a/cassandra/kotlin/src/test/kotlin/example/springdata/cassandra/kotlin/TemplateTests.kt +++ b/cassandra/kotlin/src/test/kotlin/example/springdata/cassandra/kotlin/TemplateTests.kt @@ -19,40 +19,28 @@ import com.datastax.oss.driver.api.core.CqlIdentifier import com.datastax.oss.driver.api.querybuilder.QueryBuilder import example.springdata.cassandra.util.CassandraKeyspace import org.assertj.core.api.Assertions.assertThat -import org.junit.Before -import org.junit.ClassRule -import org.junit.Test -import org.junit.runner.RunWith +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.data.cassandra.core.* import org.springframework.data.cassandra.core.query.Query.query import org.springframework.data.cassandra.core.query.isEqualTo import org.springframework.data.cassandra.core.query.where -import org.springframework.data.util.Version -import org.springframework.test.context.junit4.SpringRunner /** * Tests showing Kotlin usage of [MongoTemplate] and its Kotlin extensions. * * @author Mark Paluch */ -@RunWith(SpringRunner::class) +@CassandraKeyspace @SpringBootTest class TemplateTests { - companion object { - - @JvmField - @ClassRule - val CASSANDRA_KEYSPACE = CassandraKeyspace.onLocalhost() - .atLeast(Version.parse("3.0")) - } - @Autowired lateinit var operations: CassandraOperations - @Before + @BeforeEach fun before() { operations.truncate() } diff --git a/cassandra/reactive/src/test/java/example/springdata/cassandra/auditing/AuditingIntegrationTests.java b/cassandra/reactive/src/test/java/example/springdata/cassandra/auditing/AuditingIntegrationTests.java index ba5cf6de..614ef22f 100644 --- a/cassandra/reactive/src/test/java/example/springdata/cassandra/auditing/AuditingIntegrationTests.java +++ b/cassandra/reactive/src/test/java/example/springdata/cassandra/auditing/AuditingIntegrationTests.java @@ -22,25 +22,20 @@ import reactor.test.StepVerifier; import java.time.Instant; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.data.cassandra.DataCassandraTest; -import org.springframework.test.context.junit4.SpringRunner; /** * Integration tests showing Reactive Auditing with Cassandra in action. * * @author Mark Paluch */ -@RunWith(SpringRunner.class) +@CassandraKeyspace @DataCassandraTest public class AuditingIntegrationTests { - @ClassRule public final static CassandraKeyspace CASSANDRA_KEYSPACE = CassandraKeyspace.onLocalhost(); - @Autowired OrderRepository orderRepository; @Test diff --git a/cassandra/reactive/src/test/java/example/springdata/cassandra/people/ReactiveCassandraTemplateIntegrationTest.java b/cassandra/reactive/src/test/java/example/springdata/cassandra/people/ReactiveCassandraTemplateIntegrationTest.java index 021e7a2e..e4aeeec3 100644 --- a/cassandra/reactive/src/test/java/example/springdata/cassandra/people/ReactiveCassandraTemplateIntegrationTest.java +++ b/cassandra/reactive/src/test/java/example/springdata/cassandra/people/ReactiveCassandraTemplateIntegrationTest.java @@ -23,33 +23,29 @@ import reactor.core.publisher.Mono; import reactor.test.StepVerifier; import rx.RxReactiveStreams; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.cassandra.core.ReactiveCassandraTemplate; -import org.springframework.test.context.junit4.SpringRunner; /** * Integration test for {@link ReactiveCassandraTemplate}. * * @author Mark Paluch */ -@RunWith(SpringRunner.class) +@CassandraKeyspace @SpringBootTest -public class ReactiveCassandraTemplateIntegrationTest { - - @ClassRule public final static CassandraKeyspace CASSANDRA_KEYSPACE = CassandraKeyspace.onLocalhost(); +class ReactiveCassandraTemplateIntegrationTest { @Autowired ReactiveCassandraTemplate template; /** * Truncate table and insert some rows. */ - @Before - public void setUp() { + @BeforeEach + void setUp() { Flux truncateAndInsert = template.truncate(Person.class) // .thenMany(Flux.just(new Person("Walter", "White", 50), // @@ -66,7 +62,7 @@ public class ReactiveCassandraTemplateIntegrationTest { * the two counts ({@code 4} and {@code 6}) to the console. */ @Test - public void shouldInsertAndCountData() { + void shouldInsertAndCountData() { Mono saveAndCount = template.count(Person.class) // .doOnNext(System.out::println) // @@ -84,7 +80,7 @@ public class ReactiveCassandraTemplateIntegrationTest { * Note that the all object conversions are performed before the results are printed to the console. */ @Test - public void convertReactorTypesToRxJava1() throws Exception { + void convertReactorTypesToRxJava1() throws Exception { Flux flux = template.select("SELECT * FROM person WHERE lastname = 'White'", Person.class); diff --git a/cassandra/reactive/src/test/java/example/springdata/cassandra/people/ReactivePersonRepositoryIntegrationTest.java b/cassandra/reactive/src/test/java/example/springdata/cassandra/people/ReactivePersonRepositoryIntegrationTest.java index 670edec1..828096a2 100644 --- a/cassandra/reactive/src/test/java/example/springdata/cassandra/people/ReactivePersonRepositoryIntegrationTest.java +++ b/cassandra/reactive/src/test/java/example/springdata/cassandra/people/ReactivePersonRepositoryIntegrationTest.java @@ -20,32 +20,28 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; /** * Integration test for {@link ReactivePersonRepository} using Project Reactor types and operators. * * @author Mark Paluch */ -@RunWith(SpringRunner.class) @SpringBootTest -public class ReactivePersonRepositoryIntegrationTest { - - @ClassRule public final static CassandraKeyspace CASSANDRA_KEYSPACE = CassandraKeyspace.onLocalhost(); +@CassandraKeyspace +class ReactivePersonRepositoryIntegrationTest { @Autowired ReactivePersonRepository repository; /** * Clear table and insert some rows. */ - @Before - public void setUp() { + @BeforeEach + void setUp() { Flux deleteAndInsert = repository.deleteAll() // .thenMany(repository.saveAll(Flux.just(new Person("Walter", "White", 50), // @@ -60,7 +56,7 @@ public class ReactivePersonRepositoryIntegrationTest { * This sample performs a count, inserts data and performs a count again using reactive operator chaining. */ @Test - public void shouldInsertAndCountData() { + void shouldInsertAndCountData() { Mono saveAndCount = repository.count() // .doOnNext(System.out::println) // @@ -78,7 +74,7 @@ public class ReactivePersonRepositoryIntegrationTest { * prefetch define the amount of fetched records. */ @Test - public void shouldPerformConversionBeforeResultProcessing() { + void shouldPerformConversionBeforeResultProcessing() { StepVerifier.create(repository.findAll().doOnNext(System.out::println)) // .expectNextCount(4) // @@ -89,7 +85,7 @@ public class ReactivePersonRepositoryIntegrationTest { * Fetch data using query derivation. */ @Test - public void shouldQueryDataWithQueryDerivation() { + void shouldQueryDataWithQueryDerivation() { StepVerifier.create(repository.findByLastname("White")).expectNextCount(2).verifyComplete(); } @@ -97,7 +93,7 @@ public class ReactivePersonRepositoryIntegrationTest { * Fetch data using a string query. */ @Test - public void shouldQueryDataWithStringQuery() { + void shouldQueryDataWithStringQuery() { StepVerifier.create(repository.findByFirstnameInAndLastname("Walter", "White")).expectNextCount(1).verifyComplete(); } @@ -105,7 +101,7 @@ public class ReactivePersonRepositoryIntegrationTest { * Fetch data using query derivation. */ @Test - public void shouldQueryDataWithDeferredQueryDerivation() { + void shouldQueryDataWithDeferredQueryDerivation() { StepVerifier.create(repository.findByLastname(Mono.just("White"))).expectNextCount(2).verifyComplete(); } @@ -113,7 +109,7 @@ public class ReactivePersonRepositoryIntegrationTest { * Fetch data using query derivation and deferred parameter resolution. */ @Test - public void shouldQueryDataWithMixedDeferredQueryDerivation() { + void shouldQueryDataWithMixedDeferredQueryDerivation() { StepVerifier.create(repository.findByFirstnameAndLastname(Mono.just("Walter"), "White")) // .expectNextCount(1) // diff --git a/cassandra/reactive/src/test/java/example/springdata/cassandra/people/RxJava2PersonRepositoryIntegrationTest.java b/cassandra/reactive/src/test/java/example/springdata/cassandra/people/RxJava2PersonRepositoryIntegrationTest.java index bb315845..fdb5425b 100644 --- a/cassandra/reactive/src/test/java/example/springdata/cassandra/people/RxJava2PersonRepositoryIntegrationTest.java +++ b/cassandra/reactive/src/test/java/example/springdata/cassandra/people/RxJava2PersonRepositoryIntegrationTest.java @@ -20,14 +20,12 @@ import io.reactivex.Completable; import io.reactivex.Flowable; import io.reactivex.Single; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.cassandra.core.ReactiveCassandraOperations; -import org.springframework.test.context.junit4.SpringRunner; /** * Integration test for {@link RxJava2PersonRepository} using RxJava1 types. Note that @@ -36,16 +34,15 @@ import org.springframework.test.context.junit4.SpringRunner; * * @author Mark Paluch */ -@RunWith(SpringRunner.class) +@CassandraKeyspace @SpringBootTest public class RxJava2PersonRepositoryIntegrationTest { - @ClassRule public final static CassandraKeyspace CASSANDRA_KEYSPACE = CassandraKeyspace.onLocalhost(); @Autowired RxJava2PersonRepository repository; @Autowired ReactiveCassandraOperations operations; - @Before + @BeforeEach public void setUp() throws Exception { Completable deleteAll = repository.deleteAll(); diff --git a/cassandra/reactive/src/test/java/example/springdata/cassandra/spel/ExpressionIntegrationTests.java b/cassandra/reactive/src/test/java/example/springdata/cassandra/spel/ExpressionIntegrationTests.java index a0dd7ec4..69f4a2f5 100644 --- a/cassandra/reactive/src/test/java/example/springdata/cassandra/spel/ExpressionIntegrationTests.java +++ b/cassandra/reactive/src/test/java/example/springdata/cassandra/spel/ExpressionIntegrationTests.java @@ -24,30 +24,25 @@ import reactor.util.context.Context; import java.util.Arrays; -import org.junit.Before; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.data.cassandra.DataCassandraTest; -import org.springframework.test.context.junit4.SpringRunner; /** * Integration tests showing the SpEL context extension in action. * * @author Mark Paluch */ -@RunWith(SpringRunner.class) +@CassandraKeyspace @DataCassandraTest -public class ExpressionIntegrationTests { - - @ClassRule public final static CassandraKeyspace CASSANDRA_KEYSPACE = CassandraKeyspace.onLocalhost(); +class ExpressionIntegrationTests { @Autowired EmployeeRepository employeeRepository; - @Before - public void before() { + @BeforeEach + void before() { employeeRepository.deleteAll().as(StepVerifier::create).verifyComplete(); @@ -60,7 +55,7 @@ public class ExpressionIntegrationTests { } @Test - public void shouldFindByTenantIdAndName() { + void shouldFindByTenantIdAndName() { employeeRepository.findAllByName("Walter") // .contextWrite(Context.of(Tenant.class, new Tenant("breaking-bad"))).as(StepVerifier::create) // diff --git a/cassandra/util/pom.xml b/cassandra/util/pom.xml index 5869a8fd..296b9514 100644 --- a/cassandra/util/pom.xml +++ b/cassandra/util/pom.xml @@ -16,8 +16,8 @@ - junit - junit + org.junit.jupiter + junit-jupiter-api diff --git a/cassandra/util/src/main/java/example/springdata/cassandra/util/Cassandra.java b/cassandra/util/src/main/java/example/springdata/cassandra/util/Cassandra.java deleted file mode 100644 index 5f690472..00000000 --- a/cassandra/util/src/main/java/example/springdata/cassandra/util/Cassandra.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2017-2018 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 - * - * https://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 example.springdata.cassandra.util; - -import java.util.concurrent.TimeUnit; - -import org.cassandraunit.utils.EmbeddedCassandraServerHelper; -import org.junit.AssumptionViolatedException; - -/** - * {@link org.junit.rules.TestRule} for Cassandra server use. This rule can start a Cassandra instance, reuse a running - * instance or simply require a running Cassandra server (will skip the test if Cassandra is not running). - * - * @author Mark Paluch - */ -public class Cassandra extends CassandraResource { - - private final RuntimeMode runtimeMode; - - private Cassandra(String host, int port, RuntimeMode runtimeMode) { - - super(host, port); - this.runtimeMode = runtimeMode; - } - - /** - * Require a running instance on {@code host:port}. Fails with {@link AssumptionViolatedException} if Cassandra is not - * running. - * - * @param host must not be {@literal null} or empty. - * @param port must be between 0 and 65535. - * @return the {@link Cassandra} rule - */ - public static Cassandra requireRunningInstance(String host, int port) { - return new Cassandra(host, port, RuntimeMode.REQUIRE_RUNNING_INSTANCE); - } - - /** - * Start an embedded Cassandra instance on {@code host:port} if Cassandra is not running already. - * - * @param host must not be {@literal null} or empty. - * @param port must be between 0 and 65535. - * @return the {@link Cassandra} rule - */ - public static Cassandra embeddedIfNotRunning(String host, int port) { - return new Cassandra(host, port, RuntimeMode.EMBEDDED_IF_NOT_RUNNING); - } - - @Override - protected void before() throws Throwable { - - if (runtimeMode == RuntimeMode.REQUIRE_RUNNING_INSTANCE) { - if (!CassandraSocket.isConnectable(getHost(), getPort())) { - throw new AssumptionViolatedException( - String.format("Cassandra is not reachable at %s:%s.", getHost(), getPort())); - } - } - - if (runtimeMode == RuntimeMode.EMBEDDED_IF_NOT_RUNNING) { - if (CassandraSocket.isConnectable(getHost(), getPort())) { - return; - } - } - - EmbeddedCassandraServerHelper.startEmbeddedCassandra("embedded-cassandra.yaml", "target/embeddedCassandra", - TimeUnit.SECONDS.toMillis(60)); - super.before(); - } - - private enum RuntimeMode { - REQUIRE_RUNNING_INSTANCE, EMBEDDED_IF_NOT_RUNNING; - } -} diff --git a/cassandra/util/src/main/java/example/springdata/cassandra/util/CassandraExtension.java b/cassandra/util/src/main/java/example/springdata/cassandra/util/CassandraExtension.java new file mode 100644 index 00000000..1f018d1d --- /dev/null +++ b/cassandra/util/src/main/java/example/springdata/cassandra/util/CassandraExtension.java @@ -0,0 +1,68 @@ +/* + * Copyright 2021 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 example.springdata.cassandra.util; + +import java.net.InetSocketAddress; +import java.util.Optional; + +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.platform.commons.util.AnnotationUtils; + +import com.datastax.oss.driver.api.core.CqlSession; + +/** + * JUnit 5 {@link BeforeAllCallback} extension to ensure a running Cassandra server. + * + * @author Mark Paluch + * @see CassandraKeyspace + */ +class CassandraExtension implements BeforeAllCallback { + + private static final ExtensionContext.Namespace NAMESPACE = ExtensionContext.Namespace + .create(CassandraExtension.class); + + @Override + public void beforeAll(ExtensionContext context) throws Exception { + + ExtensionContext.Store store = context.getStore(NAMESPACE); + CassandraKeyspace cassandra = findAnnotation(context); + + CassandraServer keyspace = store.getOrComputeIfAbsent(CassandraServer.class, it -> { + return CassandraServer.embeddedIfNotRunning("localhost", 9042); + }, CassandraServer.class); + + keyspace.before(); + + CqlSession session = store.getOrComputeIfAbsent(CqlSession.class, it -> { + + return CqlSession.builder().addContactPoint(new InetSocketAddress("localhost", 9042)) + .withLocalDatacenter("datacenter1").build(); + }, CqlSession.class); + + session.execute(String.format("CREATE KEYSPACE IF NOT EXISTS %s \n" + + "WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };", cassandra.keyspace())); + } + + private static CassandraKeyspace findAnnotation(ExtensionContext context) { + + Class testClass = context.getRequiredTestClass(); + + Optional annotation = AnnotationUtils.findAnnotation(testClass, CassandraKeyspace.class); + + return annotation.orElseThrow(() -> new IllegalStateException("Test class not annotated with @Cassandra")); + } +} diff --git a/cassandra/util/src/main/java/example/springdata/cassandra/util/CassandraKeyspace.java b/cassandra/util/src/main/java/example/springdata/cassandra/util/CassandraKeyspace.java index 5d9289e4..f0cc11be 100644 --- a/cassandra/util/src/main/java/example/springdata/cassandra/util/CassandraKeyspace.java +++ b/cassandra/util/src/main/java/example/springdata/cassandra/util/CassandraKeyspace.java @@ -1,11 +1,11 @@ /* - * Copyright 2016-2018 the original author or authors. + * Copyright 2021 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 * - * https://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, @@ -15,111 +15,29 @@ */ package example.springdata.cassandra.util; -import java.net.InetSocketAddress; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; -import org.junit.AssumptionViolatedException; - -import org.springframework.data.util.Version; -import org.springframework.util.Assert; - -import com.datastax.oss.driver.api.core.CqlSession; +import org.junit.jupiter.api.extension.ExtendWith; /** - * {@link CassandraResource} to require (create or reuse) an Apache Cassandra keyspace and optionally require a specific - * Apache Cassandra version. This {@link org.junit.rules.TestRule} can be chained to depend on another - * {@link CassandraResource} rule to require a running instance/start an embedded Apache Cassandra instance. + * Annotation that can activates embedded Cassandra providing a keyspace at {@link #keyspace()} * * @author Mark Paluch */ -public class CassandraKeyspace extends CassandraResource { - - private final String keyspaceName; - private final Version requiredVersion; - private final CassandraResource dependency; - - private CassandraKeyspace(String host, int port, String keyspaceName, CassandraResource dependency, - Version requiredVersion) { - - super(host, port); - - this.keyspaceName = keyspaceName; - this.dependency = dependency; - this.requiredVersion = requiredVersion; - } +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@ExtendWith(CassandraExtension.class) +public @interface CassandraKeyspace { /** - * Create a {@link CassandraKeyspace} test rule to provide a running Cassandra instance on {@code localhost:9042} with - * a keyspace {@code example}. Reuses a running Cassandra instance if available or starts an embedded instance. + * Name of the desired keyspace to be provided. * - * @return the {@link CassandraKeyspace} rule. + * @return */ - public static CassandraKeyspace onLocalhost() { - return new CassandraKeyspace("localhost", 9042, "example", Cassandra.embeddedIfNotRunning("localhost", 9042), - new Version(0, 0, 0)); - } - - /** - * Setup a dependency to an upstream {@link CassandraResource}. The dependency is activated by {@code this} test rule. - * - * @param cassandraResource must not be {@literal null}. - * @return the {@link CassandraKeyspace} rule. - */ - public CassandraKeyspace dependsOn(CassandraResource cassandraResource) { - - Assert.notNull(cassandraResource, "CassandraResource must not be null!"); - - return new CassandraKeyspace(getHost(), getPort(), keyspaceName, cassandraResource, requiredVersion); - } - - /** - * Setup a version requirement. - * - * @param requiredVersion must not be {@literal null}. - * @return the {@link CassandraKeyspace} rule - */ - public CassandraKeyspace atLeast(Version requiredVersion) { - - Assert.notNull(requiredVersion, "Required version must not be null!"); - - return new CassandraKeyspace(getHost(), getPort(), keyspaceName, dependency, requiredVersion); - } - - /* - * (non-Javadoc) - * @see org.junit.rules.ExternalResource#before() - */ - @Override - protected void before() throws Throwable { - - dependency.before(); - - try (CqlSession session = CqlSession.builder().addContactPoint(new InetSocketAddress(getHost(), getPort())) - .withLocalDatacenter("datacenter1").build()) { - - if (requiredVersion != null) { - - Version cassandraReleaseVersion = CassandraVersion.getReleaseVersion(session); - - if (cassandraReleaseVersion.isLessThan(requiredVersion)) { - throw new AssumptionViolatedException( - String.format("Cassandra at %s:%s runs in Version %s but we require at least %s", getHost(), getPort(), - cassandraReleaseVersion, requiredVersion)); - } - } - - session.execute(String.format("CREATE KEYSPACE IF NOT EXISTS %s \n" - + "WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };", keyspaceName)); - } - } - - /* - * (non-Javadoc) - * @see org.junit.rules.ExternalResource#after() - */ - @Override - protected void after() { - - super.after(); - dependency.after(); - } + String keyspace() default "example"; } diff --git a/cassandra/util/src/main/java/example/springdata/cassandra/util/CassandraResource.java b/cassandra/util/src/main/java/example/springdata/cassandra/util/CassandraResource.java deleted file mode 100644 index 444e0b84..00000000 --- a/cassandra/util/src/main/java/example/springdata/cassandra/util/CassandraResource.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2017-2018 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 - * - * https://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 example.springdata.cassandra.util; - -import org.junit.rules.ExternalResource; -import org.springframework.util.Assert; - -/** - * Base class to abstract contact point details for Apache Cassandra as {@link ExternalResource}. - * - * @author Mark Paluch - */ -public abstract class CassandraResource extends ExternalResource { - - private final String host; - private final int port; - - CassandraResource(String host, int port) { - - Assert.hasText(host, "Host must not be null or empty!"); - Assert.isTrue(port >= 0 && port <= 65535, "Port must be in the range of 0..65535!"); - - this.host = host; - this.port = port; - } - - /** - * @return the Cassandra hostname. - */ - public String getHost() { - return host; - } - - /** - * @return the Cassandra port. - */ - public int getPort() { - return port; - } - - /* - * (non-Javadoc) - * @see org.junit.rules.ExternalResource#before() - */ - @Override - protected void before() throws Throwable { - super.before(); - } - - /* - * (non-Javadoc) - * @see org.junit.rules.ExternalResource#after() - */ - @Override - protected void after() { - super.after(); - } -} diff --git a/cassandra/util/src/main/java/example/springdata/cassandra/util/CassandraServer.java b/cassandra/util/src/main/java/example/springdata/cassandra/util/CassandraServer.java new file mode 100644 index 00000000..8500110d --- /dev/null +++ b/cassandra/util/src/main/java/example/springdata/cassandra/util/CassandraServer.java @@ -0,0 +1,118 @@ +/* + * Copyright 2017-2018 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 + * + * https://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 example.springdata.cassandra.util; + +import java.net.InetSocketAddress; +import java.net.Socket; +import java.util.concurrent.TimeUnit; + +import org.cassandraunit.utils.EmbeddedCassandraServerHelper; +import org.junit.jupiter.api.Assumptions; + +import org.springframework.util.Assert; + +/** + * Utility for Cassandra server use. This utility can start a Cassandra instance, reuse a running instance or simply + * require a running Cassandra server (will skip the test if Cassandra is not running). + * + * @author Mark Paluch + */ +class CassandraServer { + + private final String host; + private final int port; + private final RuntimeMode runtimeMode; + + private CassandraServer(String host, int port, RuntimeMode runtimeMode) { + + this.host = host; + this.port = port; + this.runtimeMode = runtimeMode; + } + + /** + * Require a running instance on {@code host:port}. Fails with {@link AssumptionViolatedException} if Cassandra is not + * running. + * + * @param host must not be {@literal null} or empty. + * @param port must be between 0 and 65535. + * @return the {@link CassandraServer} rule + */ + public static CassandraServer requireRunningInstance(String host, int port) { + return new CassandraServer(host, port, RuntimeMode.REQUIRE_RUNNING_INSTANCE); + } + + /** + * Start an embedded Cassandra instance on {@code host:port} if Cassandra is not running already. + * + * @param host must not be {@literal null} or empty. + * @param port must be between 0 and 65535. + * @return the {@link CassandraServer} rule + */ + public static CassandraServer embeddedIfNotRunning(String host, int port) { + return new CassandraServer(host, port, RuntimeMode.EMBEDDED_IF_NOT_RUNNING); + } + + /** + * @param host must not be {@literal null} or empty. + * @param port + * @return {@literal true} if the TCP port accepts a connection. + */ + public static boolean isConnectable(String host, int port) { + + Assert.hasText(host, "Host must not be null or empty!"); + + try (Socket socket = new Socket()) { + + socket.setSoLinger(true, 0); + socket.connect(new InetSocketAddress(host, port), (int) TimeUnit.MILLISECONDS.convert(10, TimeUnit.SECONDS)); + + return true; + + } catch (Exception e) { + return false; + } + } + + public String getHost() { + return host; + } + + public int getPort() { + return port; + } + + protected void before() throws Exception { + + if (runtimeMode == RuntimeMode.REQUIRE_RUNNING_INSTANCE) { + Assumptions.assumeTrue(isConnectable(getHost(), getPort()), + () -> String.format("Cassandra is not reachable at %s:%s.", getHost(), getPort())); + } + + if (runtimeMode == RuntimeMode.EMBEDDED_IF_NOT_RUNNING) { + if (isConnectable(getHost(), getPort())) { + return; + } + } + + EmbeddedCassandraServerHelper.startEmbeddedCassandra("embedded-cassandra.yaml", "target/embeddedCassandra", + TimeUnit.SECONDS.toMillis(60)); + } + + private enum RuntimeMode { + REQUIRE_RUNNING_INSTANCE, EMBEDDED_IF_NOT_RUNNING; + } +} diff --git a/cassandra/util/src/main/java/example/springdata/cassandra/util/CassandraSocket.java b/cassandra/util/src/main/java/example/springdata/cassandra/util/CassandraSocket.java deleted file mode 100644 index 1df0bd9d..00000000 --- a/cassandra/util/src/main/java/example/springdata/cassandra/util/CassandraSocket.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2017-2018 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 - * - * https://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 example.springdata.cassandra.util; - -import lombok.experimental.UtilityClass; - -import java.net.InetSocketAddress; -import java.net.Socket; -import java.util.concurrent.TimeUnit; - -import org.springframework.util.Assert; - -/** - * @author Mark Paluch - */ -@UtilityClass -class CassandraSocket { - - /** - * @param host must not be {@literal null} or empty. - * @param port - * @return {@literal true} if the TCP port accepts a connection. - */ - public static boolean isConnectable(String host, int port) { - - Assert.hasText(host, "Host must not be null or empty!"); - - try (Socket socket = new Socket()) { - - socket.setSoLinger(true, 0); - socket.connect(new InetSocketAddress(host, port), (int) TimeUnit.MILLISECONDS.convert(10, TimeUnit.SECONDS)); - - return true; - - } catch (Exception e) { - return false; - } - } -} diff --git a/cassandra/util/src/main/resources/application.conf b/cassandra/util/src/main/resources/application.conf new file mode 100644 index 00000000..672734b8 --- /dev/null +++ b/cassandra/util/src/main/resources/application.conf @@ -0,0 +1,234 @@ +# Configuration for the DataStax Java driver for Apache Cassandra®. +# +# Unless you use a custom mechanism to load your configuration (see +# SessionBuilder.withConfigLoader), all the values declared here will be used as defaults. You can +# place your own `application.conf` in the classpath to override them. +# +# Options are classified into two categories: +# - basic: what is most likely to be customized first when kickstarting a new application. +# - advanced: more elaborate tuning options, or "expert"-level customizations. +# +# This file is in HOCON format, see https://github.com/typesafehub/config/blob/master/HOCON.md. +datastax-java-driver { + + basic.load-balancing-policy { + class = DcInferringLoadBalancingPolicy + } + + basic.request { + # How long the driver waits for a request to complete. This is a global limit on the duration of + # a session.execute() call, including any internal retries the driver might do. + # + # By default, this value is set pretty high to ensure that DDL queries don't time out, in order + # to provide the best experience for new users trying the driver with the out-of-the-box + # configuration. + # For any serious deployment, we recommend that you use separate configuration profiles for DDL + # and DML; you can then set the DML timeout much lower (down to a few milliseconds if needed). + # + # Note that, because timeouts are scheduled on the driver's timer thread, the duration specified + # here must be greater than the timer tick duration defined by the + # advanced.netty.timer.tick-duration setting (see below). If that is not the case, timeouts will + # not be triggered as timely as desired. + # + # Required: yes + # Modifiable at runtime: yes, the new value will be used for requests issued after the change. + # Overridable in a profile: yes + timeout = 8 seconds + } + + # ADVANCED OPTIONS ------------------------------------------------------------------------------- + + advanced.connection { + # The timeout to use for internal queries that run as part of the initialization process, just + # after we open a connection. If this timeout fires, the initialization of the connection will + # fail. If this is the first connection ever, the driver will fail to initialize as well, + # otherwise it will retry the connection later. + # + # Required: yes + # Modifiable at runtime: yes, the new value will be used for connections created after the + # change. + # Overridable in a profile: no + init-query-timeout = 500 milliseconds + + # The driver maintains a connection pool to each node, according to the distance assigned to it + # by the load balancing policy. If the distance is IGNORED, no connections are maintained. + pool { + local { + # The number of connections in the pool. + # + # Required: yes + # Modifiable at runtime: yes; when the change is detected, all active pools will be notified + # and will adjust their size. + # Overridable in a profile: no + size = 1 + } + remote { + size = 1 + } + } + } + advanced.metrics { + # The session-level metrics (all disabled by default). + # + # Required: yes + # Modifiable at runtime: no + # Overridable in a profile: no + session { + enabled = [] + + } + # The node-level metrics (all disabled by default). + # + # Required: yes + # Modifiable at runtime: no + # Overridable in a profile: no + node { + enabled = [] + } + } + + advanced.control-connection { + schema-agreement { + # The interval between each attempt. + # Required: yes + # Modifiable at runtime: yes, the new value will be used for checks issued after the change. + # Overridable in a profile: no + interval = 100 seconds + + # The timeout after which schema agreement fails. + # If this is set to 0, schema agreement is skipped and will always fail. + # + # Required: yes + # Modifiable at runtime: yes, the new value will be used for checks issued after the change. + # Overridable in a profile: no + timeout = 100 seconds + + # Whether to log a warning if schema agreement fails. + # You might want to change this if you've set the timeout to 0. + # + # Required: yes + # Modifiable at runtime: yes, the new value will be used for checks issued after the change. + # Overridable in a profile: no + warn-on-failure = true + } + } + + # Options related to the Netty event loop groups used internally by the driver. + advanced.netty { + + # Whether the threads created by the driver should be daemon threads. + # This will apply to the threads in io-group, admin-group, and the timer thread. + # + # Required: yes + # Modifiable at runtime: no + # Overridable in a profile: no + daemon = false + + # The event loop group used for I/O operations (reading and writing to Cassandra nodes). + # By default, threads in this group are named after the session name, "-io-" and an incrementing + # counter, for example "s0-io-0". + io-group { + # The number of threads. + # If this is set to 0, the driver will use `Runtime.getRuntime().availableProcessors() * 2`. + # + # Required: yes + # Modifiable at runtime: no + # Overridable in a profile: no + size = 4 + + # The options to shut down the event loop group gracefully when the driver closes. If a task + # gets submitted during the quiet period, it is accepted and the quiet period starts over. + # The timeout limits the overall shutdown time. + # + # Required: yes + # Modifiable at runtime: no + # Overridable in a profile: no + shutdown {quiet-period = 0, timeout = 0, unit = SECONDS} + } + # The event loop group used for admin tasks not related to request I/O (handle cluster events, + # refresh metadata, schedule reconnections, etc.) + # By default, threads in this group are named after the session name, "-admin-" and an + # incrementing counter, for example "s0-admin-0". + admin-group { + size = 2 + + shutdown {quiet-period = 0, timeout = 0, unit = SECONDS} + } + } + + advanced.metadata { + # Topology events are external signals that inform the driver of the state of Cassandra nodes + # (by default, they correspond to gossip events received on the control connection). + # The debouncer helps smoothen out oscillations if conflicting events are sent out in short + # bursts. + # Debouncing may be disabled by setting the window to 0 or max-events to 1 (this is not + # recommended). + topology-event-debouncer { + # How long the driver waits to propagate an event. If another event is received within that + # time, the window is reset and a batch of accumulated events will be delivered. + # + # Required: yes + # Modifiable at runtime: no + # Overridable in a profile: no + window = 0 second + + # The maximum number of events that can accumulate. If this count is reached, the events are + # delivered immediately and the time window is reset. This avoids holding events indefinitely + # if the window keeps getting reset. + # + # Required: yes + # Modifiable at runtime: no + # Overridable in a profile: no + max-events = 20 + } + + # Options relating to schema metadata (Cluster.getMetadata.getKeyspaces). + # This metadata is exposed by the driver for informational purposes, and is also necessary for + # token-aware routing. + schema { + # Whether schema metadata is enabled. + # If this is false, the schema will remain empty, or to the last known value. + # + # Required: yes + # Modifiable at runtime: yes, the new value will be used for refreshes issued after the + # change. It can also be overridden programmatically via Cluster.setSchemaMetadataEnabled. + # Overridable in a profile: no + enabled = true + + # Protects against bursts of schema updates (for example when a client issues a sequence of + # DDL queries), by coalescing them into a single update. + # Debouncing may be disabled by setting the window to 0 or max-events to 1 (this is highly + # discouraged for schema refreshes). + debouncer { + # How long the driver waits to apply a refresh. If another refresh is requested within that + # time, the window is reset and a single refresh will be triggered when it ends. + # + # Required: yes + # Modifiable at runtime: no + # Overridable in a profile: no + window = 0 second + + # The maximum number of refreshes that can accumulate. If this count is reached, a refresh + # is done immediately and the window is reset. + # + # Required: yes + # Modifiable at runtime: no + # Overridable in a profile: no + max-events = 20 + } + } + + # Whether token metadata (Cluster.getMetadata.getTokenMap) is enabled. + # This metadata is exposed by the driver for informational purposes, and is also necessary for + # token-aware routing. + # If this is false, it will remain empty, or to the last known value. Note that its computation + # requires information about the schema; therefore if schema metadata is disabled or filtered to + # a subset of keyspaces, the token map will be incomplete, regardless of the value of this + # property. + # + # Required: yes + # Modifiable at runtime: yes, the new value will be used for refreshes issued after the change. + # Overridable in a profile: no + token-map.enabled = true + } +}