package org.testcontainers.containers; import org.rnorth.ducttape.inconsistents.Inconsistents; import org.rnorth.ducttape.ratelimits.RateLimiter; import org.rnorth.ducttape.ratelimits.RateLimiterBuilder; import java.sql.Connection; import java.sql.SQLException; import java.util.concurrent.TimeUnit; public class VirtuosoContainer<SELF extends VirtuosoContainer<SELF>> extends JdbcDatabaseContainer<SELF> { public static final String NAME = "virtuoso"; public static final String IMAGE = "tenforce/virtuoso"; public static final Integer JDBC_PORT = 1111; public static final Integer SPARQL_SERVICE_PORT = 8890; private static final RateLimiter LIVENESS_RATE_LIMITER = RateLimiterBuilder.newBuilder() .withConstantThroughput() .withRate(1, TimeUnit.SECONDS) .build(); public VirtuosoContainer() { super(IMAGE + ":1.0.0-virtuoso7.2.2"); } public VirtuosoContainer(String dockerImageName) { super(dockerImageName); } @Override protected void configure() { addExposedPort(JDBC_PORT); addExposedPort(SPARQL_SERVICE_PORT); addEnv("DBA_PASSWORD", getPassword()); addEnv("SPARQL_UPDATE", "true"); addEnv("DEFAULT_GRAPH", "http://localhost:8890/DAV"); addExposedPorts(JDBC_PORT, SPARQL_SERVICE_PORT); } @Override protected String getDriverClassName() { return "virtuoso.jdbc4.Driver"; } @Override public String getJdbcUrl() { return "jdbc:virtuoso://" + getContainerIpAddress() + ":" + getMappedPort(JDBC_PORT); } public String getSparqlUrl() { return "http://" + getContainerIpAddress() + ":" + getMappedPort(SPARQL_SERVICE_PORT) + "/sparql"; } @Override public String getUsername() { return "dba"; } @Override public String getPassword() { return "myDbaPassword"; } @Override protected String getTestQueryString() { return "SELECT 1"; } @Override protected Integer getLivenessCheckPort() { return getMappedPort(JDBC_PORT); } @Override protected void waitUntilContainerStarted() { // Repeatedly try and open a connection to the DB and execute a test query logger().info("Waiting for database connection to become available at {} using query '{}'", getJdbcUrl(), getTestQueryString()); // Wait for consecutive JDBC connection successes over a period of time. The Virtuoso container seems // to initially return a connection that fails on subsequent attempts, so wait for a consistently stable connection Inconsistents.retryUntilConsistent(5, 120, TimeUnit.SECONDS, () -> { //noinspection CodeBlock2Expr return LIVENESS_RATE_LIMITER.getWhenReady(() -> { if (!isRunning()) { throw new ContainerLaunchException("Container failed to start"); } try { Connection connection = createConnection(""); boolean success = connection.createStatement().execute(this.getTestQueryString()); if (success) { logger().info("Obtained a connection to container ({})", this.getJdbcUrl()); return true; } else { throw new SQLException("Failed to execute test query"); } } catch (SQLException e) { throw new ContainerLaunchException(e.getMessage()); } }); }); } }