Skip to content

Commit b67a1a7

Browse files
authored
GH-5498 migrate Elasticsearch tests to testcontainer (#5634)
2 parents 8043b6d + c82496e commit b67a1a7

54 files changed

Lines changed: 655 additions & 414 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

compliance/elasticsearch/pom.xml

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,23 @@
1212
<!-- disable the Java security manager for elasticsearch tests -->
1313
<build>
1414
<plugins>
15+
<plugin>
16+
<groupId>org.apache.maven.plugins</groupId>
17+
<artifactId>maven-surefire-plugin</artifactId>
18+
<configuration>
19+
<systemPropertyVariables>
20+
<elasticsearch.docker.version>${elasticsearch.version}</elasticsearch.docker.version>
21+
</systemPropertyVariables>
22+
</configuration>
23+
</plugin>
1524
<plugin>
1625
<groupId>org.apache.maven.plugins</groupId>
1726
<artifactId>maven-failsafe-plugin</artifactId>
1827
<configuration>
1928
<forkCount>0</forkCount>
2029
<systemPropertyVariables>
2130
<tests.security.manager>false</tests.security.manager>
31+
<elasticsearch.docker.version>${elasticsearch.version}</elasticsearch.docker.version>
2232
</systemPropertyVariables>
2333
</configuration>
2434
</plugin>
@@ -37,34 +47,6 @@
3747
<version>${project.version}</version>
3848
<scope>test</scope>
3949
</dependency>
40-
<dependency>
41-
<groupId>org.apache.lucene</groupId>
42-
<artifactId>lucene-test-framework</artifactId>
43-
<version>${lucene.version}</version>
44-
<scope>test</scope>
45-
<exclusions>
46-
<exclusion>
47-
<groupId>org.hamcrest</groupId>
48-
<artifactId>hamcrest-core</artifactId>
49-
</exclusion>
50-
</exclusions>
51-
</dependency>
52-
<dependency>
53-
<groupId>org.elasticsearch.test</groupId>
54-
<artifactId>framework</artifactId>
55-
<version>${elasticsearch.version}</version>
56-
<scope>test</scope>
57-
<exclusions>
58-
<exclusion>
59-
<groupId>commons-logging</groupId>
60-
<artifactId>commons-logging</artifactId>
61-
</exclusion>
62-
<exclusion>
63-
<groupId>org.apache.httpcomponents</groupId>
64-
<artifactId>httpcore</artifactId>
65-
</exclusion>
66-
</exclusions>
67-
</dependency>
6850
<dependency>
6951
<groupId>org.apache.httpcomponents</groupId>
7052
<artifactId>httpcore</artifactId>
@@ -105,12 +87,32 @@
10587
<version>${elasticsearch.version}</version>
10688
<scope>test</scope>
10789
<exclusions>
90+
<exclusion>
91+
<groupId>commons-logging</groupId>
92+
<artifactId>commons-logging</artifactId>
93+
</exclusion>
10894
<exclusion>
10995
<groupId>com.vividsolutions</groupId>
11096
<artifactId>jts</artifactId>
11197
</exclusion>
98+
<exclusion>
99+
<groupId>org.elasticsearch</groupId>
100+
<artifactId>jna</artifactId>
101+
</exclusion>
112102
</exclusions>
113103
</dependency>
104+
<dependency>
105+
<groupId>org.testcontainers</groupId>
106+
<artifactId>testcontainers</artifactId>
107+
<version>${testcontainers.version}</version>
108+
<scope>test</scope>
109+
</dependency>
110+
<dependency>
111+
<groupId>org.testcontainers</groupId>
112+
<artifactId>junit-jupiter</artifactId>
113+
<version>${testcontainers.version}</version>
114+
<scope>test</scope>
115+
</dependency>
114116
<dependency>
115117
<groupId>org.apache.logging.log4j</groupId>
116118
<artifactId>log4j-core</artifactId>
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Eclipse RDF4J contributors.
3+
*
4+
* All rights reserved. This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Distribution License v1.0
6+
* which accompanies this distribution, and is available at
7+
* http://www.eclipse.org/org/documents/edl-v10.php.
8+
*
9+
* SPDX-License-Identifier: BSD-3-Clause
10+
*******************************************************************************/
11+
// Some portions generated by Codex
12+
package org.eclipse.rdf4j.sail.elasticsearch;
13+
14+
import java.net.InetAddress;
15+
import java.util.concurrent.TimeUnit;
16+
17+
import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
18+
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
19+
import org.elasticsearch.client.Client;
20+
import org.elasticsearch.client.transport.TransportClient;
21+
import org.elasticsearch.common.settings.Settings;
22+
import org.elasticsearch.common.transport.TransportAddress;
23+
import org.elasticsearch.core.TimeValue;
24+
import org.elasticsearch.transport.client.PreBuiltTransportClient;
25+
import org.junit.jupiter.api.AfterAll;
26+
import org.junit.jupiter.api.Assumptions;
27+
import org.junit.jupiter.api.BeforeAll;
28+
import org.testcontainers.containers.GenericContainer;
29+
import org.testcontainers.junit.jupiter.Container;
30+
import org.testcontainers.junit.jupiter.Testcontainers;
31+
import org.testcontainers.utility.DockerImageName;
32+
33+
@Testcontainers(disabledWithoutDocker = true)
34+
public abstract class AbstractElasticsearchTest {
35+
36+
protected static final String CLUSTER_NAME = "test";
37+
38+
@Container
39+
public static final GenericContainer<?> elasticsearch = new GenericContainer<>(dockerImageName())
40+
.withEnv("discovery.type", "single-node")
41+
.withEnv("cluster.name", CLUSTER_NAME)
42+
.withEnv("ES_JAVA_OPTS",
43+
"-Djdk.disableLastUsageTracking=true -XX:-UseContainerSupport -Xms512m -Xmx512m")
44+
.withEnv("JDK_JAVA_OPTIONS",
45+
"-Djdk.disableLastUsageTracking=true -XX:-UseContainerSupport -Xms512m -Xmx512m")
46+
.withEnv("JAVA_TOOL_OPTIONS",
47+
"-Djdk.disableLastUsageTracking=true -XX:-UseContainerSupport -Xms512m -Xmx512m")
48+
.withExposedPorts(9200, 9300);
49+
50+
protected static TransportClient client;
51+
52+
@BeforeAll
53+
public static void setUpCluster() throws Exception {
54+
System.out.println("Setting up elasticsearch cluster");
55+
if (client != null) {
56+
return;
57+
}
58+
59+
Assumptions.assumeTrue(elasticsearch.isRunning(),
60+
"Elasticsearch test container failed to start:\n" + safeLogs());
61+
62+
Settings settings = Settings.builder().put("cluster.name", CLUSTER_NAME).build();
63+
64+
String host = elasticsearch.getHost();
65+
int transportPort = elasticsearch.getMappedPort(9300);
66+
67+
TransportClient transportClient = new PreBuiltTransportClient(settings)
68+
.addTransportAddress(new TransportAddress(InetAddress.getByName(host), transportPort));
69+
70+
waitForClusterReady(transportClient);
71+
72+
client = transportClient;
73+
}
74+
75+
@AfterAll
76+
public static void tearDownCluster() {
77+
if (client != null) {
78+
client.close();
79+
client = null;
80+
}
81+
}
82+
83+
private static DockerImageName dockerImageName() {
84+
String esVersion = System.getProperty("elasticsearch.docker.version",
85+
System.getProperty("elasticsearch.version", "7.15.2"));
86+
87+
return DockerImageName
88+
.parse("docker.elastic.co/elasticsearch/elasticsearch:" + esVersion)
89+
.asCompatibleSubstituteFor("docker.elastic.co/elasticsearch/elasticsearch");
90+
}
91+
92+
private static void waitForClusterReady(Client client) {
93+
if (!elasticsearch.isRunning()) {
94+
throw new IllegalStateException("Elasticsearch test container stopped before health check:\n" + safeLogs());
95+
}
96+
97+
long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(180);
98+
Exception lastFailure = null;
99+
100+
while (System.nanoTime() < deadline) {
101+
if (!elasticsearch.isRunning()) {
102+
throw new IllegalStateException(
103+
"Elasticsearch test container stopped during health check:\n" + safeLogs());
104+
}
105+
try {
106+
ClusterHealthRequest request = new ClusterHealthRequest()
107+
.waitForYellowStatus()
108+
.timeout(TimeValue.timeValueSeconds(1));
109+
110+
ClusterHealthResponse response = client.admin().cluster().health(request).actionGet();
111+
if (!response.isTimedOut()) {
112+
return;
113+
}
114+
lastFailure = new IllegalStateException("Cluster health timed out waiting for YELLOW status");
115+
} catch (Exception e) {
116+
lastFailure = e;
117+
}
118+
119+
try {
120+
Thread.sleep(100);
121+
} catch (InterruptedException ie) {
122+
Thread.currentThread().interrupt();
123+
throw new IllegalStateException("Interrupted while waiting for Elasticsearch test cluster", ie);
124+
}
125+
}
126+
127+
throw new IllegalStateException("Timed out waiting for Elasticsearch test cluster", lastFailure);
128+
}
129+
130+
private static String safeLogs() {
131+
try {
132+
return elasticsearch.getLogs();
133+
} catch (Exception e) {
134+
return "Unable to read container logs: " + e.getMessage();
135+
}
136+
}
137+
}

compliance/elasticsearch/src/test/java/org/eclipse/rdf4j/sail/elasticsearch/ElasticsearchIndexTest.java

Lines changed: 21 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,17 @@
88
*
99
* SPDX-License-Identifier: BSD-3-Clause
1010
*******************************************************************************/
11+
// Some portions generated by Codex
1112
package org.eclipse.rdf4j.sail.elasticsearch;
1213

14+
import static org.junit.jupiter.api.Assertions.assertEquals;
15+
import static org.junit.jupiter.api.Assertions.assertFalse;
16+
import static org.junit.jupiter.api.Assertions.assertNotNull;
17+
import static org.junit.jupiter.api.Assertions.assertNull;
18+
import static org.junit.jupiter.api.Assertions.assertTrue;
19+
import static org.junit.jupiter.api.Assertions.fail;
20+
1321
import java.io.IOException;
14-
import java.util.Collection;
1522
import java.util.HashSet;
1623
import java.util.Iterator;
1724
import java.util.List;
@@ -29,21 +36,15 @@
2936
import org.eclipse.rdf4j.sail.lucene.SearchDocument;
3037
import org.eclipse.rdf4j.sail.lucene.SearchFields;
3138
import org.eclipse.rdf4j.sail.memory.MemoryStore;
32-
import org.elasticsearch.client.transport.TransportClient;
3339
import org.elasticsearch.index.query.QueryBuilders;
34-
import org.elasticsearch.index.reindex.ReindexPlugin;
35-
import org.elasticsearch.plugins.Plugin;
3640
import org.elasticsearch.search.SearchHit;
3741
import org.elasticsearch.search.SearchHits;
3842
import org.elasticsearch.search.builder.SearchSourceBuilder;
39-
import org.elasticsearch.test.ESIntegTestCase;
40-
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
41-
import org.junit.After;
42-
import org.junit.Before;
43-
import org.junit.Test;
43+
import org.junit.jupiter.api.AfterEach;
44+
import org.junit.jupiter.api.BeforeEach;
45+
import org.junit.jupiter.api.Test;
4446

45-
@ClusterScope(numDataNodes = 1)
46-
public class ElasticsearchIndexTest extends ESIntegTestCase {
47+
public class ElasticsearchIndexTest extends AbstractElasticsearchTest {
4748

4849
private static final ValueFactory vf = SimpleValueFactory.getInstance();
4950

@@ -92,44 +93,27 @@ public class ElasticsearchIndexTest extends ESIntegTestCase {
9293

9394
Statement statementContext232 = vf.createStatement(subject2, predicate2, object5, CONTEXT_2);
9495

95-
TransportClient client;
96-
9796
ElasticsearchIndex index;
9897

99-
@Before
100-
@Override
98+
@BeforeEach
10199
public void setUp() throws Exception {
102-
super.setUp();
103-
client = (TransportClient) internalCluster().transportClient();
104-
105100
Properties sailProperties = new Properties();
106101
sailProperties.put(ElasticsearchIndex.TRANSPORT_KEY, client.transportAddresses().get(0).toString());
107102
sailProperties.put(ElasticsearchIndex.ELASTICSEARCH_KEY_PREFIX + "cluster.name",
108103
client.settings().get("cluster.name"));
109104
sailProperties.put(ElasticsearchIndex.INDEX_NAME_KEY, ElasticsearchTestUtils.getNextTestIndexName());
110-
sailProperties.put(ElasticsearchIndex.WAIT_FOR_STATUS_KEY, "green");
105+
sailProperties.put(ElasticsearchIndex.WAIT_FOR_STATUS_KEY, "yellow");
111106
sailProperties.put(ElasticsearchIndex.WAIT_FOR_NODES_KEY, ">=1");
112107
index = new ElasticsearchIndex();
113108
index.initialize(sailProperties);
114109
}
115110

116-
@Override
117-
protected Collection<Class<? extends Plugin>> transportClientPlugins() {
118-
return List.of(ReindexPlugin.class);
119-
}
120-
121-
@Override
122-
protected Collection<Class<? extends Plugin>> nodePlugins() {
123-
return List.of(ReindexPlugin.class);
124-
}
125-
126-
@After
127-
@Override
111+
@AfterEach
128112
public void tearDown() throws Exception {
129113
try {
130114
index.shutDown();
131115
} finally {
132-
super.tearDown();
116+
index = null;
133117
}
134118

135119
org.eclipse.rdf4j.common.concurrent.locks.Properties.setLockTrackingEnabled(false);
@@ -445,10 +429,10 @@ public void testRejectedDatatypes() {
445429
Literal literal2 = vf.createLiteral("hi there, too", STRING);
446430
Literal literal3 = vf.createLiteral("1.0");
447431
Literal literal4 = vf.createLiteral("1.0", FLOAT);
448-
assertTrue("Is the first literal accepted?", index.accept(literal1));
449-
assertTrue("Is the second literal accepted?", index.accept(literal2));
450-
assertTrue("Is the third literal accepted?", index.accept(literal3));
451-
assertFalse("Is the fourth literal accepted?", index.accept(literal4));
432+
assertTrue(index.accept(literal1), "Is the first literal accepted?");
433+
assertTrue(index.accept(literal2), "Is the second literal accepted?");
434+
assertTrue(index.accept(literal3), "Is the third literal accepted?");
435+
assertFalse(index.accept(literal4), "Is the fourth literal accepted?");
452436
}
453437

454438
private void assertStatement(Statement statement) throws Exception {
@@ -469,7 +453,7 @@ private void assertNoStatement(Statement statement) throws Exception {
469453

470454
private void assertStatement(Statement statement, SearchDocument document) {
471455
List<String> fields = document.getProperty(SearchFields.getPropertyField(statement.getPredicate()));
472-
assertNotNull("field " + statement.getPredicate() + " not found in document " + document, fields);
456+
assertNotNull(fields, "field " + statement.getPredicate() + " not found in document " + document);
473457
for (String f : fields) {
474458
if (((Literal) statement.getObject()).getLabel().equals(f)) {
475459
return;

0 commit comments

Comments
 (0)