From 13c0dea55c37235eba6331efa401735e292f52bd Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 26 Apr 2022 11:30:09 +0200 Subject: [PATCH] Switch to Testcontainers for Elasticsearch examples. See #636 --- elasticsearch/example/pom.xml | 5 -- .../src/main/resources/application.properties | 1 - .../example/src/main/resources/log4j2.xml | 12 ++++ .../ElasticsearchOperationsTest.java | 29 +++++++--- elasticsearch/pom.xml | 13 ++++- elasticsearch/reactive/pom.xml | 5 -- .../conference/ApplicationConfiguration.java | 14 ++--- .../src/main/resources/application.properties | 1 - .../reactive/src/main/resources/log4j2.xml | 12 ++++ .../ReactiveElasticsearchOperationsTest.java | 26 +++++++-- .../ReactiveElasticsearchRepositoryTest.java | 26 +++++++-- elasticsearch/util/pom.xml | 35 ------------ .../util/ElasticsearchAvailableCondition.java | 57 ------------------- .../util/EnabledOnElasticsearch.java | 48 ---------------- 14 files changed, 107 insertions(+), 177 deletions(-) delete mode 100644 elasticsearch/example/src/main/resources/application.properties create mode 100644 elasticsearch/example/src/main/resources/log4j2.xml delete mode 100644 elasticsearch/reactive/src/main/resources/application.properties create mode 100644 elasticsearch/reactive/src/main/resources/log4j2.xml delete mode 100644 elasticsearch/util/pom.xml delete mode 100644 elasticsearch/util/src/main/java/example/springdata/elasticsearch/util/ElasticsearchAvailableCondition.java delete mode 100644 elasticsearch/util/src/main/java/example/springdata/elasticsearch/util/EnabledOnElasticsearch.java diff --git a/elasticsearch/example/pom.xml b/elasticsearch/example/pom.xml index 38528897..8a8c6a74 100644 --- a/elasticsearch/example/pom.xml +++ b/elasticsearch/example/pom.xml @@ -17,11 +17,6 @@ - - org.springframework.data.examples - spring-data-elasticsearch-example-utils - - org.springframework.boot spring-boot-starter-log4j2 diff --git a/elasticsearch/example/src/main/resources/application.properties b/elasticsearch/example/src/main/resources/application.properties deleted file mode 100644 index e3aca775..00000000 --- a/elasticsearch/example/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ -#spring.elasticsearch.rest.uris=http://localhost:9200 diff --git a/elasticsearch/example/src/main/resources/log4j2.xml b/elasticsearch/example/src/main/resources/log4j2.xml new file mode 100644 index 00000000..feee1a0a --- /dev/null +++ b/elasticsearch/example/src/main/resources/log4j2.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/elasticsearch/example/src/test/java/example/springdata/elasticsearch/conference/ElasticsearchOperationsTest.java b/elasticsearch/example/src/test/java/example/springdata/elasticsearch/conference/ElasticsearchOperationsTest.java index 35ceb5c9..4483aa37 100644 --- a/elasticsearch/example/src/test/java/example/springdata/elasticsearch/conference/ElasticsearchOperationsTest.java +++ b/elasticsearch/example/src/test/java/example/springdata/elasticsearch/conference/ElasticsearchOperationsTest.java @@ -17,8 +17,6 @@ package example.springdata.elasticsearch.conference; import static org.assertj.core.api.Assertions.*; -import example.springdata.elasticsearch.util.EnabledOnElasticsearch; - import java.text.ParseException; import java.text.SimpleDateFormat; @@ -27,12 +25,17 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.elasticsearch.core.ElasticsearchOperations; -import org.springframework.data.elasticsearch.core.SearchHit; -import org.springframework.data.elasticsearch.core.SearchHits; import org.springframework.data.elasticsearch.core.geo.GeoPoint; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; import org.springframework.data.elasticsearch.core.query.Criteria; import org.springframework.data.elasticsearch.core.query.CriteriaQuery; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; + +import org.testcontainers.elasticsearch.ElasticsearchContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; /** * Test case to show Spring Data Elasticsearch functionality. @@ -43,13 +46,25 @@ import org.springframework.data.elasticsearch.core.query.CriteriaQuery; * @author Prakhar Gupta */ @SpringBootTest(classes = ApplicationConfiguration.class) -@EnabledOnElasticsearch +@Testcontainers class ElasticsearchOperationsTest { private static final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); - @Autowired - ElasticsearchOperations operations; + @Container // + private static ElasticsearchContainer container = new ElasticsearchContainer( + DockerImageName.parse("docker.elastic.co/elasticsearch/elasticsearch:7.17.2")) // + .withPassword("foobar") // + .withReuse(true); + + @DynamicPropertySource + static void setProperties(DynamicPropertyRegistry registry) { + registry.add("spring.elasticsearch.uris", () -> "http://" + container.getHttpHostAddress()); + registry.add("spring.elasticsearch.username", () -> "elastic"); + registry.add("spring.elasticsearch.password", () -> "foobar"); + } + + @Autowired ElasticsearchOperations operations; @Test void textSearch() throws ParseException { diff --git a/elasticsearch/pom.xml b/elasticsearch/pom.xml index 1f509d98..4de2433e 100644 --- a/elasticsearch/pom.xml +++ b/elasticsearch/pom.xml @@ -16,7 +16,6 @@ https://github.com/spring-projects/spring-data-elasticsearch - util example reactive @@ -44,6 +43,18 @@ + + org.testcontainers + elasticsearch + test + + + + org.testcontainers + junit-jupiter + test + + diff --git a/elasticsearch/reactive/pom.xml b/elasticsearch/reactive/pom.xml index ec944e18..aff4c0e0 100644 --- a/elasticsearch/reactive/pom.xml +++ b/elasticsearch/reactive/pom.xml @@ -17,11 +17,6 @@ - - org.springframework.data.examples - spring-data-elasticsearch-example-utils - - io.projectreactor reactor-test diff --git a/elasticsearch/reactive/src/main/java/example/springdata/elasticsearch/conference/ApplicationConfiguration.java b/elasticsearch/reactive/src/main/java/example/springdata/elasticsearch/conference/ApplicationConfiguration.java index 4822aa92..480bf987 100644 --- a/elasticsearch/reactive/src/main/java/example/springdata/elasticsearch/conference/ApplicationConfiguration.java +++ b/elasticsearch/reactive/src/main/java/example/springdata/elasticsearch/conference/ApplicationConfiguration.java @@ -19,7 +19,6 @@ import reactor.test.StepVerifier; import java.io.IOException; import java.util.Arrays; -import java.util.List; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -27,12 +26,11 @@ import javax.annotation.PreDestroy; import org.elasticsearch.ElasticsearchStatusException; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.client.RequestOptions; +import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.client.indices.CreateIndexRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.data.elasticsearch.client.ClientConfiguration; -import org.springframework.data.elasticsearch.client.RestClients; import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations; import org.springframework.data.elasticsearch.core.geo.GeoPoint; @@ -43,13 +41,13 @@ import org.springframework.data.elasticsearch.core.geo.GeoPoint; class ApplicationConfiguration { @Autowired ReactiveElasticsearchOperations operations; + @Autowired RestHighLevelClient client; @Autowired ConferenceRepository repository; @PreDestroy public void deleteIndex() { try { - RestClients.create(ClientConfiguration.localhost()).rest().indices() - .delete(new DeleteIndexRequest("conference-index"), RequestOptions.DEFAULT); + client.indices().delete(new DeleteIndexRequest("conference-index"), RequestOptions.DEFAULT); } catch (IOException | ElasticsearchStatusException e) { // just ignore it } @@ -59,8 +57,7 @@ class ApplicationConfiguration { public void insertDataSample() { try { - RestClients.create(ClientConfiguration.localhost()).rest().indices() - .create(new CreateIndexRequest("conference-index"), RequestOptions.DEFAULT); + client.indices().create(new CreateIndexRequest("conference-index"), RequestOptions.DEFAULT); } catch (IOException | ElasticsearchStatusException e) { // just ignore it } @@ -79,7 +76,6 @@ class ApplicationConfiguration { .location(new GeoPoint(50.0646501D, 19.9449799)).build()); // Remove all documents - repository.deleteAll().then(repository.saveAll(documents).then()) - .as(StepVerifier::create).verifyComplete(); + repository.deleteAll().then(repository.saveAll(documents).then()).as(StepVerifier::create).verifyComplete(); } } diff --git a/elasticsearch/reactive/src/main/resources/application.properties b/elasticsearch/reactive/src/main/resources/application.properties deleted file mode 100644 index f5dac6c0..00000000 --- a/elasticsearch/reactive/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ -spring.data.elasticsearch.client.reactive.endpoints=localhost:9200 diff --git a/elasticsearch/reactive/src/main/resources/log4j2.xml b/elasticsearch/reactive/src/main/resources/log4j2.xml new file mode 100644 index 00000000..feee1a0a --- /dev/null +++ b/elasticsearch/reactive/src/main/resources/log4j2.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/elasticsearch/reactive/src/test/java/example/springdata/elasticsearch/conference/ReactiveElasticsearchOperationsTest.java b/elasticsearch/reactive/src/test/java/example/springdata/elasticsearch/conference/ReactiveElasticsearchOperationsTest.java index 23733f0b..6081ff31 100644 --- a/elasticsearch/reactive/src/test/java/example/springdata/elasticsearch/conference/ReactiveElasticsearchOperationsTest.java +++ b/elasticsearch/reactive/src/test/java/example/springdata/elasticsearch/conference/ReactiveElasticsearchOperationsTest.java @@ -17,7 +17,6 @@ package example.springdata.elasticsearch.conference; import static org.assertj.core.api.Assertions.*; -import example.springdata.elasticsearch.util.EnabledOnElasticsearch; import reactor.test.StepVerifier; import java.text.ParseException; @@ -31,6 +30,13 @@ import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperatio import org.springframework.data.elasticsearch.core.SearchHit; import org.springframework.data.elasticsearch.core.query.Criteria; import org.springframework.data.elasticsearch.core.query.CriteriaQuery; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; + +import org.testcontainers.elasticsearch.ElasticsearchContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; /** * Test case to show Spring Data Elasticsearch functionality. @@ -38,14 +44,26 @@ import org.springframework.data.elasticsearch.core.query.CriteriaQuery; * @author Christoph Strobl * @author Prakhar Gupta */ -@EnabledOnElasticsearch @SpringBootTest(classes = ApplicationConfiguration.class) +@Testcontainers class ReactiveElasticsearchOperationsTest { private static final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); - @Autowired - ReactiveElasticsearchOperations operations; + @Container // + private static ElasticsearchContainer container = new ElasticsearchContainer( + DockerImageName.parse("docker.elastic.co/elasticsearch/elasticsearch:7.17.2")) // + .withPassword("foobar") // + .withReuse(true); + + @DynamicPropertySource + static void setProperties(DynamicPropertyRegistry registry) { + registry.add("spring.elasticsearch.uris", () -> "http://" + container.getHttpHostAddress()); + registry.add("spring.elasticsearch.username", () -> "elastic"); + registry.add("spring.elasticsearch.password", () -> "foobar"); + } + + @Autowired ReactiveElasticsearchOperations operations; @Test void textSearch() { diff --git a/elasticsearch/reactive/src/test/java/example/springdata/elasticsearch/conference/ReactiveElasticsearchRepositoryTest.java b/elasticsearch/reactive/src/test/java/example/springdata/elasticsearch/conference/ReactiveElasticsearchRepositoryTest.java index 95fd42e7..7f6db008 100644 --- a/elasticsearch/reactive/src/test/java/example/springdata/elasticsearch/conference/ReactiveElasticsearchRepositoryTest.java +++ b/elasticsearch/reactive/src/test/java/example/springdata/elasticsearch/conference/ReactiveElasticsearchRepositoryTest.java @@ -17,7 +17,6 @@ package example.springdata.elasticsearch.conference; import static org.assertj.core.api.Assertions.*; -import example.springdata.elasticsearch.util.EnabledOnElasticsearch; import reactor.test.StepVerifier; import java.text.ParseException; @@ -27,6 +26,13 @@ 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.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; + +import org.testcontainers.elasticsearch.ElasticsearchContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; /** * Test case to show reactive Spring Data Elasticsearch repository functionality. @@ -34,14 +40,26 @@ import org.springframework.boot.test.context.SpringBootTest; * @author Christoph Strobl * @author Prakhar Gupta */ -@EnabledOnElasticsearch @SpringBootTest(classes = ApplicationConfiguration.class) +@Testcontainers class ReactiveElasticsearchRepositoryTest { private static final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); - @Autowired - ConferenceRepository repository; + @Container // + private static ElasticsearchContainer container = new ElasticsearchContainer( + DockerImageName.parse("docker.elastic.co/elasticsearch/elasticsearch:7.17.2")) // + .withPassword("foobar") // + .withReuse(true); + + @DynamicPropertySource + static void setProperties(DynamicPropertyRegistry registry) { + registry.add("spring.elasticsearch.uris", () -> "http://" + container.getHttpHostAddress()); + registry.add("spring.elasticsearch.username", () -> "elastic"); + registry.add("spring.elasticsearch.password", () -> "foobar"); + } + + @Autowired ConferenceRepository repository; @Test void textSearch() { diff --git a/elasticsearch/util/pom.xml b/elasticsearch/util/pom.xml deleted file mode 100644 index 995bd40a..00000000 --- a/elasticsearch/util/pom.xml +++ /dev/null @@ -1,35 +0,0 @@ - - 4.0.0 - - - org.springframework.data.examples - spring-data-elasticsearch-examples - 2.0.0.BUILD-SNAPSHOT - - - spring-data-elasticsearch-example-utils - Spring Data Elasticsearch - Example Utilities - - - - - org.junit.jupiter - junit-jupiter-api - - - - org.junit.platform - junit-platform-commons - compile - - - - org.springframework - spring-web - - - - - diff --git a/elasticsearch/util/src/main/java/example/springdata/elasticsearch/util/ElasticsearchAvailableCondition.java b/elasticsearch/util/src/main/java/example/springdata/elasticsearch/util/ElasticsearchAvailableCondition.java deleted file mode 100644 index b7fd60fa..00000000 --- a/elasticsearch/util/src/main/java/example/springdata/elasticsearch/util/ElasticsearchAvailableCondition.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2021-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.elasticsearch.util; - -import org.junit.jupiter.api.extension.ConditionEvaluationResult; -import org.junit.jupiter.api.extension.ExecutionCondition; -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.platform.commons.support.AnnotationSupport; - -import org.springframework.http.HttpMethod; -import org.springframework.web.client.RestTemplate; - -/** - * {@link ExecutionCondition} evaluating {@link EnabledOnElasticsearch @EnableOnElasticsearch}. - * - * @author Christoph Strobl - * @author Prakhar Gupta - */ -class ElasticsearchAvailableCondition implements ExecutionCondition { - - @Override - public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext extensionContext) { - - var annotation = AnnotationSupport.findAnnotation(extensionContext.getElement(), - EnabledOnElasticsearch.class); - - return annotation.map(EnabledOnElasticsearch::url) // - .map(ElasticsearchAvailableCondition::checkServerRunning) // - .orElse(ConditionEvaluationResult.enabled("Enabled by default")); - } - - private static ConditionEvaluationResult checkServerRunning(String url) { - - var template = new RestTemplate(); - - try { - var entity = template.exchange(url, HttpMethod.HEAD, null, byte[].class); - return ConditionEvaluationResult - .enabled("Successfully connected to Elasticsearch server: " + entity.getStatusCode()); - } catch (RuntimeException e) { - return ConditionEvaluationResult.disabled("Elasticsearch unavailable at " + url + "; " + e.getMessage()); - } - } -} diff --git a/elasticsearch/util/src/main/java/example/springdata/elasticsearch/util/EnabledOnElasticsearch.java b/elasticsearch/util/src/main/java/example/springdata/elasticsearch/util/EnabledOnElasticsearch.java deleted file mode 100644 index dc6c6837..00000000 --- a/elasticsearch/util/src/main/java/example/springdata/elasticsearch/util/EnabledOnElasticsearch.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2021-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.elasticsearch.util; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.junit.jupiter.api.extension.ExtendWith; - -/** - * {@code @EnableOnElasticsearch} is used to signal that the annotated test class or test method is only - * enabled if Elasticsearch is available at {@link #url()}. - *

- * When applied at the class level, all test methods within that class will be enabled if Elasticsearch is available. - *

- * If a test method is disabled via this annotation, that does not prevent the test class from being instantiated. - * Rather, it prevents the execution of the test method and method-level lifecycle callbacks such as {@code @BeforeEach} - * methods, {@code @AfterEach} methods, and corresponding extension APIs. - * - * @author Prakhar Gupta - * @author Mark Paluch - */ -@Retention(RetentionPolicy.RUNTIME) -@Target({ElementType.TYPE, ElementType.METHOD}) -@ExtendWith(ElasticsearchAvailableCondition.class) -public @interface EnabledOnElasticsearch { - - /** - * URL pointing at the Elasticsearch instance to check. - */ - String url() default "http://localhost:9200"; - -}