Skip to content

Commit 4700995

Browse files
committed
GH-5498 initial test container commit
1 parent 8043b6d commit 4700995

32 files changed

Lines changed: 560 additions & 265 deletions

compliance/elasticsearch/pom.xml

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,29 @@
99
<artifactId>rdf4j-elasticsearch-compliance</artifactId>
1010
<name>RDF4J: Elasticsearch Sail Tests</name>
1111
<description>Tests for Elasticsearch.</description>
12+
<properties>
13+
<testcontainers.version>1.19.7</testcontainers.version>
14+
</properties>
1215
<!-- disable the Java security manager for elasticsearch tests -->
1316
<build>
1417
<plugins>
18+
<plugin>
19+
<groupId>org.apache.maven.plugins</groupId>
20+
<artifactId>maven-surefire-plugin</artifactId>
21+
<configuration>
22+
<systemPropertyVariables>
23+
<elasticsearch.docker.version>${elasticsearch.version}</elasticsearch.docker.version>
24+
</systemPropertyVariables>
25+
</configuration>
26+
</plugin>
1527
<plugin>
1628
<groupId>org.apache.maven.plugins</groupId>
1729
<artifactId>maven-failsafe-plugin</artifactId>
1830
<configuration>
1931
<forkCount>0</forkCount>
2032
<systemPropertyVariables>
2133
<tests.security.manager>false</tests.security.manager>
34+
<elasticsearch.docker.version>${elasticsearch.version}</elasticsearch.docker.version>
2235
</systemPropertyVariables>
2336
</configuration>
2437
</plugin>
@@ -37,34 +50,6 @@
3750
<version>${project.version}</version>
3851
<scope>test</scope>
3952
</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>
6853
<dependency>
6954
<groupId>org.apache.httpcomponents</groupId>
7055
<artifactId>httpcore</artifactId>
@@ -105,12 +90,26 @@
10590
<version>${elasticsearch.version}</version>
10691
<scope>test</scope>
10792
<exclusions>
93+
<exclusion>
94+
<groupId>commons-logging</groupId>
95+
<artifactId>commons-logging</artifactId>
96+
</exclusion>
10897
<exclusion>
10998
<groupId>com.vividsolutions</groupId>
11099
<artifactId>jts</artifactId>
111100
</exclusion>
101+
<exclusion>
102+
<groupId>org.elasticsearch</groupId>
103+
<artifactId>jna</artifactId>
104+
</exclusion>
112105
</exclusions>
113106
</dependency>
107+
<dependency>
108+
<groupId>org.testcontainers</groupId>
109+
<artifactId>testcontainers</artifactId>
110+
<version>${testcontainers.version}</version>
111+
<scope>test</scope>
112+
</dependency>
114113
<dependency>
115114
<groupId>org.apache.logging.log4j</groupId>
116115
<artifactId>log4j-core</artifactId>
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
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.AfterClass;
26+
import org.junit.Assume;
27+
import org.junit.BeforeClass;
28+
import org.testcontainers.containers.GenericContainer;
29+
import org.testcontainers.utility.DockerImageName;
30+
31+
public abstract class AbstractElasticsearchTest {
32+
33+
protected static final String CLUSTER_NAME = "test";
34+
35+
public static final GenericContainer<?> elasticsearch = new GenericContainer<>(dockerImageName())
36+
.withEnv("discovery.type", "single-node")
37+
.withEnv("cluster.name", CLUSTER_NAME)
38+
.withEnv("ES_JAVA_OPTS",
39+
"-Djdk.disableLastUsageTracking=true -XX:-UseContainerSupport -Xms512m -Xmx512m")
40+
.withEnv("JDK_JAVA_OPTIONS",
41+
"-Djdk.disableLastUsageTracking=true -XX:-UseContainerSupport -Xms512m -Xmx512m")
42+
.withEnv("JAVA_TOOL_OPTIONS",
43+
"-Djdk.disableLastUsageTracking=true -XX:-UseContainerSupport -Xms512m -Xmx512m")
44+
.withExposedPorts(9200, 9300);
45+
46+
protected static TransportClient client;
47+
48+
@BeforeClass
49+
public static void setUpCluster() throws Exception {
50+
System.out.println("Setting up elasticsearch cluster");
51+
if (client != null) {
52+
return;
53+
}
54+
55+
try {
56+
elasticsearch.start();
57+
} catch (IllegalStateException e) {
58+
Assume.assumeTrue("Docker is required to run Elasticsearch compliance tests:\n" + safeLogs(), false);
59+
}
60+
61+
if (!elasticsearch.isRunning()) {
62+
Assume.assumeTrue("Elasticsearch test container failed to stay running:\n" + safeLogs(), false);
63+
}
64+
65+
Settings settings = Settings.builder().put("cluster.name", CLUSTER_NAME).build();
66+
67+
String host = elasticsearch.getHost();
68+
int transportPort = elasticsearch.getMappedPort(9300);
69+
70+
TransportClient transportClient = new PreBuiltTransportClient(settings)
71+
.addTransportAddress(new TransportAddress(InetAddress.getByName(host), transportPort));
72+
73+
waitForClusterReady(transportClient);
74+
75+
client = transportClient;
76+
}
77+
78+
@AfterClass
79+
public static void tearDownCluster() {
80+
if (client != null) {
81+
client.close();
82+
client = null;
83+
}
84+
if (elasticsearch != null && elasticsearch.isRunning()) {
85+
elasticsearch.stop();
86+
}
87+
}
88+
89+
private static DockerImageName dockerImageName() {
90+
String esVersion = System.getProperty("elasticsearch.docker.version",
91+
System.getProperty("elasticsearch.version", "7.15.2"));
92+
93+
return DockerImageName
94+
.parse("docker.elastic.co/elasticsearch/elasticsearch:" + esVersion)
95+
.asCompatibleSubstituteFor("docker.elastic.co/elasticsearch/elasticsearch");
96+
}
97+
98+
private static void waitForClusterReady(Client client) {
99+
if (!elasticsearch.isRunning()) {
100+
throw new IllegalStateException("Elasticsearch test container stopped before health check:\n" + safeLogs());
101+
}
102+
103+
long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(180);
104+
Exception lastFailure = null;
105+
106+
while (System.nanoTime() < deadline) {
107+
if (!elasticsearch.isRunning()) {
108+
throw new IllegalStateException(
109+
"Elasticsearch test container stopped during health check:\n" + safeLogs());
110+
}
111+
try {
112+
ClusterHealthRequest request = new ClusterHealthRequest()
113+
.waitForYellowStatus()
114+
.timeout(TimeValue.timeValueSeconds(1));
115+
116+
ClusterHealthResponse response = client.admin().cluster().health(request).actionGet();
117+
if (!response.isTimedOut()) {
118+
return;
119+
}
120+
lastFailure = new IllegalStateException("Cluster health timed out waiting for YELLOW status");
121+
} catch (Exception e) {
122+
lastFailure = e;
123+
}
124+
125+
try {
126+
Thread.sleep(100);
127+
} catch (InterruptedException ie) {
128+
Thread.currentThread().interrupt();
129+
throw new IllegalStateException("Interrupted while waiting for Elasticsearch test cluster", ie);
130+
}
131+
}
132+
133+
throw new IllegalStateException("Timed out waiting for Elasticsearch test cluster", lastFailure);
134+
}
135+
136+
private static String safeLogs() {
137+
try {
138+
return elasticsearch.getLogs();
139+
} catch (Exception e) {
140+
return "Unable to read container logs: " + e.getMessage();
141+
}
142+
}
143+
}

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

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
*******************************************************************************/
1111
package org.eclipse.rdf4j.sail.elasticsearch;
1212

