Skip to content

Commit 2dab879

Browse files
committed
support as a repeatable annotation
1 parent f8b25f5 commit 2dab879

File tree

7 files changed

+160
-23
lines changed

7 files changed

+160
-23
lines changed

README.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Spring Test Elasticsearch
22

3+
image:https://codecov.io/gh/jupiter-tools/spring-test-elasticsearch/branch/master/graph/badge.svg["", link="https://codecov.io/gh/jupiter-tools/spring-test-elasticsearch"]
4+
5+
36
Tools to write integration tests of Spring Framework with the Elasticsearch.
47

58
## How to write integration tests on Spring Boot with Elasticsearch in docker

src/main/java/com/jupitertools/springtestelasticsearch/ElasticsearchTestContainer.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33

44
import java.lang.annotation.ElementType;
5+
import java.lang.annotation.Repeatable;
56
import java.lang.annotation.Retention;
67
import java.lang.annotation.RetentionPolicy;
78
import java.lang.annotation.Target;
@@ -14,7 +15,10 @@
1415
*/
1516
@Retention(RetentionPolicy.RUNTIME)
1617
@Target(ElementType.TYPE)
18+
@Repeatable(ElasticsearchTestContainers.class)
1719
public @interface ElasticsearchTestContainer {
1820

21+
String clusterNodesPropertyHolder() default "spring.data.elasticsearch.cluster-nodes";
1922

23+
String clusterNamePropertyHolder() default "spring.data.elasticsearch.cluster-name";
2024
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.jupitertools.springtestelasticsearch;
2+
3+
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+
/**
10+
* Created on 2019-05-24
11+
* <p>
12+
* This annotation provide an ability to use the @{@link ElasticsearchTestContainer}
13+
* annotation as a repeatable annotation.
14+
*
15+
* @author Korovin Anatoliy
16+
*/
17+
@Retention(RetentionPolicy.RUNTIME)
18+
@Target(ElementType.TYPE)
19+
public @interface ElasticsearchTestContainers {
20+
21+
ElasticsearchTestContainer[] value();
22+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.jupitertools.springtestelasticsearch.customizer;
2+
3+
import java.util.Objects;
4+
5+
/**
6+
* Created on 28/11/2019
7+
* <p>
8+
* TODO: replace on the JavaDoc
9+
*
10+
* @author Korovin Anatoliy
11+
*/
12+
public class ContainerDescription {
13+
14+
private final String clusterNodes;
15+
private final String clusterName;
16+
17+
public ContainerDescription(String clusterNodes, String clusterName) {
18+
this.clusterNodes = clusterNodes;
19+
this.clusterName = clusterName;
20+
}
21+
22+
public String getClusterNodes() {
23+
return clusterNodes;
24+
}
25+
26+
public String getClusterName() {
27+
return clusterName;
28+
}
29+
30+
@Override
31+
public boolean equals(Object o) {
32+
if (this == o) { return true; }
33+
if (o == null || getClass() != o.getClass()) { return false; }
34+
ContainerDescription that = (ContainerDescription) o;
35+
return Objects.equals(clusterNodes, that.clusterNodes) &&
36+
Objects.equals(clusterName, that.clusterName);
37+
}
38+
39+
@Override
40+
public int hashCode() {
41+
return Objects.hash(clusterNodes, clusterName);
42+
}
43+
}

src/main/java/com/jupitertools/springtestelasticsearch/customizer/ElasticsearchContextCustomizer.java

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package com.jupitertools.springtestelasticsearch.customizer;
22

33
import java.time.Duration;
4+
import java.util.Objects;
5+
import java.util.Random;
6+
import java.util.Set;
47

58
import org.slf4j.Logger;
69
import org.slf4j.LoggerFactory;
@@ -26,8 +29,15 @@
2629
*/
2730
public class ElasticsearchContextCustomizer implements ContextCustomizer {
2831

29-
private static final Logger log = LoggerFactory.getLogger(ElasticsearchContextCustomizer.class);
3032
private static final String DOCKER_IMAGE_NAME = "docker.elastic.co/elasticsearch/elasticsearch:6.4.1";
33+
private static final Logger log = LoggerFactory.getLogger(ElasticsearchContextCustomizer.class);
34+
35+
private final Set<ContainerDescription> containerDescriptions;
36+
37+
38+
public ElasticsearchContextCustomizer(Set<ContainerDescription> descriptions) {
39+
this.containerDescriptions = descriptions;
40+
}
3141

3242
@Override
3343
public void customizeContext(ConfigurableApplicationContext configurableApplicationContext,
@@ -39,28 +49,48 @@ public void customizeContext(ConfigurableApplicationContext configurableApplicat
3949
response == HTTP_UNAUTHORIZED)
4050
.withStartupTimeout(Duration.ofMinutes(2));
4151

42-
GenericContainer container =
43-
new FixedHostPortGenericContainer<>(DOCKER_IMAGE_NAME)
44-
.withExposedPorts(9200, 9300)
45-
.withEnv("cluster.name", "test_cluster")
46-
.withEnv("discovery.type", "single-node")
47-
.waitingFor(waitStrategy);
52+
for (ContainerDescription description : containerDescriptions) {
53+
54+
String clusterName = "test_cluster_" + new Random().nextInt(1000000);
4855

49-
log.debug("Starting Elasticsearch TestContainer");
50-
container.start();
51-
log.debug("Started Elasticsearch TestContainer at:[{}]", getHostPort(container));
56+
GenericContainer container =
57+
new FixedHostPortGenericContainer<>(DOCKER_IMAGE_NAME)
58+
.withExposedPorts(9200, 9300)
59+
.withEnv("cluster.name", clusterName)
60+
.withEnv("discovery.type", "single-node")
61+
.waitingFor(waitStrategy);
5262

53-
TestPropertyValues testPropertyValues =
54-
TestPropertyValues.of(
55-
"spring.data.elasticsearch.cluster-nodes=" + getHostPort(container),
56-
"spring.data.elasticsearch.cluster-name=" + "test_cluster");
63+
log.info("Starting Elasticsearch TestContainer");
64+
container.start();
65+
log.info("Started Elasticsearch TestContainer at:[{}] and bind to [{}]",
66+
getHostPort(container),
67+
description.getClusterNodes());
5768

58-
testPropertyValues.applyTo(configurableApplicationContext);
69+
TestPropertyValues testPropertyValues =
70+
TestPropertyValues.of(
71+
description.getClusterNodes() + "=" + getHostPort(container),
72+
description.getClusterName() + "=" + clusterName);
73+
74+
testPropertyValues.applyTo(configurableApplicationContext);
75+
}
5976
}
6077

6178
private String getHostPort(GenericContainer container) {
6279
return String.format("%s:%s",
6380
container.getContainerIpAddress(),
6481
container.getMappedPort(9300));
6582
}
83+
84+
@Override
85+
public boolean equals(Object o) {
86+
if (this == o) { return true; }
87+
if (o == null || getClass() != o.getClass()) { return false; }
88+
ElasticsearchContextCustomizer that = (ElasticsearchContextCustomizer) o;
89+
return Objects.equals(containerDescriptions, that.containerDescriptions);
90+
}
91+
92+
@Override
93+
public int hashCode() {
94+
return Objects.hash(containerDescriptions);
95+
}
6696
}

src/main/java/com/jupitertools/springtestelasticsearch/customizer/ElasticsearchContextCustomizerFactory.java

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package com.jupitertools.springtestelasticsearch.customizer;
22

33
import java.util.List;
4+
import java.util.Set;
5+
import java.util.stream.Collectors;
46

57
import com.jupitertools.springtestelasticsearch.ElasticsearchTestContainer;
8+
import com.jupitertools.springtestelasticsearch.ElasticsearchTestContainers;
69

710
import org.springframework.core.annotation.AnnotationUtils;
811
import org.springframework.test.context.ContextConfigurationAttributes;
@@ -23,14 +26,17 @@ public class ElasticsearchContextCustomizerFactory implements ContextCustomizerF
2326
public ContextCustomizer createContextCustomizer(Class<?> testClass,
2427
List<ContextConfigurationAttributes> list) {
2528

26-
ElasticsearchTestContainer annotation =
27-
AnnotationUtils.getAnnotation(testClass, ElasticsearchTestContainer.class);
29+
Set<ElasticsearchTestContainer> annotations =
30+
AnnotationUtils.getRepeatableAnnotations(testClass,
31+
ElasticsearchTestContainer.class,
32+
ElasticsearchTestContainers.class);
2833

29-
if (annotation != null) {
30-
return new ElasticsearchContextCustomizer();
31-
} else {
32-
// nothing to customize
33-
return null;
34-
}
34+
Set<ContainerDescription> descriptions =
35+
annotations.stream()
36+
.map(annotation -> new ContainerDescription(annotation.clusterNodesPropertyHolder(),
37+
annotation.clusterNamePropertyHolder()))
38+
.collect(Collectors.toSet());
39+
40+
return new ElasticsearchContextCustomizer(descriptions);
3541
}
3642
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.jupitertools.springtestelasticsearch;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import org.springframework.beans.factory.annotation.Value;
6+
import org.springframework.boot.test.context.SpringBootTest;
7+
8+
/**
9+
* Created on 28/11/2019
10+
*
11+
* @author Korovin Anatoliy
12+
*/
13+
@ElasticsearchTestContainer(clusterNodesPropertyHolder = "es.nodes",
14+
clusterNamePropertyHolder = "es.name")
15+
@SpringBootTest
16+
class SecondTest {
17+
18+
@Value("${es.nodes}")
19+
private String nodes;
20+
21+
@Value("${es.name}")
22+
private String name;
23+
24+
@Test
25+
void name() {
26+
System.out.println("nodes: " + nodes);
27+
System.out.println("name: " + name);
28+
}
29+
}

0 commit comments

Comments
 (0)