DATAES-68 - Add support for auditing annotations.

Original PR: #400
This commit is contained in:
Peter-Josef Meisch
2020-03-11 18:39:11 +01:00
committed by GitHub
parent 0b0c8027a3
commit 300eb313dd
31 changed files with 1863 additions and 45 deletions

View File

@@ -0,0 +1,47 @@
/*
* 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 org.springframework.data.elasticsearch;
import static org.assertj.core.api.Assertions.*;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
import org.springframework.data.elasticsearch.junit.jupiter.ReactiveElasticsearchRestTemplateConfiguration;
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
import org.springframework.test.context.ContextConfiguration;
/**
* class demonstrating the setup of a JUnit 5 test in Spring Data Elasticsearch that uses the reactive rest client. The
* ContextConfiguration must include the {@link ElasticsearchRestTemplateConfiguration} class.
*
* @author Peter-Josef Meisch
*/
@SpringIntegrationTest
@ContextConfiguration(classes = { ReactiveElasticsearchRestTemplateConfiguration.class })
@DisplayName("a sample JUnit 5 test with reactive rest client")
public class JUnit5SampleReactiveRestClientBasedTests {
@Autowired private ReactiveElasticsearchOperations elasticsearchOperations;
@Test
@DisplayName("should have a ReactiveElasticsearchOperations")
void shouldHaveARestTemplate() {
assertThat(elasticsearchOperations).isNotNull().isInstanceOf(ReactiveElasticsearchOperations.class);
}
}

View File

@@ -0,0 +1,142 @@
/*
* 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 org.springframework.data.elasticsearch.config;
import static org.assertj.core.api.Assertions.*;
import java.time.LocalDateTime;
import java.util.Optional;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
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.domain.AuditorAware;
import org.springframework.data.domain.Persistable;
import org.springframework.data.elasticsearch.core.event.BeforeConvertCallback;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.data.mapping.callback.EntityCallbacks;
import org.springframework.lang.Nullable;
/**
* @author Peter-Josef Meisch
*/
public abstract class AuditingIntegrationTest {
public static AuditorAware<String> auditorProvider() {
return new AuditorAware<String>() {
int count = 0;
@Override
public Optional<String> getCurrentAuditor() {
return Optional.of("Auditor " + (++count));
}
};
}
@Autowired ApplicationContext applicationContext;
@Test // DATAES-68
void shouldEnableAuditingAndSetAuditingDates() throws InterruptedException {
SimpleElasticsearchMappingContext mappingContext = applicationContext
.getBean(SimpleElasticsearchMappingContext.class);
mappingContext.getPersistentEntity(Entity.class);
EntityCallbacks callbacks = EntityCallbacks.create(applicationContext);
Entity entity = new Entity();
entity.setId("1");
entity = callbacks.callback(BeforeConvertCallback.class, entity);
assertThat(entity.getCreated()).isNotNull();
assertThat(entity.getModified()).isEqualTo(entity.created);
assertThat(entity.getCreatedBy()).isEqualTo("Auditor 1");
assertThat(entity.getModifiedBy()).isEqualTo("Auditor 1");
Thread.sleep(10);
entity = callbacks.callback(BeforeConvertCallback.class, entity);
assertThat(entity.getCreated()).isNotNull();
assertThat(entity.getModified()).isNotEqualTo(entity.created);
assertThat(entity.getCreatedBy()).isEqualTo("Auditor 1");
assertThat(entity.getModifiedBy()).isEqualTo("Auditor 2");
}
static class Entity implements Persistable<String> {
private @Nullable @Id String id;
private @Nullable @CreatedDate LocalDateTime created;
private @Nullable LocalDateTime modified;
private @Nullable @CreatedBy String createdBy;
private @Nullable @LastModifiedBy String modifiedBy;
@Nullable
public String getId() {
return id;
}
public void setId(@Nullable String id) {
this.id = id;
}
@Nullable
public LocalDateTime getCreated() {
return created;
}
public void setCreated(@Nullable LocalDateTime created) {
this.created = created;
}
public void setModified(@Nullable LocalDateTime modified) {
this.modified = modified;
}
@Nullable
@LastModifiedDate
public LocalDateTime getModified() {
return modified;
}
@Nullable
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(@Nullable String createdBy) {
this.createdBy = createdBy;
}
@Nullable
public String getModifiedBy() {
return modifiedBy;
}
public void setModifiedBy(@Nullable String modifiedBy) {
this.modifiedBy = modifiedBy;
}
@Override
public boolean isNew() {
return id == null || (created == null && createdBy == null);
}
}
}

