diff --git a/ci/smoke-tests.yml b/ci/smoke-tests.yml index 32d1d6ee..f548be6d 100644 --- a/ci/smoke-tests.yml +++ b/ci/smoke-tests.yml @@ -21,6 +21,7 @@ smoke_tests: - conditional - configuration-properties - data-cassandra + - data-cassandra-reactive - data-jdbc-h2 - data-jdbc-postgresql - data-jpa diff --git a/data-cassandra-reactive/README.adoc b/data-cassandra-reactive/README.adoc new file mode 100644 index 00000000..2727d01c --- /dev/null +++ b/data-cassandra-reactive/README.adoc @@ -0,0 +1 @@ +Tests if Spring Data Cassandra Reactive works diff --git a/data-cassandra-reactive/build.gradle b/data-cassandra-reactive/build.gradle new file mode 100644 index 00000000..2391eb81 --- /dev/null +++ b/data-cassandra-reactive/build.gradle @@ -0,0 +1,16 @@ +plugins { + id 'java' + id 'org.springframework.boot' + id 'org.springframework.aot.smoke-test' + id 'org.graalvm.buildtools.native' +} + +dependencies { + implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)) + implementation("org.springframework.boot:spring-boot-starter-data-cassandra-reactive") + + testImplementation("org.springframework.boot:spring-boot-starter-test") + + aotTestImplementation(project(":aot-smoke-test-support")) + aotTestImplementation("org.awaitility:awaitility:4.2.0") +} diff --git a/data-cassandra-reactive/docker-compose.yml b/data-cassandra-reactive/docker-compose.yml new file mode 100644 index 00000000..f596a805 --- /dev/null +++ b/data-cassandra-reactive/docker-compose.yml @@ -0,0 +1,6 @@ +version: '3.1' +services: + cassandra: + image: 'cassandra:4' + ports: + - '9042' diff --git a/data-cassandra-reactive/src/aotTest/java/com/example/data/cassandra/reactive/DataCassandraReactiveApplicationAotTests.java b/data-cassandra-reactive/src/aotTest/java/com/example/data/cassandra/reactive/DataCassandraReactiveApplicationAotTests.java new file mode 100644 index 00000000..73a3c884 --- /dev/null +++ b/data-cassandra-reactive/src/aotTest/java/com/example/data/cassandra/reactive/DataCassandraReactiveApplicationAotTests.java @@ -0,0 +1,33 @@ +package com.example.data.cassandra.reactive; + +import java.time.Duration; + +import org.awaitility.Awaitility; +import org.junit.jupiter.api.Test; + +import org.springframework.aot.smoketest.support.assertj.AssertableOutput; +import org.springframework.aot.smoketest.support.junit.AotSmokeTest; + +import static org.assertj.core.api.Assertions.assertThat; + +@AotSmokeTest +class DataCassandraReactiveApplicationAotTests { + + @Test + void findAll(AssertableOutput output) { + Awaitility.await().atMost(Duration.ofSeconds(10)).untilAsserted(() -> { + assertThat(output).hasSingleLineContaining("findAll(): Person{firstname='first-1', lastname='last-1'}") + .hasSingleLineContaining("findAll(): Person{firstname='first-2', lastname='last-2'}") + .hasSingleLineContaining("findAll(): Person{firstname='first-3', lastname='last-3'}"); + }); + } + + @Test + void findByLastName(AssertableOutput output) { + Awaitility.await().atMost(Duration.ofSeconds(10)).untilAsserted(() -> { + assertThat(output) + .hasSingleLineContaining("findByLastname(): Person{firstname='first-3', lastname='last-3'}"); + }); + } + +} diff --git a/data-cassandra-reactive/src/main/java/com/example/data/cassandra/reactive/CLR.java b/data-cassandra-reactive/src/main/java/com/example/data/cassandra/reactive/CLR.java new file mode 100644 index 00000000..3e12840e --- /dev/null +++ b/data-cassandra-reactive/src/main/java/com/example/data/cassandra/reactive/CLR.java @@ -0,0 +1,33 @@ +package com.example.data.cassandra.reactive; + +import java.util.UUID; + +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +@Component +class CLR implements CommandLineRunner { + + private final PersonRepository personRepository; + + CLR(PersonRepository personRepository) { + this.personRepository = personRepository; + } + + @Override + public void run(String... args) { + this.personRepository.save(new Person(UUID.randomUUID().toString(), "first-1", "last-1")) + .then(this.personRepository.save(new Person(UUID.randomUUID().toString(), "first-2", "last-2"))) + .then(this.personRepository.save(new Person(UUID.randomUUID().toString(), "first-3", "last-3"))) + .block(); + + this.personRepository.findAll().subscribe((person) -> { + System.out.printf("findAll(): %s%n", person); + }, (ex) -> ex.printStackTrace(System.out)); + + this.personRepository.findByLastname("last-3").subscribe((person) -> { + System.out.printf("findByLastname(): %s%n", person); + }, (ex) -> ex.printStackTrace(System.out)); + } + +} diff --git a/data-cassandra-reactive/src/main/java/com/example/data/cassandra/reactive/CassandraConfiguration.java b/data-cassandra-reactive/src/main/java/com/example/data/cassandra/reactive/CassandraConfiguration.java new file mode 100644 index 00000000..ae633198 --- /dev/null +++ b/data-cassandra-reactive/src/main/java/com/example/data/cassandra/reactive/CassandraConfiguration.java @@ -0,0 +1,25 @@ +package com.example.data.cassandra.reactive; + +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.CqlSessionBuilder; + +import org.springframework.boot.autoconfigure.cassandra.CassandraProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.cassandra.core.cql.generator.CreateKeyspaceCqlGenerator; +import org.springframework.data.cassandra.core.cql.keyspace.CreateKeyspaceSpecification; + +@Configuration +class CassandraConfiguration { + + @Bean + CqlSession cqlSession(CqlSessionBuilder cqlSessionBuilder, CassandraProperties properties) { + // This creates the keyspace on startup + try (CqlSession session = cqlSessionBuilder.build()) { + session.execute(CreateKeyspaceCqlGenerator + .toCql(CreateKeyspaceSpecification.createKeyspace(properties.getKeyspaceName()).ifNotExists())); + } + return cqlSessionBuilder.build(); + } + +} diff --git a/data-cassandra-reactive/src/main/java/com/example/data/cassandra/reactive/DataCassandraReactiveApplication.java b/data-cassandra-reactive/src/main/java/com/example/data/cassandra/reactive/DataCassandraReactiveApplication.java new file mode 100644 index 00000000..edfb26e5 --- /dev/null +++ b/data-cassandra-reactive/src/main/java/com/example/data/cassandra/reactive/DataCassandraReactiveApplication.java @@ -0,0 +1,14 @@ +package com.example.data.cassandra.reactive; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class DataCassandraReactiveApplication { + + public static void main(String[] args) throws InterruptedException { + SpringApplication.run(DataCassandraReactiveApplication.class, args); + Thread.currentThread().join(); // To be able to measure memory consumption + } + +} diff --git a/data-cassandra-reactive/src/main/java/com/example/data/cassandra/reactive/Person.java b/data-cassandra-reactive/src/main/java/com/example/data/cassandra/reactive/Person.java new file mode 100644 index 00000000..b3d079f4 --- /dev/null +++ b/data-cassandra-reactive/src/main/java/com/example/data/cassandra/reactive/Person.java @@ -0,0 +1,59 @@ +package com.example.data.cassandra.reactive; + +import org.springframework.data.cassandra.core.mapping.Column; +import org.springframework.data.cassandra.core.mapping.Indexed; +import org.springframework.data.cassandra.core.mapping.PrimaryKey; +import org.springframework.data.cassandra.core.mapping.Table; + +@Table +public class Person { + + @PrimaryKey + private String id; + + @Column + private String firstname; + + @Column + @Indexed + private String lastname; + + public Person() { + } + + public Person(String id, String firstname, String lastname) { + this.id = id; + this.firstname = firstname; + this.lastname = lastname; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getFirstname() { + return firstname; + } + + public void setFirstname(String firstname) { + this.firstname = firstname; + } + + public String getLastname() { + return lastname; + } + + public void setLastname(String lastname) { + this.lastname = lastname; + } + + @Override + public String toString() { + return "Person{" + "firstname='" + firstname + '\'' + ", lastname='" + lastname + '\'' + '}'; + } + +} diff --git a/data-cassandra-reactive/src/main/java/com/example/data/cassandra/reactive/PersonRepository.java b/data-cassandra-reactive/src/main/java/com/example/data/cassandra/reactive/PersonRepository.java new file mode 100644 index 00000000..8bb41986 --- /dev/null +++ b/data-cassandra-reactive/src/main/java/com/example/data/cassandra/reactive/PersonRepository.java @@ -0,0 +1,26 @@ +/* + * Copyright 2020 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 com.example.data.cassandra.reactive; + +import reactor.core.publisher.Flux; + +import org.springframework.data.repository.reactive.ReactiveCrudRepository; + +public interface PersonRepository extends ReactiveCrudRepository { + + Flux findByLastname(String lastname); + +} diff --git a/data-cassandra-reactive/src/main/resources/application.properties b/data-cassandra-reactive/src/main/resources/application.properties new file mode 100644 index 00000000..04fee7eb --- /dev/null +++ b/data-cassandra-reactive/src/main/resources/application.properties @@ -0,0 +1,4 @@ +spring.cassandra.contact-points=${CASSANDRA_HOST:127.0.0.1}:${CASSANDRA_PORT_9042:9042} +spring.cassandra.local-datacenter=datacenter1 +spring.cassandra.keyspace-name=example +spring.cassandra.schema-action=recreate diff --git a/data-cassandra-reactive/src/test/java/com/example/data/cassandra/reactive/DataCassandraReactiveApplicationTests.java b/data-cassandra-reactive/src/test/java/com/example/data/cassandra/reactive/DataCassandraReactiveApplicationTests.java new file mode 100644 index 00000000..4ece053d --- /dev/null +++ b/data-cassandra-reactive/src/test/java/com/example/data/cassandra/reactive/DataCassandraReactiveApplicationTests.java @@ -0,0 +1,14 @@ +package com.example.data.cassandra.reactive; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class DataCassandraReactiveApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/settings.gradle b/settings.gradle index d78f7bdd..9e7e7df9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -49,6 +49,7 @@ include "command-line-runner" include "conditional" include "configuration-properties" include "data-cassandra" +include "data-cassandra-reactive" include "data-jdbc-h2" include "data-jdbc-postgresql" include "data-jpa"