Skip to content

Commit 1c8e0e0

Browse files
authored
Make integration tests configurable to use different containers.
Original Pull Request: #1888 Closes #1882
1 parent d80d920 commit 1c8e0e0

10 files changed

+214
-46
lines changed

pom.xml

+30-26
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@
2525
<testcontainers>1.15.3</testcontainers>
2626
<blockhound-junit>1.0.6.RELEASE</blockhound-junit>
2727
<java-module-name>spring.data.elasticsearch</java-module-name>
28+
29+
<!--
30+
properties defining the maven phase for the tests and integration tests
31+
set to "none" to disable the corresponding test execution (-Dmvn.unit-test.goal=none)
32+
default execution for unit-test: "test", for the integration tests: "integration-test"
33+
-->
34+
<mvn.unit-test.goal>test</mvn.unit-test.goal>
35+
<mvn.integration-test-elasticsearch.goal>integration-test</mvn.integration-test-elasticsearch.goal>
36+
<mvn.integration-test-opensearch.goal>none</mvn.integration-test-opensearch.goal>
2837
</properties>
2938

3039
<developers>
@@ -264,25 +273,6 @@
264273
<scope>test</scope>
265274
</dependency>
266275

267-
<!--
268-
<dependency>
269-
<groupId>org.apache.openwebbeans.test</groupId>
270-
<artifactId>cditest-owb</artifactId>
271-
<version>1.2.8</version>
272-
<scope>test</scope>
273-
<exclusions>
274-
<exclusion>
275-
<groupId>org.apache.geronimo.specs</groupId>
276-
<artifactId>geronimo-jcdi_1.0_spec</artifactId>
277-
</exclusion>
278-
<exclusion>
279-
<groupId>org.apache.geronimo.specs</groupId>
280-
<artifactId>geronimo-atinject_1.0_spec</artifactId>
281-
</exclusion>
282-
</exclusions>
283-
</dependency>
284-
-->
285-
286276
<dependency>
287277
<groupId>org.skyscreamer</groupId>
288278
<artifactId>jsonassert</artifactId>
@@ -365,9 +355,6 @@
365355
</resources>
366356