View File

@@ -0,0 +1,50 @@
/*
* 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 org.springframework.data.elasticsearch.config;
import static org.assertj.core.api.Assertions.*;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.type.AnnotationMetadata;
/**
* Unit tests for {@link ElasticsearchAuditingRegistrar}.
*
* @author Oliver Gierke
* @author Peter-Josef Meisch
*/
@ExtendWith(MockitoExtension.class)
public class ElasticsearchAuditingRegistrarUnitTests {
ElasticsearchAuditingRegistrar registrar = new ElasticsearchAuditingRegistrar();
@Mock AnnotationMetadata metadata;
@Mock BeanDefinitionRegistry registry;
@Test // DATAES-68
public void rejectsNullAnnotationMetadata() {
assertThatIllegalArgumentException().isThrownBy(() -> registrar.registerBeanDefinitions(null, registry));
}
@Test // DATAES-68
public void rejectsNullBeanDefinitionRegistry() {
assertThatIllegalArgumentException().isThrownBy(() -> registrar.registerBeanDefinitions(metadata, null));
}
}

View File

@@ -0,0 +1,41 @@
/*
* 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 org.springframework.data.elasticsearch.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
import org.springframework.test.context.ContextConfiguration;
/**
* @author Peter-Josef Meisch
*/
@SpringIntegrationTest
@ContextConfiguration(classes = { ElasticsearchRestAuditingIntegrationTest.Config.class })
public class ElasticsearchRestAuditingIntegrationTest extends AuditingIntegrationTest {
@Import({ ElasticsearchRestTemplateConfiguration.class })
@EnableElasticsearchAuditing(auditorAwareRef = "auditorAware")
static class Config {
@Bean
public AuditorAware<String> auditorAware() {
return auditorProvider();
}
}
}

View File

@@ -0,0 +1,41 @@
/*
* 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 org.springframework.data.elasticsearch.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchTemplateConfiguration;
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
import org.springframework.test.context.ContextConfiguration;
/**
* @author Peter-Josef Meisch
*/
@SpringIntegrationTest
@ContextConfiguration(classes = { ElasticsearchTransportAuditingIntegrationTest.Config.class })
public class ElasticsearchTransportAuditingIntegrationTest extends AuditingIntegrationTest {
@Import({ ElasticsearchTemplateConfiguration.class })
@EnableElasticsearchAuditing(auditorAwareRef = "auditorAware")
static class Config {
@Bean
public AuditorAware<String> auditorAware() {
return auditorProvider();
}
}
}

View File

