diff --git a/persistence-modules/pom.xml b/persistence-modules/pom.xml index 92af416b94..86e496e3f8 100644 --- a/persistence-modules/pom.xml +++ b/persistence-modules/pom.xml @@ -58,6 +58,7 @@ spring-boot-persistence-h2 spring-boot-persistence-mongodb spring-data-cassandra + spring-data-cassandra-test spring-data-cassandra-reactive spring-data-cosmosdb spring-data-couchbase-2 diff --git a/persistence-modules/spring-data-cassandra-test/README.md b/persistence-modules/spring-data-cassandra-test/README.md new file mode 100644 index 0000000000..cfad972cb3 --- /dev/null +++ b/persistence-modules/spring-data-cassandra-test/README.md @@ -0,0 +1,16 @@ +## Spring @DataCassandraTest + +### Build the Project +``` +mvn clean install +``` + +### Prerequisite To Run Test +- Docker Engine must be running on the system +- Docker Compose must be installed + +### Run Tests Directly +``` +mvn test +``` + diff --git a/persistence-modules/spring-data-cassandra-test/pom.xml b/persistence-modules/spring-data-cassandra-test/pom.xml new file mode 100644 index 0000000000..f2cbc834de --- /dev/null +++ b/persistence-modules/spring-data-cassandra-test/pom.xml @@ -0,0 +1,77 @@ + + + 4.0.0 + spring-data-cassandra-test + spring-data-cassandra-test + jar + + + com.baeldung + parent-boot-2 + 0.0.1-SNAPSHOT + ../../parent-boot-2 + + + + 2.5.3 + 1.18.18 + 4.13.0 + 4.3.1.0 + 1.15.3 + 1.5.0 + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-data-cassandra + ${spring-boot-starter-data-cassandra.version} + + + + com.datastax.oss + java-driver-core + ${java-driver-core.version} + + + + org.projectlombok + lombok + ${lombok.version} + + + + com.datastax.oss + native-protocol + ${native-protocol.version} + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.testcontainers + testcontainers + ${testcontainers.version} + test + + + + org.testcontainers + cassandra + ${testcontainers.version} + test + + + + \ No newline at end of file diff --git a/persistence-modules/spring-data-cassandra-test/src/main/java/com/baeldung/spring/data/cassandra/test/CassandraDataTestApplication.java b/persistence-modules/spring-data-cassandra-test/src/main/java/com/baeldung/spring/data/cassandra/test/CassandraDataTestApplication.java new file mode 100644 index 0000000000..f0e6ba3c88 --- /dev/null +++ b/persistence-modules/spring-data-cassandra-test/src/main/java/com/baeldung/spring/data/cassandra/test/CassandraDataTestApplication.java @@ -0,0 +1,11 @@ +package com.baeldung.spring.data.cassandra.test; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class CassandraDataTestApplication { + public static void main(String[] args) { + SpringApplication.run(CassandraDataTestApplication.class, args); + } +} diff --git a/persistence-modules/spring-data-cassandra-test/src/main/java/com/baeldung/spring/data/cassandra/test/api/InventoryController.java b/persistence-modules/spring-data-cassandra-test/src/main/java/com/baeldung/spring/data/cassandra/test/api/InventoryController.java new file mode 100644 index 0000000000..6c4dfe055c --- /dev/null +++ b/persistence-modules/spring-data-cassandra-test/src/main/java/com/baeldung/spring/data/cassandra/test/api/InventoryController.java @@ -0,0 +1,43 @@ +package com.baeldung.spring.data.cassandra.test.api; + +import com.baeldung.spring.data.cassandra.test.domain.Vehicle; +import com.baeldung.spring.data.cassandra.test.service.InventoryService; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/v1/api/inventory") +public class InventoryController { + private InventoryService inventoryService; + + public InventoryController(InventoryService inventoryService) { + this.inventoryService = inventoryService; + } + + @GetMapping("/vehicles") + public List getVehicles() { + return this.inventoryService.getVehicles(); + } + + @PostMapping("/vehicles") + public void addVehicles(@RequestBody List vehicles) { + this.inventoryService.addVehicles(vehicles); + } + + @PutMapping("/vehicles") + public void updateVehicles(@RequestBody List vehicles) { + this.inventoryService.updateVehicles(vehicles); + } + + @PutMapping("/vehicles/{vin}") + public void updateVehicles(@PathVariable(name = "vin") String vin, + @RequestBody Vehicle vehicles) { + this.inventoryService.updateVehicle(vin, vehicles); + } + + @DeleteMapping("/vehicles/{vin}") + public void removeVehicle(@PathVariable(name = "vin") String vin) { + this.inventoryService.deleteVehicle(vin); + } +} diff --git a/persistence-modules/spring-data-cassandra-test/src/main/java/com/baeldung/spring/data/cassandra/test/config/CassandraConfig.java b/persistence-modules/spring-data-cassandra-test/src/main/java/com/baeldung/spring/data/cassandra/test/config/CassandraConfig.java new file mode 100644 index 0000000000..d362d67a68 --- /dev/null +++ b/persistence-modules/spring-data-cassandra-test/src/main/java/com/baeldung/spring/data/cassandra/test/config/CassandraConfig.java @@ -0,0 +1,24 @@ +package com.baeldung.spring.data.cassandra.test.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.data.cassandra.config.AbstractCassandraConfiguration; + +@Configuration +public class CassandraConfig extends AbstractCassandraConfiguration { + @Override + protected String getKeyspaceName() { + return "inventory"; + } + + @Override + public String getContactPoints() { + return "localhost"; + } + + @Override + protected String getLocalDataCenter() { + return "datacenter1"; + } + + +} diff --git a/persistence-modules/spring-data-cassandra-test/src/main/java/com/baeldung/spring/data/cassandra/test/domain/Vehicle.java b/persistence-modules/spring-data-cassandra-test/src/main/java/com/baeldung/spring/data/cassandra/test/domain/Vehicle.java new file mode 100644 index 0000000000..aa16440c83 --- /dev/null +++ b/persistence-modules/spring-data-cassandra-test/src/main/java/com/baeldung/spring/data/cassandra/test/domain/Vehicle.java @@ -0,0 +1,17 @@ +package com.baeldung.spring.data.cassandra.test.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; +import org.springframework.data.annotation.Id; +import org.springframework.data.cassandra.core.mapping.Table; + +@Data +@Table("vehicles") +@AllArgsConstructor +public class Vehicle { + @Id + private String vin; + private Integer year; + private String make; + private String model; +} diff --git a/persistence-modules/spring-data-cassandra-test/src/main/java/com/baeldung/spring/data/cassandra/test/repository/InventoryRepository.java b/persistence-modules/spring-data-cassandra-test/src/main/java/com/baeldung/spring/data/cassandra/test/repository/InventoryRepository.java new file mode 100644 index 0000000000..c6fe4a91fe --- /dev/null +++ b/persistence-modules/spring-data-cassandra-test/src/main/java/com/baeldung/spring/data/cassandra/test/repository/InventoryRepository.java @@ -0,0 +1,26 @@ +package com.baeldung.spring.data.cassandra.test.repository; + +import com.baeldung.spring.data.cassandra.test.domain.Vehicle; +import com.datastax.oss.driver.api.core.DefaultConsistencyLevel; +import org.springframework.data.cassandra.repository.Consistency; +import org.springframework.data.cassandra.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface InventoryRepository extends CrudRepository { + + @Query("select * from vehicles") + @Consistency(DefaultConsistencyLevel.LOCAL_QUORUM) + List findAllVehicles(); + + @Consistency(DefaultConsistencyLevel.LOCAL_QUORUM) + Optional findByVin(@Param("vin") String vin); + + @Consistency(DefaultConsistencyLevel.LOCAL_QUORUM) + void deleteByVin(String vin); +} diff --git a/persistence-modules/spring-data-cassandra-test/src/main/java/com/baeldung/spring/data/cassandra/test/service/InventoryService.java b/persistence-modules/spring-data-cassandra-test/src/main/java/com/baeldung/spring/data/cassandra/test/service/InventoryService.java new file mode 100644 index 0000000000..75a198738a --- /dev/null +++ b/persistence-modules/spring-data-cassandra-test/src/main/java/com/baeldung/spring/data/cassandra/test/service/InventoryService.java @@ -0,0 +1,47 @@ +package com.baeldung.spring.data.cassandra.test.service; + +import com.baeldung.spring.data.cassandra.test.domain.Vehicle; +import com.baeldung.spring.data.cassandra.test.repository.InventoryRepository; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class InventoryService { + private final InventoryRepository inventoryRepository; + + public InventoryService(InventoryRepository inventoryRepository) { + this.inventoryRepository = inventoryRepository; + } + + public List getVehicles() { + return this.inventoryRepository.findAllVehicles(); + } + + public Vehicle getVehicle(String vin) { + return this.inventoryRepository.findByVin(vin).orElse(null); + } + + public void addVehicles(List vehicles) { + this.inventoryRepository.saveAll(vehicles); + } + + public void updateVehicles(List vehicles) { + this.inventoryRepository.saveAll(vehicles); + } + + public void updateVehicle(String vin, Vehicle vehicle) { + Vehicle existingVehicle = this.inventoryRepository.findByVin(vin) + .orElseThrow(() -> new RuntimeException("Vehicle not found")); + + existingVehicle.setMake(vehicle.getMake()); + existingVehicle.setYear(vehicle.getYear()); + existingVehicle.setModel(vehicle.getModel()); + + this.inventoryRepository.save(existingVehicle); + } + + public void deleteVehicle(String vin) { + this.inventoryRepository.deleteByVin(vin); + } +} diff --git a/persistence-modules/spring-data-cassandra-test/src/main/resources/application.yml b/persistence-modules/spring-data-cassandra-test/src/main/resources/application.yml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/persistence-modules/spring-data-cassandra-test/src/main/resources/logback.xml b/persistence-modules/spring-data-cassandra-test/src/main/resources/logback.xml new file mode 100644 index 0000000000..612e9cac40 --- /dev/null +++ b/persistence-modules/spring-data-cassandra-test/src/main/resources/logback.xml @@ -0,0 +1,14 @@ + + + + + %d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger{36}.%M - %msg%n + + + + + + + + + \ No newline at end of file diff --git a/persistence-modules/spring-data-cassandra-test/src/test/java/com/baeldung/spring/data/cassandra/test/service/InventoryServiceLiveTest.java b/persistence-modules/spring-data-cassandra-test/src/test/java/com/baeldung/spring/data/cassandra/test/service/InventoryServiceLiveTest.java new file mode 100644 index 0000000000..80958d01d2 --- /dev/null +++ b/persistence-modules/spring-data-cassandra-test/src/test/java/com/baeldung/spring/data/cassandra/test/service/InventoryServiceLiveTest.java @@ -0,0 +1,71 @@ +package com.baeldung.spring.data.cassandra.test.service; + +import com.baeldung.spring.data.cassandra.test.config.CassandraConfig; +import com.baeldung.spring.data.cassandra.test.domain.Vehicle; +import com.baeldung.spring.data.cassandra.test.repository.InventoryRepository; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.data.cassandra.DataCassandraTest; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.junit4.SpringRunner; +import org.testcontainers.containers.DockerComposeContainer; + +import java.io.File; +import java.util.Arrays; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(SpringRunner.class) +@DataCassandraTest +@Import(CassandraConfig.class) +public class InventoryServiceLiveTest { + @Autowired + private InventoryRepository repository; + + private InventoryService inventoryService; + + @ClassRule + public static DockerComposeContainer environment = + new DockerComposeContainer(new File("src/test/resources/compose-test.yml")); + + @Before + public void setUp() { + inventoryService = new InventoryService(this.repository); + } + + @Test + public void givenVehiclesInDBInitially_whenRetrieved_thenReturnAllVehiclesFromDB() { + List vehicles = inventoryService.getVehicles(); + assertThat(vehicles).isNotNull(); + assertThat(vehicles).isNotEmpty(); + } + + @Test + public void whenAddMoreVehiclesToDB_thenRetrievalReturnsAllVehicles() { + String vin1 = "ABC123"; + String vin2 = "XYZ123"; + List vehicles = Arrays.asList( + new Vehicle(vin1, 2020, "Toyota", "Camry"), + new Vehicle(vin2, 2019, "Honda", "Prius") + ); + inventoryService.addVehicles(vehicles); + + vehicles = inventoryService.getVehicles(); + assertThat(vehicles).isNotNull(); + assertThat(vehicles).isNotEmpty(); + assertThat(vehicles.size()).isEqualTo(5); + + Vehicle vehicle = inventoryService.getVehicle(vin1); + assertThat(vehicle).isNotNull(); + assertThat(vehicle.getVin()).isEqualTo(vin1); + + vehicle = inventoryService.getVehicle(vin2); + assertThat(vehicle).isNotNull(); + assertThat(vehicle.getVin()).isEqualTo(vin2); + } +} diff --git a/persistence-modules/spring-data-cassandra-test/src/test/resources/bootstrap-test.cql b/persistence-modules/spring-data-cassandra-test/src/test/resources/bootstrap-test.cql new file mode 100644 index 0000000000..6f3821ed83 --- /dev/null +++ b/persistence-modules/spring-data-cassandra-test/src/test/resources/bootstrap-test.cql @@ -0,0 +1,20 @@ +CREATE KEYSPACE inventory +WITH replication = { + 'class' : 'NetworkTopologyStrategy', + 'datacenter1' : 3 +}; + +use inventory; + +CREATE TABLE vehicles ( + vin text PRIMARY KEY, + year int, + make varchar, + model varchar +); + +consistency LOCAL_QUORUM; + +insert into vehicles (vin, year, make, model) values ('387KSJHFK23874GH', 2020, 'Ford', 'F-150'); +insert into vehicles (vin, year, make, model) values ('534HNDHFK23873EF', 2020, 'Honda', 'Accord'); +insert into vehicles (vin, year, make, model) values ('953TOYJEK23853DB', 2020, 'Toyota', 'Camry'); \ No newline at end of file diff --git a/persistence-modules/spring-data-cassandra-test/src/test/resources/compose-test.yml b/persistence-modules/spring-data-cassandra-test/src/test/resources/compose-test.yml new file mode 100644 index 0000000000..50f0f448f6 --- /dev/null +++ b/persistence-modules/spring-data-cassandra-test/src/test/resources/compose-test.yml @@ -0,0 +1,79 @@ +version: '2.1' +services: + cassandra1: + image: cassandra:3.11.10 + hostname: cassandra1 + networks: + - cassandranet + ports: + - "9042:9042" + environment: + CASSANDRA_SEEDS: "cassandra1" + CASSANDRA_DC: datacenter1 + CASSANDRA_RACK: rack1 + CASSANDRA_ENDPOINT_SNITCH: GossipingPropertyFileSnitch + healthcheck: + test: [ "CMD", "cqlsh", "-u cassandra", "-p cassandra" ,"-e describe keyspaces" ] + interval: 15s + timeout: 10s + retries: 10 + + cassandra2: + image: cassandra:3.11.10 + hostname: cassandra2 + networks: + - cassandranet + depends_on: + cassandra1: + condition: service_healthy + ports: + - "9043:9042" + environment: + CASSANDRA_SEEDS: "cassandra1" + CASSANDRA_DC: datacenter1 + CASSANDRA_RACK: rack1 + CASSANDRA_ENDPOINT_SNITCH: GossipingPropertyFileSnitch + healthcheck: + test: [ "CMD", "cqlsh", "-u cassandra", "-p cassandra" ,"-e describe keyspaces" ] + interval: 15s + timeout: 10s + retries: 10 + + cassandra3: + image: cassandra:3.11.10 + hostname: cassandra3 + networks: + - cassandranet + depends_on: + cassandra2: + condition: service_healthy + ports: + - "9044:9042" + environment: + CASSANDRA_SEEDS: "cassandra1" + CASSANDRA_DC: datacenter1 + CASSANDRA_RACK: rack1 + CASSANDRA_ENDPOINT_SNITCH: GossipingPropertyFileSnitch + healthcheck: + test: [ "CMD", "cqlsh", "-u cassandra", "-p cassandra" ,"-e describe keyspaces" ] + interval: 15s + timeout: 10s + retries: 10 + + cassandra-load-keyspace: + image: cassandra:3.11.10 + networks: + - cassandranet + depends_on: + cassandra1: + condition: service_healthy + cassandra2: + condition: service_healthy + cassandra3: + condition: service_healthy + volumes: + - ./bootstrap-test.cql:/schema.cql + command: /bin/bash -c "echo loading cassandra keyspace && cqlsh cassandra1 -f /schema.cql" + +networks: + cassandranet: \ No newline at end of file