367357
<plugins>
368-
<!--
369-
please do not remove this configuration for surefire - we need that to avoid issue with jar hell
370-
-->
371358
<plugin>
372359
<groupId>org.apache.maven.plugins</groupId>
373360
<artifactId>maven-surefire-plugin</artifactId>
@@ -386,23 +373,40 @@
386373
<!-- the default-test execution runs only the unit tests -->
387374
<execution>
388375
<id>default-test</id>
389-
<phase>test</phase>
376+
<phase>${mvn.unit-test.goal}</phase>
390377
<goals>
391378
<goal>test</goal>
392379
</goals>
393380
<configuration>
394381
<excludedGroups>integration-test</excludedGroups>
395382
</configuration>
396383
</execution>
397-
<!-- execution to run the integration tests -->
384+
<!-- execution to run the integration tests against Elasticsearch -->
385+
<execution>
386+
<id>integration-test-elasticsearch</id>
387+
<phase>${mvn.integration-test-elasticsearch.goal}</phase>
388+
<goals>
389+
<goal>test</goal>
390+
</goals>
391+
<configuration>
392+
<groups>integration-test</groups>
393+
<systemPropertyVariables>
394+
<sde.integration-test.environment>elasticsearch</sde.integration-test.environment>
395+
</systemPropertyVariables>
396+
</configuration>
397+
</execution>
398+
<!-- execution to run the integration tests against Opensearch -->
398399
<execution>
399-
<id>integration-test</id>
400-
<phase>integration-test</phase>
400+
<id>integration-test-opensearch</id>
401+
<phase>${mvn.integration-test-opensearch.goal}</phase>
401402
<goals>
402403
<goal>test</goal>
403404
</goals>
404405
<configuration>
405406
<groups>integration-test</groups>
407+
<systemPropertyVariables>
408+
<sde.integration-test.environment>opensearch</sde.integration-test.environment>
409+
</systemPropertyVariables>
406410
</configuration>
407411
</execution>
408412
</executions>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package org.springframework.data.elasticsearch;
2+
3+
import java.lang.annotation.Documented;
4+
import java.lang.annotation.ElementType;
5+
import java.lang.annotation.Retention;
6+
import java.lang.annotation.RetentionPolicy;
7+
import java.lang.annotation.Target;
8+
9+
import org.junit.jupiter.api.Tag;
10+
11+
/**
12+
* @author Peter-Josef Meisch
13+
*/
14+
@Target({ ElementType.TYPE, ElementType.METHOD })
15+
@Retention(RetentionPolicy.RUNTIME)
16+
@Documented
17+
@Tag("foobar")
18+
public @interface Foobar {
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package org.springframework.data.elasticsearch;
2+
3+
import static org.assertj.core.api.Assertions.*;
4+
5+
import org.junit.jupiter.api.DisplayName;
6+
import org.junit.jupiter.api.Test;
7+
import org.slf4j.Logger;
8+
import org.slf4j.LoggerFactory;
9+
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
10+
11+
/**
12+
* @author Peter-Josef Meisch
13+
*/
14+
@SpringIntegrationTest
15+
@Foobar
16+
public abstract class FoobarIntegrationTest {
17+
18+
private final Logger LOGGER = LoggerFactory.getLogger(getClass());
19+
20+
@Test
21+
@DisplayName("should run test")
22+
void shouldRunTest() {
23+
24+
int answer = 42;
25+
26+
assertThat(answer).isEqualTo(42);
27+
}
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.springframework.data.elasticsearch;
2+
3+
import org.junit.jupiter.api.DisplayName;
4+
import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
5+
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchTemplateConfiguration;
6+
import org.springframework.data.elasticsearch.junit.jupiter.IntegrationtestEnvironment;
7+
import org.springframework.test.context.ContextConfiguration;
8+
9+
/**
10+
* This class should only run when the cluster is an Elasticsearch cluster.
11+
*
12+
* @author Peter-Josef Meisch
13+
*/
14+
@EnabledIfSystemProperty(named = IntegrationtestEnvironment.SYSTEM_PROPERTY, matches = "(?i)elasticsearch")
15+
@ContextConfiguration(classes = { ElasticsearchTemplateConfiguration.class })
16+
@DisplayName("foobar integration with transport client")
17+
public class TransportFoobarIntegrationTest extends FoobarIntegrationTest {}

src/test/java/org/springframework/data/elasticsearch/config/AuditingIntegrationTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ void shouldEnableAuditingAndSetAuditingDates() throws InterruptedException {
7373
assertThat(entity.getCreatedBy()).isEqualTo("Auditor 1");
7474
assertThat(entity.getModifiedBy()).isEqualTo("Auditor 1");
7575

76-
Thread.sleep(10);
76+
Thread.sleep(50);
7777

7878
entity = callbacks.callback(BeforeConvertCallback.class, entity, IndexCoordinates.of("index"));
7979

src/test/java/org/springframework/data/elasticsearch/junit/jupiter/ClusterConnection.java

+43-12
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@
2424
import org.junit.jupiter.api.extension.ExtensionContext;
2525
import org.slf4j.Logger;
2626
import org.slf4j.LoggerFactory;
27-
import org.springframework.data.elasticsearch.support.VersionInfo;
2827
import org.springframework.lang.Nullable;
2928
import org.testcontainers.elasticsearch.ElasticsearchContainer;
29+
import org.testcontainers.utility.DockerImageName;
3030

3131
/**
3232
* 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
4040

4141
private static final Logger LOGGER = LoggerFactory.getLogger(ClusterConnection.class);
4242

43+
private static final String SDE_TESTCONTAINER_IMAGE_NAME = "sde.testcontainers.image-name";
44+
private static final String SDE_TESTCONTAINER_IMAGE_VERSION = "sde.testcontainers.image-version";
4345
private static final int ELASTICSEARCH_DEFAULT_PORT = 9200;
4446
private static final int ELASTICSEARCH_DEFAULT_TRANSPORT_PORT = 9300;
45-
private static final String ELASTICSEARCH_DEFAULT_IMAGE = "docker.elastic.co/elasticsearch/elasticsearch";
4647

4748
private static final ThreadLocal<ClusterConnectionInfo> clusterConnectionInfoThreadLocal = new ThreadLocal<>();
4849

@@ -78,20 +79,27 @@ public ClusterConnectionInfo getClusterConnectionInfo() {
7879
@Nullable
7980
private ClusterConnectionInfo startElasticsearchContainer() {
8081

81-
LOGGER.debug("Starting Elasticsearch Container");
82+
LOGGER.info("Starting Elasticsearch Container...");
8283

8384
try {
84-
String elasticsearchVersion = VersionInfo.versionProperties()
85-
.getProperty(VersionInfo.VERSION_ELASTICSEARCH_CLIENT);
86-
Map<String, String> elasticsearchProperties = elasticsearchProperties();
85+
IntegrationtestEnvironment integrationtestEnvironment = IntegrationtestEnvironment.get();
86+
LOGGER.info("Integration test environment: {}", integrationtestEnvironment);
87+
if (integrationtestEnvironment == IntegrationtestEnvironment.UNDEFINED) {
88+
throw new IllegalArgumentException(IntegrationtestEnvironment.SYSTEM_PROPERTY + " property not set");
89+
}
90+
91+
String testcontainersConfiguration = integrationtestEnvironment.name().toLowerCase();
92+
Map<String, String> testcontainersProperties = testcontainersProperties(
93+
"testcontainers-" + testcontainersConfiguration + ".properties");
8794

88-
String dockerImageName = ELASTICSEARCH_DEFAULT_IMAGE + ':' + elasticsearchVersion;
89-
LOGGER.debug("Docker image: {}", dockerImageName);
95+
DockerImageName dockerImageName = getDockerImageName(testcontainersProperties);
9096

91-
ElasticsearchContainer elasticsearchContainer = new ElasticsearchContainer(dockerImageName);
92-
elasticsearchContainer.withEnv(elasticsearchProperties);
97+
ElasticsearchContainer elasticsearchContainer = new ElasticsearchContainer(dockerImageName)
98+
.withEnv(testcontainersProperties);
9399
elasticsearchContainer.start();
100+
94101
return ClusterConnectionInfo.builder() //
102+
.withIntegrationtestEnvironment(integrationtestEnvironment)
95103
.withHostAndPort(elasticsearchContainer.getHost(),
96104
elasticsearchContainer.getMappedPort(ELASTICSEARCH_DEFAULT_PORT)) //
97105
.withTransportPort(elasticsearchContainer.getMappedPort(ELASTICSEARCH_DEFAULT_TRANSPORT_PORT)) //
@@ -104,9 +112,32 @@ private ClusterConnectionInfo startElasticsearchContainer() {
104112
return null;
105113
}
106114

107-
private Map<String, String> elasticsearchProperties() {
115+
private DockerImageName getDockerImageName(Map<String, String> testcontainersProperties) {
116+
117+
String imageName = testcontainersProperties.get(SDE_TESTCONTAINER_IMAGE_NAME);
118+
String imageVersion = testcontainersProperties.get(SDE_TESTCONTAINER_IMAGE_VERSION);
119+
120+
if (imageName == null) {
121+
throw new IllegalArgumentException("property " + SDE_TESTCONTAINER_IMAGE_NAME + " not configured");
122+
}
123+
testcontainersProperties.remove(SDE_TESTCONTAINER_IMAGE_NAME);
124+
125+
if (imageVersion == null) {
126+
throw new IllegalArgumentException("property " + SDE_TESTCONTAINER_IMAGE_VERSION + " not configured");
127+
}
128+
testcontainersProperties.remove(SDE_TESTCONTAINER_IMAGE_VERSION);
129+
130+
String configuredImageName = imageName + ':' + imageVersion;
131+
DockerImageName dockerImageName = DockerImageName.parse(configuredImageName)
132+
.asCompatibleSubstituteFor("docker.elastic.co/elasticsearch/elasticsearch");
133+
LOGGER.info("Docker image: {}", dockerImageName);
134+
return dockerImageName;
135+
}
136+
137+
private Map<String, String> testcontainersProperties(String propertiesFile) {
138+
139+
LOGGER.info("load configuration from {}", propertiesFile);
108140

109-
String propertiesFile = "testcontainers-elasticsearch.properties";
110141
try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(propertiesFile)) {
111142
Properties props = new Properties();
112143

src/test/java/org/springframework/data/elasticsearch/junit/jupiter/ClusterConnectionInfo.java

+18-6
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,11 @@
2525
* with a rest client for both a local started cluster and for one defined by the cluster URL when creating the
2626
* {@link ClusterConnection}.<br/>
2727
* The object must be created by using a {@link ClusterConnectionInfo.Builder}.
28-
*
28+
*
2929
* @author Peter-Josef Meisch
3030
*/
3131
public final class ClusterConnectionInfo {
32+
private final IntegrationtestEnvironment integrationtestEnvironment;
3233
private final boolean useSsl;
3334
private final String host;
3435
private final int httpPort;
@@ -40,8 +41,9 @@ public static Builder builder() {
4041
return new Builder();
4142
}
4243

43-
private ClusterConnectionInfo(String host, int httpPort, boolean useSsl, int transportPort,
44-
@Nullable ElasticsearchContainer elasticsearchContainer) {
44+
private ClusterConnectionInfo(IntegrationtestEnvironment integrationtestEnvironment, String host, int httpPort,
45+
boolean useSsl, int transportPort, @Nullable ElasticsearchContainer elasticsearchContainer) {
46+
this.integrationtestEnvironment = integrationtestEnvironment;
4547
this.host = host;
4648
this.httpPort = httpPort;
4749
this.useSsl = useSsl;
@@ -53,7 +55,8 @@ private ClusterConnectionInfo(String host, int httpPort, boolean useSsl, int tra
5355
@Override
5456
public String toString() {
5557
return "ClusterConnectionInfo{" + //
56-
"useSsl=" + useSsl + //
58+
"configuration: " + integrationtestEnvironment + //
59+
", useSsl=" + useSsl + //
5760
", host='" + host + '\'' + //
5861
", httpPort=" + httpPort + //
5962
", transportPort=" + transportPort + //
@@ -86,14 +89,22 @@ public ElasticsearchContainer getElasticsearchContainer() {
8689
}
8790

8891
public static class Builder {
89-
boolean useSsl = false;
92+
private IntegrationtestEnvironment integrationtestEnvironment;
93+
private boolean useSsl = false;
9094
private String host;
9195
private int httpPort;
9296
private int transportPort;
9397
@Nullable private ElasticsearchContainer elasticsearchContainer;
9498

99+
public Builder withIntegrationtestEnvironment(IntegrationtestEnvironment integrationtestEnvironment) {
100+
this.integrationtestEnvironment = integrationtestEnvironment;
101+
return this;
102+
}
103+
95104
public Builder withHostAndPort(String host, int httpPort) {
105+
96106
Assert.hasLength(host, "host must not be empty");
107+
97108
this.host = host;
98109
this.httpPort = httpPort;
99110
return this;
@@ -115,7 +126,8 @@ public Builder withElasticsearchContainer(ElasticsearchContainer elasticsearchCo
115126
}
116127

117128
public ClusterConnectionInfo build() {
118-
return new ClusterConnectionInfo(host, httpPort, useSsl, transportPort, elasticsearchContainer);
129+
return new ClusterConnectionInfo(integrationtestEnvironment, host, httpPort, useSsl, transportPort,
130+
elasticsearchContainer);
119131
}
120132
}
121133
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.elasticsearch.junit.jupiter;
17+
18+
/**
19+
* @author Peter-Josef Meisch
20+
*/
21+
public enum IntegrationtestEnvironment {
22+
23+
ELASTICSEARCH, OPENSEARCH, UNDEFINED;
24+
25+
public static final String SYSTEM_PROPERTY = "sde.integration-test.environment";
26+
27+
public static IntegrationtestEnvironment get() {
28+
29+
String property = System.getProperty(SYSTEM_PROPERTY, "elasticsearch");
30+
switch (property.toUpperCase()) {
31+
case "ELASTICSEARCH":
32+
return ELASTICSEARCH;
33+
case "OPENSEARCH":
34+
return OPENSEARCH;
35+
default:
36+
return UNDEFINED;
37+
}
38+
}
39+
}
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,10 @@
1-
# 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
1+
#
2+
# properties defining the image, these are not passed to the container on startup
3+
#
4+
sde.testcontainers.image-name=docker.elastic.co/elasticsearch/elasticsearch
5+
sde.testcontainers.image-version=7.13.3
6+
#
7+
#
8+
# 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
9+
#
210
action.destructive_requires_name=false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#
2+
# properties defining the image, these are not passed to the container on startup
3+
#
4+
sde.testcontainers.image-name=opensearchproject/opensearch
5+
sde.testcontainers.image-version=1.0.0
6+
#
7+
#
8+
# Opensearch as default has TLS and Basic auth enabled, we do not want this here, Testcontainers cannot ignore self signed certificates
9+
#
10+
plugins.security.disabled=true

0 commit comments

Comments
 (0)