@@ -0,0 +1,160 @@
/*
* 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 org.springframework.data.elasticsearch.config;
import static org.assertj.core.api.Assertions.*;
import java.time.LocalDateTime;
import java.util.Optional;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
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.domain.AuditorAware;
import org.springframework.data.domain.Persistable;
import org.springframework.data.elasticsearch.core.event.ReactiveBeforeConvertCallback;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.data.elasticsearch.junit.jupiter.ReactiveElasticsearchRestTemplateConfiguration;
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
import org.springframework.data.mapping.callback.ReactiveEntityCallbacks;
import org.springframework.lang.Nullable;
import org.springframework.test.context.ContextConfiguration;
/**
* @author Peter-Josef Meisch
*/
@SpringIntegrationTest
@ContextConfiguration(classes = { ReactiveAuditingIntegrationTest.Config.class })
public class ReactiveAuditingIntegrationTest {
public static AuditorAware<String> auditorProvider() {
return new AuditorAware<String>() {
int count = 0;
@Override
public Optional<String> getCurrentAuditor() {
return Optional.of("Auditor " + (++count));
}
};
}
@Import({ ReactiveElasticsearchRestTemplateConfiguration.class })
@EnableElasticsearchAuditing(auditorAwareRef = "auditorAware")
static class Config {
@Bean
public AuditorAware<String> auditorAware() {
return auditorProvider();
}
}
@Autowired ApplicationContext applicationContext;
@Test // DATAES-68
void shouldEnableAuditingAndSetAuditingDates() throws InterruptedException {
SimpleElasticsearchMappingContext mappingContext = applicationContext
.getBean(SimpleElasticsearchMappingContext.class);
mappingContext.getPersistentEntity(Entity.class);
ReactiveEntityCallbacks callbacks = ReactiveEntityCallbacks.create(applicationContext);
Entity entity = new Entity();
entity.setId("1");
entity = callbacks.callback(ReactiveBeforeConvertCallback.class, entity).block();
assertThat(entity.getCreated()).isNotNull();
assertThat(entity.getModified()).isEqualTo(entity.created);
assertThat(entity.getCreatedBy()).isEqualTo("Auditor 1");
assertThat(entity.getModifiedBy()).isEqualTo("Auditor 1");
Thread.sleep(10);
entity = callbacks.callback(ReactiveBeforeConvertCallback.class, entity).block();
assertThat(entity.getCreated()).isNotNull();
assertThat(entity.getModified()).isNotEqualTo(entity.created);
assertThat(entity.getCreatedBy()).isEqualTo("Auditor 1");
assertThat(entity.getModifiedBy()).isEqualTo("Auditor 2");
}
static class Entity implements Persistable<String> {
private @Nullable @Id String id;
private @Nullable @CreatedDate LocalDateTime created;
private @Nullable LocalDateTime modified;
private @Nullable @CreatedBy String createdBy;
private @Nullable @LastModifiedBy String modifiedBy;
@Nullable
public String getId() {
return id;
}
public void setId(@Nullable String id) {
this.id = id;
}
@Nullable
public LocalDateTime getCreated() {
return created;
}
public void setCreated(@Nullable LocalDateTime created) {
this.created = created;
}
public void setModified(@Nullable LocalDateTime modified) {
this.modified = modified;
}
@Nullable
@LastModifiedDate
public LocalDateTime getModified() {
return modified;
}
@Nullable
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(@Nullable String createdBy) {
this.createdBy = createdBy;
}
@Nullable
public String getModifiedBy() {
return modifiedBy;
}
public void setModifiedBy(@Nullable String modifiedBy) {
this.modifiedBy = modifiedBy;
}
@Override
public boolean isNew() {
return id == null || (created == null && createdBy == null);
}
}
}

View File