13+
import static org.junit.Assert.*;
14+
1315
import java.io.IOException;
14-
import java.util.Collection;
1516
import java.util.HashSet;
1617
import java.util.Iterator;
1718
import java.util.List;
@@ -29,21 +30,15 @@
2930
import org.eclipse.rdf4j.sail.lucene.SearchDocument;
3031
import org.eclipse.rdf4j.sail.lucene.SearchFields;
3132
import org.eclipse.rdf4j.sail.memory.MemoryStore;
32-
import org.elasticsearch.client.transport.TransportClient;
3333
import org.elasticsearch.index.query.QueryBuilders;
34-
import org.elasticsearch.index.reindex.ReindexPlugin;
35-
import org.elasticsearch.plugins.Plugin;
3634
import org.elasticsearch.search.SearchHit;
3735
import org.elasticsearch.search.SearchHits;
3836
import org.elasticsearch.search.builder.SearchSourceBuilder;
39-
import org.elasticsearch.test.ESIntegTestCase;
40-
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
4137
import org.junit.After;
4238
import org.junit.Before;
4339
import org.junit.Test;
4440

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

4843
private static final ValueFactory vf = SimpleValueFactory.getInstance();
4944

@@ -92,16 +87,10 @@ public class ElasticsearchIndexTest extends ESIntegTestCase {
9287

9388
Statement statementContext232 = vf.createStatement(subject2, predicate2, object5, CONTEXT_2);
9489

95-
TransportClient client;
96-
9790
ElasticsearchIndex index;
9891

9992
@Before
100-
@Override
10193
public void setUp() throws Exception {
102-
super.setUp();
103-
client = (TransportClient) internalCluster().transportClient();
104-
10594
Properties sailProperties = new Properties();
10695
sailProperties.put(ElasticsearchIndex.TRANSPORT_KEY, client.transportAddresses().get(0).toString());
10796
sailProperties.put(ElasticsearchIndex.ELASTICSEARCH_KEY_PREFIX + "cluster.name",
@@ -113,23 +102,12 @@ public void setUp() throws Exception {
113102
index.initialize(sailProperties);
114103
}
115104

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-
126105
@After
127-
@Override
128106
public void tearDown() throws Exception {
129107
try {
130108
index.shutDown();
131109
} finally {
132-
super.tearDown();
110+
index = null;
133111
}
134112

135113
org.eclipse.rdf4j.common.concurrent.locks.Properties.setLockTrackingEnabled(false);

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

Lines changed: 9 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,34 +10,22 @@
1010
*******************************************************************************/
1111
package org.eclipse.rdf4j.sail.elasticsearch;
1212

13-
import java.util.Collection;
14-
import java.util.List;
15-
1613
import org.eclipse.rdf4j.query.MalformedQueryException;
1714
import org.eclipse.rdf4j.query.QueryEvaluationException;
1815
import org.eclipse.rdf4j.repository.RepositoryException;
1916
import org.eclipse.rdf4j.sail.lucene.LuceneSail;
2017
import org.eclipse.testsuite.rdf4j.sail.lucene.AbstractLuceneSailGeoSPARQLTest;
21-
import org.elasticsearch.client.transport.TransportClient;
22-
import org.elasticsearch.index.reindex.ReindexPlugin;
23-
import org.elasticsearch.plugins.Plugin;
24-
import org.elasticsearch.test.ESIntegTestCase;
25-
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
26-
import org.junit.After;
27-
import org.junit.Before;
18+
import org.junit.AfterClass;
19+
import org.junit.BeforeClass;
2820
import org.junit.Ignore;
2921
import org.junit.Test;
3022

31-
@ClusterScope(numDataNodes = 1)
32-
public class ElasticsearchSailGeoSPARQLTest extends ESIntegTestCase {
23+
public class ElasticsearchSailGeoSPARQLTest extends AbstractElasticsearchTest {
3324

34-
AbstractLuceneSailGeoSPARQLTest delegateTest;
25+
private static AbstractLuceneSailGeoSPARQLTest delegateTest;
3526

36-
@Before
37-
@Override
38-
public void setUp() throws Exception {
39-
super.setUp();
40-
TransportClient client = (TransportClient) internalCluster().transportClient();
27+
@BeforeClass
28+
public static void setUpClass() throws Exception {
4129
delegateTest = new AbstractLuceneSailGeoSPARQLTest() {
4230

4331
@Override
@@ -54,23 +42,12 @@ protected void configure(LuceneSail sail) {
5442
delegateTest.setUp();
5543
}
5644

57-
@Override
58-
protected Collection<Class<? extends Plugin>> transportClientPlugins() {
59-
return List.of(ReindexPlugin.class);
60-
}
61-
62-
@Override
63-
protected Collection<Class<? extends Plugin>> nodePlugins() {
64-
return List.of(ReindexPlugin.class);
65-
}
66-
67-
@After
68-
@Override
69-
public void tearDown() throws Exception {
45+
@AfterClass
46+
public static void tearDownClass() throws Exception {
7047
try {
7148
delegateTest.tearDown();
7249
} finally {
73-
super.tearDown();
50+
delegateTest = null;
7451
}
7552
}
7653

0 commit comments

Comments
 (0)