diff --git a/cassandra/reactive/src/main/java/example/springdata/cassandra/auditing/ApplicationConfiguration.java b/cassandra/reactive/src/main/java/example/springdata/cassandra/auditing/ApplicationConfiguration.java new file mode 100644 index 00000000..5e52fa2c --- /dev/null +++ b/cassandra/reactive/src/main/java/example/springdata/cassandra/auditing/ApplicationConfiguration.java @@ -0,0 +1,43 @@ +/* + * 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 + * + * 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.auditing; + +import com.datastax.oss.driver.api.core.CqlIdentifier; +import com.datastax.oss.driver.api.core.CqlSession; +import reactor.core.publisher.Mono; + +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.data.cassandra.config.EnableReactiveCassandraAuditing; +import org.springframework.data.cassandra.core.CassandraTemplate; +import org.springframework.data.cassandra.core.InsertOptions; +import org.springframework.data.cassandra.core.cql.CqlTemplate; +import org.springframework.data.domain.ReactiveAuditorAware; + +/** + * Simple configuration for reactive Cassandra auditing. + * + * @author Mark Paluch + */ +@SpringBootApplication +@EnableReactiveCassandraAuditing +class ApplicationConfiguration { + + @Bean + ReactiveAuditorAware reactiveAuditorAware() { + return () -> Mono.just("the-current-user"); + } +} diff --git a/cassandra/reactive/src/main/java/example/springdata/cassandra/auditing/Order.java b/cassandra/reactive/src/main/java/example/springdata/cassandra/auditing/Order.java new file mode 100644 index 00000000..c0481085 --- /dev/null +++ b/cassandra/reactive/src/main/java/example/springdata/cassandra/auditing/Order.java @@ -0,0 +1,63 @@ +/* + * 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 + * + * 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.auditing; + +import lombok.Data; +import lombok.RequiredArgsConstructor; + +import java.time.Instant; + +import org.springframework.data.annotation.CreatedBy; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.LastModifiedBy; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.annotation.Transient; +import org.springframework.data.cassandra.core.mapping.Table; +import org.springframework.data.domain.Persistable; + +/** + * An entity to represent a Person. + * + * @author Mark Paluch + */ +@Data +@Table +@RequiredArgsConstructor +public class Order implements Persistable { + + @Transient boolean isNew; + + @Id final String orderId; + + @CreatedBy String createdBy; + + @CreatedDate Instant createdDate; + + @LastModifiedBy String lastModifiedBy; + + @LastModifiedDate Instant lastModifiedDate; + + @Override + public String getId() { + return getOrderId(); + } + + @Override + public boolean isNew() { + return isNew; + } +} diff --git a/cassandra/reactive/src/main/java/example/springdata/cassandra/auditing/OrderRepository.java b/cassandra/reactive/src/main/java/example/springdata/cassandra/auditing/OrderRepository.java new file mode 100644 index 00000000..c5bb9227 --- /dev/null +++ b/cassandra/reactive/src/main/java/example/springdata/cassandra/auditing/OrderRepository.java @@ -0,0 +1,23 @@ +/* + * 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 + * + * 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.auditing; + +import org.springframework.data.repository.reactive.ReactiveCrudRepository; + +/** + * @author Mark Paluch + */ +public interface OrderRepository extends ReactiveCrudRepository {} 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 new file mode 100644 index 00000000..ba5cf6de --- /dev/null +++ b/cassandra/reactive/src/test/java/example/springdata/cassandra/auditing/AuditingIntegrationTests.java @@ -0,0 +1,74 @@ +/* + * 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 + * + * 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.auditing; + +import static org.assertj.core.api.Assertions.*; + +import example.springdata.cassandra.util.CassandraKeyspace; +import reactor.test.StepVerifier; + +import java.time.Instant; + +import org.junit.ClassRule; +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.test.context.junit4.SpringRunner; + +/** + * Integration tests showing Reactive Auditing with Cassandra in action. + * + * @author Mark Paluch + */ +@RunWith(SpringRunner.class) +@DataCassandraTest +public class AuditingIntegrationTests { + + @ClassRule public final static CassandraKeyspace CASSANDRA_KEYSPACE = CassandraKeyspace.onLocalhost(); + + @Autowired OrderRepository orderRepository; + + @Test + public void shouldUpdateAuditor() throws InterruptedException { + + Order order = new Order("4711"); + order.setNew(true); + + orderRepository.save(order).as(StepVerifier::create).assertNext(actual -> { + + assertThat(actual.getCreatedBy()).isEqualTo("the-current-user"); + assertThat(actual.getCreatedDate()).isBetween(Instant.now().minusSeconds(60), Instant.now().plusSeconds(60)); + assertThat(actual.getLastModifiedBy()).isEqualTo("the-current-user"); + assertThat(actual.getLastModifiedDate()).isBetween(Instant.now().minusSeconds(60), Instant.now().plusSeconds(60)); + + }).verifyComplete(); + + Thread.sleep(10); + + order = orderRepository.findById("4711").block(); + + orderRepository.save(order).as(StepVerifier::create).assertNext(actual -> { + + assertThat(actual.getCreatedBy()).isEqualTo("the-current-user"); + assertThat(actual.getCreatedDate()).isBefore(actual.getLastModifiedDate()); + assertThat(actual.getLastModifiedBy()).isEqualTo("the-current-user"); + assertThat(actual.getLastModifiedDate()).isBetween(Instant.now().minusSeconds(60), Instant.now().plusSeconds(60)); + + }).verifyComplete(); + } +}