@@ -0,0 +1,163 @@
/*
* 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 org.springframework.data.elasticsearch.core.event;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.time.LocalDateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.core.Ordered;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.data.mapping.context.PersistentEntities;
import org.springframework.lang.Nullable;
/**
* @author Peter-Josef Meisch
*/
@ExtendWith(MockitoExtension.class)
class AuditingEntityCallbackTests {
IsNewAwareAuditingHandler handler;
AuditingEntityCallback callback;
@BeforeEach
void setUp() {
SimpleElasticsearchMappingContext context = new SimpleElasticsearchMappingContext();
context.getPersistentEntity(Sample.class);
handler = spy(new IsNewAwareAuditingHandler(PersistentEntities.of(context)));
callback = new AuditingEntityCallback(() -> handler);
}
@Test // DATAES-68
void shouldThrowExceptionOnNullFactory() {
assertThatIllegalArgumentException().isThrownBy(() -> new AuditingEntityCallback(null));
}
@Test // DATAES-68
void shouldHaveOrder100() {
assertThat(callback).isInstanceOf(Ordered.class);
assertThat(callback.getOrder()).isEqualTo(100);
}
@Test // DATAES-68
void shouldCallHandler() {
Sample entity = new Sample();
entity.setId("42");
callback.onBeforeConvert(entity);
verify(handler).markAudited(eq(entity));
}
@Test // DATAES-68
void shouldReturnObjectFromHandler() {
Sample sample1 = new Sample();
sample1.setId("1");
Sample sample2 = new Sample();
sample2.setId("2");
doReturn(sample2).when(handler).markAudited(any());
Sample result = (Sample) callback.onBeforeConvert(sample1);
assertThat(result).isSameAs(sample2);
}
static class Sample {
@Nullable @Id String id;
@Nullable @CreatedDate LocalDateTime createdDate;
@Nullable @CreatedBy String createdBy;
@Nullable @LastModifiedDate LocalDateTime modified;
@Nullable
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Nullable
public LocalDateTime getCreatedDate() {
return createdDate;
}
public void setCreatedDate(LocalDateTime createdDate) {
this.createdDate = createdDate;
}
@Nullable
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(@Nullable String createdBy) {
this.createdBy = createdBy;
}
@Nullable
public LocalDateTime getModified() {
return modified;
}
public void setModified(LocalDateTime modified) {
this.modified = modified;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Sample sample = (Sample) o;
if (id != null ? !id.equals(sample.id) : sample.id != null)
return false;
if (createdDate != null ? !createdDate.equals(sample.createdDate) : sample.createdDate != null)
return false;
if (createdBy != null ? !createdBy.equals(sample.createdBy) : sample.createdBy != null)
return false;
return modified != null ? modified.equals(sample.modified) : sample.modified == null;
}
@Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (createdDate != null ? createdDate.hashCode() : 0);
result = 31 * result + (createdBy != null ? createdBy.hashCode() : 0);
result = 31 * result + (modified != null ? modified.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "Sample{" + "id='" + id + '\'' + ", createdDate=" + createdDate + ", createdBy='" + createdBy + '\''
+ ", modified=" + modified + '}';
}
}
}

View File

