Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 24 additions & 39 deletions compliance/elasticsearch/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,29 @@
<artifactId>rdf4j-elasticsearch-compliance</artifactId>
<name>RDF4J: Elasticsearch Sail Tests</name>
<description>Tests for Elasticsearch.</description>
<properties>
<testcontainers.version>1.19.7</testcontainers.version>
</properties>
<!-- disable the Java security manager for elasticsearch tests -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<elasticsearch.docker.version>${elasticsearch.version}</elasticsearch.docker.version>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<forkCount>0</forkCount>
<systemPropertyVariables>
<tests.security.manager>false</tests.security.manager>
<elasticsearch.docker.version>${elasticsearch.version}</elasticsearch.docker.version>
</systemPropertyVariables>
</configuration>
</plugin>
Expand All @@ -37,34 +50,6 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-test-framework</artifactId>
<version>${lucene.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.elasticsearch.test</groupId>
<artifactId>framework</artifactId>
<version>${elasticsearch.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
Expand Down Expand Up @@ -100,20 +85,20 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>${elasticsearch.version}</version>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>${testcontainers.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${testcontainers.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>com.vividsolutions</groupId>
<artifactId>jts</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<groupId>co.elastic.clients</groupId>
<artifactId>elasticsearch-java</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*******************************************************************************
* Copyright (c) 2025 Eclipse RDF4J contributors.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*******************************************************************************/
// Some portions generated by Codex
package org.eclipse.rdf4j.sail.elasticsearch;

import java.util.concurrent.TimeUnit;

import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.BeforeAll;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.HealthStatus;
import co.elastic.clients.elasticsearch.cluster.HealthResponse;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;

@Testcontainers(disabledWithoutDocker = true)
public abstract class AbstractElasticsearchTest {

protected static final String CLUSTER_NAME = "test";

@Container
public static final GenericContainer<?> elasticsearch = new GenericContainer<>(dockerImageName())
.withEnv("discovery.type", "single-node")
.withEnv("cluster.name", CLUSTER_NAME)
.withEnv("ES_JAVA_OPTS",
"-Djdk.disableLastUsageTracking=true -XX:-UseContainerSupport -Xms512m -Xmx512m")
.withEnv("JDK_JAVA_OPTIONS",
"-Djdk.disableLastUsageTracking=true -XX:-UseContainerSupport -Xms512m -Xmx512m")
.withEnv("JAVA_TOOL_OPTIONS",
"-Djdk.disableLastUsageTracking=true -XX:-UseContainerSupport -Xms512m -Xmx512m")
.withExposedPorts(9200, 9300);

protected static RestClient lowLevelClient;
protected static ElasticsearchTransport transport;
protected static ElasticsearchClient client;
protected static String host;
protected static int httpPort;

@BeforeAll
public static void setUpCluster() throws Exception {
System.out.println("Setting up elasticsearch cluster");
if (client != null) {
return;
}

Assumptions.assumeTrue(elasticsearch.isRunning(),
"Elasticsearch test container failed to start:\n" + safeLogs());

host = elasticsearch.getHost();
httpPort = elasticsearch.getMappedPort(9200);

lowLevelClient = RestClient.builder(new HttpHost(host, httpPort, "http")).build();
transport = new RestClientTransport(lowLevelClient, new JacksonJsonpMapper());
client = new ElasticsearchClient(transport);

waitForClusterReady(client);
}

@AfterAll
public static void tearDownCluster() {
if (client != null) {
try {
lowLevelClient.close();
} catch (Exception e) {
// ignore during shutdown
}
client = null;
transport = null;
lowLevelClient = null;
}
}

private static DockerImageName dockerImageName() {
String esVersion = System.getProperty("elasticsearch.docker.version",
System.getProperty("elasticsearch.version", "7.15.2"));

return DockerImageName
.parse("docker.elastic.co/elasticsearch/elasticsearch:" + esVersion)
.asCompatibleSubstituteFor("docker.elastic.co/elasticsearch/elasticsearch");
}

private static void waitForClusterReady(ElasticsearchClient client) {
if (!elasticsearch.isRunning()) {
throw new IllegalStateException("Elasticsearch test container stopped before health check:\n" + safeLogs());
}

long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(180);
Exception lastFailure = null;

while (System.nanoTime() < deadline) {
if (!elasticsearch.isRunning()) {
throw new IllegalStateException(
"Elasticsearch test container stopped during health check:\n" + safeLogs());
}
try {
HealthResponse response = client.cluster()
.health(h -> h.waitForStatus(HealthStatus.Yellow).timeout(t -> t.time("1s")));
if (!response.timedOut()) {
return;
}
lastFailure = new IllegalStateException("Cluster health timed out waiting for YELLOW status");
} catch (Exception e) {
lastFailure = e;
}

try {
Thread.sleep(100);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw new IllegalStateException("Interrupted while waiting for Elasticsearch test cluster", ie);
}
}

throw new IllegalStateException("Timed out waiting for Elasticsearch test cluster", lastFailure);
}

private static String safeLogs() {
try {
return elasticsearch.getLogs();
} catch (Exception e) {
return "Unable to read container logs: " + e.getMessage();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*******************************************************************************
* Copyright (c) 2025 Eclipse RDF4J contributors.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*******************************************************************************/
// Some portions generated by Codex
package org.eclipse.rdf4j.sail.elasticsearch;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;

import java.util.Properties;

import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.ValueFactory;
import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
import org.junit.jupiter.api.Test;

public class ElasticsearchIndexHttpTest extends AbstractElasticsearchTest {

private static final ValueFactory VF = SimpleValueFactory.getInstance();

@Test
public void initializeAndIndexOverHttpEndpoint() {
Properties props = new Properties();
props.put(ElasticsearchIndex.TRANSPORT_KEY,
elasticsearch.getHost() + ":" + elasticsearch.getMappedPort(9200));
props.put(ElasticsearchIndex.ELASTICSEARCH_KEY_PREFIX + "cluster.name", CLUSTER_NAME);
props.put(ElasticsearchIndex.INDEX_NAME_KEY, ElasticsearchTestUtils.getNextTestIndexName());
props.put(ElasticsearchIndex.WAIT_FOR_STATUS_KEY, "yellow");

IRI subject = VF.createIRI("urn:subj-http");
IRI predicate = VF.createIRI("urn:pred-http");

ElasticsearchIndex index = new ElasticsearchIndex();

assertDoesNotThrow(() -> {
index.initialize(props);
try {
index.begin();
index.addStatement(VF.createStatement(subject, predicate, VF.createLiteral("value")));
index.commit();
} finally {
index.shutDown();
}
});
}
}
Loading
Loading