diff --git a/pom.xml b/pom.xml
index 124e702b1..63925dcd4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -25,6 +25,15 @@
1.15.3
1.0.6.RELEASE
spring.data.elasticsearch
+
+
+ test
+ integration-test
+ none
@@ -264,25 +273,6 @@
test
-
-
org.skyscreamer
jsonassert
@@ -365,9 +355,6 @@
-
org.apache.maven.plugins
maven-surefire-plugin
@@ -386,7 +373,7 @@
default-test
- test
+ ${mvn.unit-test.goal}
test
@@ -394,15 +381,32 @@
integration-test
-
+
+
+ integration-test-elasticsearch
+ ${mvn.integration-test-elasticsearch.goal}
+
+ test
+
+
+ integration-test
+
+ elasticsearch
+
+
+
+
- integration-test
- integration-test
+ integration-test-opensearch
+ ${mvn.integration-test-opensearch.goal}
test
integration-test
+
+ opensearch
+
diff --git a/src/test/java/org/springframework/data/elasticsearch/Foobar.java b/src/test/java/org/springframework/data/elasticsearch/Foobar.java
new file mode 100644
index 000000000..3f9d28f02
--- /dev/null
+++ b/src/test/java/org/springframework/data/elasticsearch/Foobar.java
@@ -0,0 +1,19 @@
+package org.springframework.data.elasticsearch;
+
+import java.lang.annotation.Documented;
+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.Tag;
+
+/**
+ * @author Peter-Josef Meisch
+ */
+@Target({ ElementType.TYPE, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Tag("foobar")
+public @interface Foobar {
+}
diff --git a/src/test/java/org/springframework/data/elasticsearch/FoobarIntegrationTest.java b/src/test/java/org/springframework/data/elasticsearch/FoobarIntegrationTest.java
new file mode 100644
index 000000000..409bf4349
--- /dev/null
+++ b/src/test/java/org/springframework/data/elasticsearch/FoobarIntegrationTest.java
@@ -0,0 +1,28 @@
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
+
+/**
+ * @author Peter-Josef Meisch
+ */
+@SpringIntegrationTest
+@Foobar
+public abstract class FoobarIntegrationTest {
+
+ private final Logger LOGGER = LoggerFactory.getLogger(getClass());
+
+ @Test
+ @DisplayName("should run test")
+ void shouldRunTest() {
+
+ int answer = 42;
+
+ assertThat(answer).isEqualTo(42);
+ }
+}
diff --git a/src/test/java/org/springframework/data/elasticsearch/TransportFoobarIntegrationTest.java b/src/test/java/org/springframework/data/elasticsearch/TransportFoobarIntegrationTest.java
new file mode 100644
index 000000000..bdc39c75c
--- /dev/null
+++ b/src/test/java/org/springframework/data/elasticsearch/TransportFoobarIntegrationTest.java
@@ -0,0 +1,17 @@
+package org.springframework.data.elasticsearch;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
+import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchTemplateConfiguration;
+import org.springframework.data.elasticsearch.junit.jupiter.IntegrationtestEnvironment;
+import org.springframework.test.context.ContextConfiguration;
+
+/**
+ * This class should only run when the cluster is an Elasticsearch cluster.
+ *
+ * @author Peter-Josef Meisch
+ */
+@EnabledIfSystemProperty(named = IntegrationtestEnvironment.SYSTEM_PROPERTY, matches = "(?i)elasticsearch")
+@ContextConfiguration(classes = { ElasticsearchTemplateConfiguration.class })
+@DisplayName("foobar integration with transport client")
+public class TransportFoobarIntegrationTest extends FoobarIntegrationTest {}
diff --git a/src/test/java/org/springframework/data/elasticsearch/config/AuditingIntegrationTest.java b/src/test/java/org/springframework/data/elasticsearch/config/AuditingIntegrationTest.java
index e14647448..e0bc69f89 100644
--- a/src/test/java/org/springframework/data/elasticsearch/config/AuditingIntegrationTest.java
+++ b/src/test/java/org/springframework/data/elasticsearch/config/AuditingIntegrationTest.java
@@ -73,7 +73,7 @@ void shouldEnableAuditingAndSetAuditingDates() throws InterruptedException {
assertThat(entity.getCreatedBy()).isEqualTo("Auditor 1");
assertThat(entity.getModifiedBy()).isEqualTo("Auditor 1");
- Thread.sleep(10);
+ Thread.sleep(50);
entity = callbacks.callback(BeforeConvertCallback.class, entity, IndexCoordinates.of("index"));
diff --git a/src/test/java/org/springframework/data/elasticsearch/junit/jupiter/ClusterConnection.java b/src/test/java/org/springframework/data/elasticsearch/junit/jupiter/ClusterConnection.java
index e0d2bc430..5f16814a3 100644
--- a/src/test/java/org/springframework/data/elasticsearch/junit/jupiter/ClusterConnection.java
+++ b/src/test/java/org/springframework/data/elasticsearch/junit/jupiter/ClusterConnection.java
@@ -24,9 +24,9 @@
import org.junit.jupiter.api.extension.ExtensionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.data.elasticsearch.support.VersionInfo;
import org.springframework.lang.Nullable;
import org.testcontainers.elasticsearch.ElasticsearchContainer;
+import org.testcontainers.utility.DockerImageName;
/**
* This class manages the connection to an Elasticsearch Cluster, starting a containerized one if necessary. The
@@ -40,9 +40,10 @@ public class ClusterConnection implements ExtensionContext.Store.CloseableResour
private static final Logger LOGGER = LoggerFactory.getLogger(ClusterConnection.class);
+ private static final String SDE_TESTCONTAINER_IMAGE_NAME = "sde.testcontainers.image-name";
+ private static final String SDE_TESTCONTAINER_IMAGE_VERSION = "sde.testcontainers.image-version";
private static final int ELASTICSEARCH_DEFAULT_PORT = 9200;
private static final int ELASTICSEARCH_DEFAULT_TRANSPORT_PORT = 9300;
- private static final String ELASTICSEARCH_DEFAULT_IMAGE = "docker.elastic.co/elasticsearch/elasticsearch";
private static final ThreadLocal clusterConnectionInfoThreadLocal = new ThreadLocal<>();
@@ -78,20 +79,27 @@ public ClusterConnectionInfo getClusterConnectionInfo() {
@Nullable
private ClusterConnectionInfo startElasticsearchContainer() {
- LOGGER.debug("Starting Elasticsearch Container");
+ LOGGER.info("Starting Elasticsearch Container...");
try {
- String elasticsearchVersion = VersionInfo.versionProperties()
- .getProperty(VersionInfo.VERSION_ELASTICSEARCH_CLIENT);
- Map elasticsearchProperties = elasticsearchProperties();
+ IntegrationtestEnvironment integrationtestEnvironment = IntegrationtestEnvironment.get();
+ LOGGER.info("Integration test environment: {}", integrationtestEnvironment);
+ if (integrationtestEnvironment == IntegrationtestEnvironment.UNDEFINED) {
+ throw new IllegalArgumentException(IntegrationtestEnvironment.SYSTEM_PROPERTY + " property not set");
+ }
+
+ String testcontainersConfiguration = integrationtestEnvironment.name().toLowerCase();
+ Map testcontainersProperties = testcontainersProperties(
+ "testcontainers-" + testcontainersConfiguration + ".properties");
- String dockerImageName = ELASTICSEARCH_DEFAULT_IMAGE + ':' + elasticsearchVersion;
- LOGGER.debug("Docker image: {}", dockerImageName);
+ DockerImageName dockerImageName = getDockerImageName(testcontainersProperties);
- ElasticsearchContainer elasticsearchContainer = new ElasticsearchContainer(dockerImageName);
- elasticsearchContainer.withEnv(elasticsearchProperties);
+ ElasticsearchContainer elasticsearchContainer = new ElasticsearchContainer(dockerImageName)
+ .withEnv(testcontainersProperties);
elasticsearchContainer.start();
+
return ClusterConnectionInfo.builder() //
+ .withIntegrationtestEnvironment(integrationtestEnvironment)
.withHostAndPort(elasticsearchContainer.getHost(),
elasticsearchContainer.getMappedPort(ELASTICSEARCH_DEFAULT_PORT)) //
.withTransportPort(elasticsearchContainer.getMappedPort(ELASTICSEARCH_DEFAULT_TRANSPORT_PORT)) //
@@ -104,9 +112,32 @@ private ClusterConnectionInfo startElasticsearchContainer() {
return null;
}
- private Map elasticsearchProperties() {
+ private DockerImageName getDockerImageName(Map testcontainersProperties) {
+
+ String imageName = testcontainersProperties.get(SDE_TESTCONTAINER_IMAGE_NAME);
+ String imageVersion = testcontainersProperties.get(SDE_TESTCONTAINER_IMAGE_VERSION);
+
+ if (imageName == null) {
+ throw new IllegalArgumentException("property " + SDE_TESTCONTAINER_IMAGE_NAME + " not configured");
+ }
+ testcontainersProperties.remove(SDE_TESTCONTAINER_IMAGE_NAME);
+
+ if (imageVersion == null) {
+ throw new IllegalArgumentException("property " + SDE_TESTCONTAINER_IMAGE_VERSION + " not configured");
+ }
+ testcontainersProperties.remove(SDE_TESTCONTAINER_IMAGE_VERSION);
+
+ String configuredImageName = imageName + ':' + imageVersion;
+ DockerImageName dockerImageName = DockerImageName.parse(configuredImageName)
+ .asCompatibleSubstituteFor("docker.elastic.co/elasticsearch/elasticsearch");
+ LOGGER.info("Docker image: {}", dockerImageName);
+ return dockerImageName;
+ }
+
+ private Map testcontainersProperties(String propertiesFile) {
+
+ LOGGER.info("load configuration from {}", propertiesFile);
- String propertiesFile = "testcontainers-elasticsearch.properties";
try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(propertiesFile)) {
Properties props = new Properties();
diff --git a/src/test/java/org/springframework/data/elasticsearch/junit/jupiter/ClusterConnectionInfo.java b/src/test/java/org/springframework/data/elasticsearch/junit/jupiter/ClusterConnectionInfo.java
index ee4217809..307e5e033 100644
--- a/src/test/java/org/springframework/data/elasticsearch/junit/jupiter/ClusterConnectionInfo.java
+++ b/src/test/java/org/springframework/data/elasticsearch/junit/jupiter/ClusterConnectionInfo.java
@@ -25,10 +25,11 @@
* with a rest client for both a local started cluster and for one defined by the cluster URL when creating the
* {@link ClusterConnection}.
* The object must be created by using a {@link ClusterConnectionInfo.Builder}.
- *
+ *
* @author Peter-Josef Meisch
*/
public final class ClusterConnectionInfo {
+ private final IntegrationtestEnvironment integrationtestEnvironment;
private final boolean useSsl;
private final String host;
private final int httpPort;
@@ -40,8 +41,9 @@ public static Builder builder() {
return new Builder();
}
- private ClusterConnectionInfo(String host, int httpPort, boolean useSsl, int transportPort,
- @Nullable ElasticsearchContainer elasticsearchContainer) {
+ private ClusterConnectionInfo(IntegrationtestEnvironment integrationtestEnvironment, String host, int httpPort,
+ boolean useSsl, int transportPort, @Nullable ElasticsearchContainer elasticsearchContainer) {
+ this.integrationtestEnvironment = integrationtestEnvironment;
this.host = host;
this.httpPort = httpPort;
this.useSsl = useSsl;
@@ -53,7 +55,8 @@ private ClusterConnectionInfo(String host, int httpPort, boolean useSsl, int tra
@Override
public String toString() {
return "ClusterConnectionInfo{" + //
- "useSsl=" + useSsl + //
+ "configuration: " + integrationtestEnvironment + //
+ ", useSsl=" + useSsl + //
", host='" + host + '\'' + //
", httpPort=" + httpPort + //
", transportPort=" + transportPort + //
@@ -86,14 +89,22 @@ public ElasticsearchContainer getElasticsearchContainer() {
}
public static class Builder {
- boolean useSsl = false;
+ private IntegrationtestEnvironment integrationtestEnvironment;
+ private boolean useSsl = false;
private String host;
private int httpPort;
private int transportPort;
@Nullable private ElasticsearchContainer elasticsearchContainer;
+ public Builder withIntegrationtestEnvironment(IntegrationtestEnvironment integrationtestEnvironment) {
+ this.integrationtestEnvironment = integrationtestEnvironment;
+ return this;
+ }
+
public Builder withHostAndPort(String host, int httpPort) {
+
Assert.hasLength(host, "host must not be empty");
+
this.host = host;
this.httpPort = httpPort;
return this;
@@ -115,7 +126,8 @@ public Builder withElasticsearchContainer(ElasticsearchContainer elasticsearchCo
}
public ClusterConnectionInfo build() {
- return new ClusterConnectionInfo(host, httpPort, useSsl, transportPort, elasticsearchContainer);
+ return new ClusterConnectionInfo(integrationtestEnvironment, host, httpPort, useSsl, transportPort,
+ elasticsearchContainer);
}
}
}
diff --git a/src/test/java/org/springframework/data/elasticsearch/junit/jupiter/IntegrationtestEnvironment.java b/src/test/java/org/springframework/data/elasticsearch/junit/jupiter/IntegrationtestEnvironment.java
new file mode 100644
index 000000000..5db8bc7fc
--- /dev/null
+++ b/src/test/java/org/springframework/data/elasticsearch/junit/jupiter/IntegrationtestEnvironment.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 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
+ *
+ * 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;
+
+/**
+ * @author Peter-Josef Meisch
+ */
+public enum IntegrationtestEnvironment {
+
+ ELASTICSEARCH, OPENSEARCH, UNDEFINED;
+
+ public static final String SYSTEM_PROPERTY = "sde.integration-test.environment";
+
+ public static IntegrationtestEnvironment get() {
+
+ String property = System.getProperty(SYSTEM_PROPERTY, "elasticsearch");
+ switch (property.toUpperCase()) {
+ case "ELASTICSEARCH":
+ return ELASTICSEARCH;
+ case "OPENSEARCH":
+ return OPENSEARCH;
+ default:
+ return UNDEFINED;
+ }
+ }
+}
diff --git a/src/test/resources/testcontainers-elasticsearch.properties b/src/test/resources/testcontainers-elasticsearch.properties
index 5bef8c62b..2ca3d43e3 100644
--- a/src/test/resources/testcontainers-elasticsearch.properties
+++ b/src/test/resources/testcontainers-elasticsearch.properties
@@ -1,2 +1,10 @@
-# needed as we do a DELETE /* at the end of the tests, will be requited from 8.0 on, produces a warning since 7.13
+#
+# properties defining the image, these are not passed to the container on startup
+#
+sde.testcontainers.image-name=docker.elastic.co/elasticsearch/elasticsearch
+sde.testcontainers.image-version=7.13.3
+#
+#
+# needed as we do a DELETE /* at the end of the tests, will be required from 8.0 on, produces a warning since 7.13
+#
action.destructive_requires_name=false
diff --git a/src/test/resources/testcontainers-opensearch.properties b/src/test/resources/testcontainers-opensearch.properties
new file mode 100644
index 000000000..147af3ce5
--- /dev/null
+++ b/src/test/resources/testcontainers-opensearch.properties
@@ -0,0 +1,10 @@
+#
+# properties defining the image, these are not passed to the container on startup
+#
+sde.testcontainers.image-name=opensearchproject/opensearch
+sde.testcontainers.image-version=1.0.0
+#
+#
+# Opensearch as default has TLS and Basic auth enabled, we do not want this here, Testcontainers cannot ignore self signed certificates
+#
+plugins.security.disabled=true