@@ -0,0 +1,100 @@
/*
* 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 org.springframework.data.elasticsearch.core.event;
import static org.assertj.core.api.Assertions.*;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.stereotype.Component;
/**
* @author Peter-Josef Meisch
*/
abstract class ElasticsearchOperationsCallbackTest {
@Autowired private ElasticsearchOperations operations;
@Configuration
static class Config {
@Component
static class SampleEntityBeforeConvertCallback implements BeforeConvertCallback<SampleEntity> {
@Override
public SampleEntity onBeforeConvert(SampleEntity entity) {
entity.setText("converted");
return entity;
}
}
}
@BeforeEach
void setUp() {
IndexOperations indexOps = operations.indexOps(SampleEntity.class);
indexOps.delete();
indexOps.create();
indexOps.putMapping(indexOps.createMapping(SampleEntity.class));
}
@AfterEach
void tearDown() {
IndexOperations indexOps = operations.indexOps(SampleEntity.class);
indexOps.delete();
}
@Test
void shouldCallBeforeConvertCallback() {
SampleEntity entity = new SampleEntity("1", "test");
SampleEntity saved = operations.save(entity);
assertThat(saved.getText()).isEqualTo("converted");
}
@Document(indexName = "test-operations-callback")
static class SampleEntity {
@Id private String id;
private String text;
public SampleEntity(String id, String text) {
this.id = id;
this.text = text;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
}

View File

@@ -0,0 +1,27 @@
/*
* 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 org.springframework.data.elasticsearch.core.event;
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
import org.springframework.test.context.ContextConfiguration;
/**
* @author Peter-Josef Meisch
*/
@SpringIntegrationTest
@ContextConfiguration(classes = { ElasticsearchRestTemplateConfiguration.class, ElasticsearchOperationsCallbackTest.Config.class })
class ElasticsearchRestOperationsCallbackTest extends ElasticsearchOperationsCallbackTest {}

View File

@@ -0,0 +1,27 @@
/*
* 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 org.springframework.data.elasticsearch.core.event;
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchTemplateConfiguration;
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
import org.springframework.test.context.ContextConfiguration;
/**
* @author Peter-Josef Meisch
*/
@SpringIntegrationTest
@ContextConfiguration(classes = { ElasticsearchTemplateConfiguration.class, ElasticsearchOperationsCallbackTest.Config.class })
class ElasticsearchTransportOperationsCallbackTest extends ElasticsearchOperationsCallbackTest {}

View File

@@ -0,0 +1,167 @@
/*
* 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 org.springframework.data.elasticsearch.core.event;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import reactor.test.StepVerifier;
import java.time.LocalDateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.core.Ordered;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.data.mapping.context.PersistentEntities;
import org.springframework.lang.Nullable;
/**
* @author Peter-Josef Meisch
*/
@ExtendWith(MockitoExtension.class)
class ReactiveAuditingEntityCallbackTests {
IsNewAwareAuditingHandler handler;
ReactiveAuditingEntityCallback callback;
@BeforeEach
void setUp() {
SimpleElasticsearchMappingContext context = new SimpleElasticsearchMappingContext();
context.getPersistentEntity(Sample.class);
handler = spy(new IsNewAwareAuditingHandler(PersistentEntities.of(context)));
callback = new ReactiveAuditingEntityCallback(() -> handler);
}
@Test // DATAES-68
void shouldThrowExceptionOnNullFactory() {
assertThatIllegalArgumentException().isThrownBy(() -> new AuditingEntityCallback(null));
}
@Test // DATAES-68
void shouldHaveOrder100() {
assertThat(callback).isInstanceOf(Ordered.class);
assertThat(callback.getOrder()).isEqualTo(100);
}
@Test // DATAES-68
void shouldCallHandler() {
Sample entity = new Sample();
entity.setId("42");
callback.onBeforeConvert(entity);
verify(handler).markAudited(eq(entity));
}
@Test // DATAES-68
void shouldReturnObjectFromHandler() {
Sample sample1 = new Sample();
sample1.setId("1");
Sample sample2 = new Sample();
sample2.setId("2");
doReturn(sample2).when(handler).markAudited(any());
callback.onBeforeConvert(sample1) //
.as(StepVerifier::create) //
.consumeNextWith(it -> { //
assertThat(it).isSameAs(sample2); //
}).verifyComplete();
}
static class Sample {
@Nullable @Id String id;
@Nullable @CreatedDate LocalDateTime createdDate;
@Nullable @CreatedBy String createdBy;
@Nullable @LastModifiedDate LocalDateTime modified;
@Nullable
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Nullable
public LocalDateTime getCreatedDate() {
return createdDate;
}
public void setCreatedDate(LocalDateTime createdDate) {
this.createdDate = createdDate;
}
@Nullable
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(@Nullable String createdBy) {
this.createdBy = createdBy;
}
@Nullable
public LocalDateTime getModified() {
return modified;
}
public void setModified(LocalDateTime modified) {
this.modified = modified;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Sample sample = (Sample) o;
if (id != null ? !id.equals(sample.id) : sample.id != null)
return false;
if (createdDate != null ? !createdDate.equals(sample.createdDate) : sample.createdDate != null)
return false;
if (createdBy != null ? !createdBy.equals(sample.createdBy) : sample.createdBy != null)
return false;
return modified != null ? modified.equals(sample.modified) : sample.modified == null;
}
@Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (createdDate != null ? createdDate.hashCode() : 0);
result = 31 * result + (createdBy != null ? createdBy.hashCode() : 0);
result = 31 * result + (modified != null ? modified.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "Sample{" + "id='" + id + '\'' + ", createdDate=" + createdDate + ", createdBy='" + createdBy + '\''
+ ", modified=" + modified + '}';
}
}
}

View File

@@ -0,0 +1,115 @@
/*
* 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 org.springframework.data.elasticsearch.core.event;
import static org.assertj.core.api.Assertions.*;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
import org.springframework.data.elasticsearch.junit.jupiter.ReactiveElasticsearchRestTemplateConfiguration;
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
import org.springframework.stereotype.Component;
import org.springframework.test.context.ContextConfiguration;
/**
* @author Peter-Josef Meisch
*/
@SpringIntegrationTest
@ContextConfiguration(classes = { ReactiveElasticsearchOperationsCallbackTest.Config.class })
public class ReactiveElasticsearchOperationsCallbackTest {
@Configuration
@Import({ ReactiveElasticsearchRestTemplateConfiguration.class, ElasticsearchRestTemplateConfiguration.class })
static class Config {
@Component
static class SampleEntityBeforeConvertCallback implements ReactiveBeforeConvertCallback<SampleEntity> {
@Override
public Mono<SampleEntity> onBeforeConvert(SampleEntity entity) {
entity.setText("reactive-converted");
return Mono.just(entity);
}
}
}
@Autowired private ReactiveElasticsearchOperations operations;
@Autowired private ElasticsearchOperations nonreactiveOperations;
@BeforeEach
void setUp() {
IndexOperations indexOps = nonreactiveOperations.indexOps(SampleEntity.class);
indexOps.create();
indexOps.putMapping(indexOps.createMapping(SampleEntity.class));
}
@AfterEach
void tearDown() {
IndexOperations indexOps = nonreactiveOperations.indexOps(SampleEntity.class);
indexOps.delete();
}
@Test // DATES-68
void shouldCallCallbackOnSave() {
SampleEntity sample = new SampleEntity("42", "initial");
operations.save(sample) //
.as(StepVerifier::create) //
.consumeNextWith(it -> { //
assertThat(it.text).isEqualTo("reactive-converted"); //
}) //
.verifyComplete();
}
@Document(indexName = "test-operations-reactive-callback")
static class SampleEntity {
@Id private String id;
private String text;
public SampleEntity(String id, String text) {
this.id = id;
this.text = text;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
}

View File

@@ -104,7 +104,7 @@ public class SimpleElasticsearchPersistentEntityTests {
}
private class EntityWithWrongVersionType {
private static class EntityWithWrongVersionType {
@Nullable @Version private String version;
@@ -118,7 +118,7 @@ public class SimpleElasticsearchPersistentEntityTests {
}
}
private class EntityWithMultipleVersionField {
private static class EntityWithMultipleVersionField {
@Nullable @Version private Long version1;
@Nullable @Version private Long version2;
@@ -143,7 +143,6 @@ public class SimpleElasticsearchPersistentEntityTests {
}
// DATAES-462
static class TwoScoreProperties {
@Score float first;

View File

@@ -27,16 +27,14 @@ import org.springframework.data.elasticsearch.config.AbstractElasticsearchConfig
/**
* Configuration for Spring Data Elasticsearch using
* {@link org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate}. The required
* {@link ClusterConnectionInfo} bean must be provided by the testclass.
* {@link org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate}.
*
* @author Peter-Josef Meisch
*/
@Configuration
public class ElasticsearchRestTemplateConfiguration extends AbstractElasticsearchConfiguration {
@Autowired
private ClusterConnectionInfo clusterConnectionInfo;
@Autowired private ClusterConnectionInfo clusterConnectionInfo;
@Override
@Bean

View File

@@ -0,0 +1,51 @@
/*
* 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 org.springframework.data.elasticsearch.junit.jupiter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient;
import org.springframework.data.elasticsearch.client.reactive.ReactiveRestClients;
import org.springframework.data.elasticsearch.config.AbstractReactiveElasticsearchConfiguration;
/**
* Configuration for Spring Data Elasticsearch Integration Tests using
* {@link org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations}
*
* @author Peter-Josef Meisch
*/
@Configuration
public class ReactiveElasticsearchRestTemplateConfiguration extends AbstractReactiveElasticsearchConfiguration {
@Autowired private ClusterConnectionInfo clusterConnectionInfo;
@Override
public ReactiveElasticsearchClient reactiveElasticsearchClient() {
String elasticsearchHostPort = clusterConnectionInfo.getHost() + ':' + clusterConnectionInfo.getHttpPort();
ClientConfiguration.TerminalClientConfigurationBuilder configurationBuilder = ClientConfiguration.builder() //
.connectedTo(elasticsearchHostPort);
if (clusterConnectionInfo.isUseSsl()) {
configurationBuilder = ((ClientConfiguration.MaybeSecureClientConfigurationBuilder) configurationBuilder)
.usingSsl();
}
return ReactiveRestClients.create(configurationBuilder.build());
}
}