diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 27dd0c47e..a4bbfc881 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,6 +32,9 @@ jobs: - docker.io/arangodb/arangodb:3.12 - docker.io/arangodb/enterprise:3.11 - docker.io/arangodb/enterprise:3.12 + starter-docker-img: + # support activefailover + - docker.io/arangodb/arangodb-starter:0.18.5 topology: - single - cluster @@ -60,6 +63,7 @@ jobs: ARANGO_LICENSE_KEY: ${{ secrets.ARANGO_LICENSE_KEY }} STARTER_MODE: ${{matrix.topology}} DOCKER_IMAGE: ${{matrix.docker-img}} + STARTER_DOCKER_IMAGE: ${{matrix.starter-docker-img}} - name: Info run: mvn -version - name: Test @@ -127,6 +131,9 @@ jobs: matrix: docker-img: - docker.io/arangodb/enterprise:3.11 + starter-docker-img: + # support activefailover + - docker.io/arangodb/arangodb-starter:0.18.5 topology: - single - cluster @@ -150,6 +157,7 @@ jobs: ARANGO_LICENSE_KEY: ${{ secrets.ARANGO_LICENSE_KEY }} STARTER_MODE: ${{matrix.topology}} DOCKER_IMAGE: ${{matrix.docker-img}} + STARTER_DOCKER_IMAGE: ${{matrix.starter-docker-img}} - name: Set JWT run: | ENDPOINT=$(./docker/find_active_endpoint.sh) diff --git a/core/src/main/java/com/arangodb/ArangoDB.java b/core/src/main/java/com/arangodb/ArangoDB.java index 9a5cc430a..ad9b3bf43 100644 --- a/core/src/main/java/com/arangodb/ArangoDB.java +++ b/core/src/main/java/com/arangodb/ArangoDB.java @@ -23,6 +23,7 @@ import com.arangodb.arch.UnstableApi; import com.arangodb.config.ArangoConfigProperties; import com.arangodb.config.HostDescription; +import com.arangodb.config.ProtocolConfig; import com.arangodb.entity.*; import com.arangodb.internal.ArangoDBImpl; import com.arangodb.internal.ArangoExecutorSync; @@ -264,9 +265,9 @@ public interface ArangoDB extends ArangoSerdeAccessor { * * @param user The name of the user * @param permissions The permissions the user grant - * @since ArangoDB 3.2.0 * @see API * Documentation + * @since ArangoDB 3.2.0 */ void grantDefaultDatabaseAccess(String user, Permissions permissions); @@ -276,9 +277,9 @@ public interface ArangoDB extends ArangoSerdeAccessor { * * @param user The name of the user * @param permissions The permissions the user grant - * @since ArangoDB 3.2.0 * @see API * Documentation + * @since ArangoDB 3.2.0 */ void grantDefaultCollectionAccess(String user, Permissions permissions); @@ -313,9 +314,9 @@ public interface ArangoDB extends ArangoSerdeAccessor { * Returns the server's current loglevel settings. * * @return the server's current loglevel settings - * @since ArangoDB 3.1.0 * @see API * Documentation + * @since ArangoDB 3.1.0 */ LogLevelEntity getLogLevel(); @@ -323,9 +324,9 @@ public interface ArangoDB extends ArangoSerdeAccessor { * Returns the server's current loglevel settings. * * @return the server's current loglevel settings - * @since ArangoDB 3.10 * @see API * Documentation + * @since ArangoDB 3.10 */ LogLevelEntity getLogLevel(LogLevelOptions options); @@ -334,9 +335,9 @@ public interface ArangoDB extends ArangoSerdeAccessor { * * @param entity loglevel settings * @return the server's current loglevel settings - * @since ArangoDB 3.1.0 * @see API * Documentation + * @since ArangoDB 3.1.0 */ LogLevelEntity setLogLevel(LogLevelEntity entity); @@ -345,17 +346,17 @@ public interface ArangoDB extends ArangoSerdeAccessor { * * @param entity loglevel settings * @return the server's current loglevel settings - * @since ArangoDB 3.10 * @see API * Documentation + * @since ArangoDB 3.10 */ LogLevelEntity setLogLevel(LogLevelEntity entity, LogLevelOptions options); /** * @return the list of available rules and their respective flags - * @since ArangoDB 3.10 * @see API * Documentation + * @since ArangoDB 3.10 */ Collection getQueryOptimizerRules(); @@ -381,7 +382,7 @@ public ArangoDB build() { ProtocolProvider protocolProvider = protocolProvider(config.getProtocol()); config.setProtocolModule(protocolProvider.protocolModule()); - ConnectionFactory connectionFactory = protocolProvider.createConnectionFactory(); + ConnectionFactory connectionFactory = protocolProvider.createConnectionFactory(config.getProtocolConfig()); Collection hostList = createHostList(connectionFactory); HostResolver hostResolver = createHostResolver(hostList, connectionFactory); HostHandler hostHandler = createHostHandler(hostResolver); @@ -680,6 +681,15 @@ public Builder compressionLevel(Integer level) { return this; } + /** + * Configuration specific for {@link com.arangodb.internal.net.ProtocolProvider}. + * @return {@link ArangoDB.Builder} + */ + public Builder protocolConfig(ProtocolConfig protocolConfig) { + config.setProtocolConfig(protocolConfig); + return this; + } + @UnstableApi protected ProtocolProvider protocolProvider(Protocol protocol) { ServiceLoader loader = ServiceLoader.load(ProtocolProvider.class); diff --git a/core/src/main/java/com/arangodb/config/ArangoConfigProperties.java b/core/src/main/java/com/arangodb/config/ArangoConfigProperties.java index 47c464a1e..9690e5f4e 100644 --- a/core/src/main/java/com/arangodb/config/ArangoConfigProperties.java +++ b/core/src/main/java/com/arangodb/config/ArangoConfigProperties.java @@ -110,4 +110,8 @@ default Optional getCompressionLevel() { return Optional.empty(); } + default Optional getReuseVertx() { + return Optional.empty(); + } + } diff --git a/core/src/main/java/com/arangodb/config/ProtocolConfig.java b/core/src/main/java/com/arangodb/config/ProtocolConfig.java new file mode 100644 index 000000000..54432800d --- /dev/null +++ b/core/src/main/java/com/arangodb/config/ProtocolConfig.java @@ -0,0 +1,7 @@ +package com.arangodb.config; + +/** + * Configuration specific for {@link com.arangodb.internal.net.ProtocolProvider}. + */ +public interface ProtocolConfig { +} diff --git a/core/src/main/java/com/arangodb/internal/config/ArangoConfig.java b/core/src/main/java/com/arangodb/internal/config/ArangoConfig.java index ecfc47724..da6bc176b 100644 --- a/core/src/main/java/com/arangodb/internal/config/ArangoConfig.java +++ b/core/src/main/java/com/arangodb/internal/config/ArangoConfig.java @@ -7,6 +7,7 @@ import com.arangodb.arch.UsedInApi; import com.arangodb.config.ArangoConfigProperties; import com.arangodb.config.HostDescription; +import com.arangodb.config.ProtocolConfig; import com.arangodb.entity.LoadBalancingStrategy; import com.arangodb.internal.ArangoDefaults; import com.arangodb.internal.serde.ContentTypeFactory; @@ -49,6 +50,7 @@ public class ArangoConfig { private Compression compression; private Integer compressionThreshold; private Integer compressionLevel; + private ProtocolConfig protocolConfig; private static final Logger LOG = LoggerFactory.getLogger(ArangoConfig.class); @@ -329,4 +331,12 @@ public Integer getCompressionLevel() { public void setCompressionLevel(Integer compressionLevel) { this.compressionLevel = compressionLevel; } + + public ProtocolConfig getProtocolConfig() { + return protocolConfig; + } + + public void setProtocolConfig(ProtocolConfig protocolConfig) { + this.protocolConfig = protocolConfig; + } } diff --git a/core/src/main/java/com/arangodb/internal/net/ProtocolProvider.java b/core/src/main/java/com/arangodb/internal/net/ProtocolProvider.java index bcc55e127..9420a1cb5 100644 --- a/core/src/main/java/com/arangodb/internal/net/ProtocolProvider.java +++ b/core/src/main/java/com/arangodb/internal/net/ProtocolProvider.java @@ -3,6 +3,7 @@ import com.arangodb.Protocol; import com.arangodb.arch.UsedInApi; +import com.arangodb.config.ProtocolConfig; import com.arangodb.internal.config.ArangoConfig; import com.fasterxml.jackson.databind.Module; @@ -11,7 +12,17 @@ public interface ProtocolProvider { boolean supportsProtocol(Protocol protocol); - ConnectionFactory createConnectionFactory(); + /** + * @deprecated use {@link #createConnectionFactory(ProtocolConfig)} instead + */ + @Deprecated + default ConnectionFactory createConnectionFactory() { + throw new UnsupportedOperationException(); + } + + default ConnectionFactory createConnectionFactory(ProtocolConfig config) { + return createConnectionFactory(); + } CommunicationProtocol createProtocol(ArangoConfig config, HostHandler hostHandler); diff --git a/docker/start_db.sh b/docker/start_db.sh index 9da44fd1c..b8b012637 100755 --- a/docker/start_db.sh +++ b/docker/start_db.sh @@ -3,6 +3,7 @@ # Configuration environment variables: # STARTER_MODE: (single|cluster|activefailover), default single # DOCKER_IMAGE: ArangoDB docker image, default docker.io/arangodb/arangodb:latest +# STARTER_DOCKER_IMAGE: ArangoDB Starter docker image, default docker.io/arangodb/arangodb-starter:latest # SSL: (true|false), default false # ARANGO_LICENSE_KEY: only required for ArangoDB Enterprise @@ -11,10 +12,10 @@ STARTER_MODE=${STARTER_MODE:=single} DOCKER_IMAGE=${DOCKER_IMAGE:=docker.io/arangodb/arangodb:latest} +STARTER_DOCKER_IMAGE=${STARTER_DOCKER_IMAGE:=docker.io/arangodb/arangodb-starter:latest} SSL=${SSL:=false} COMPRESSION=${COMPRESSION:=false} -STARTER_DOCKER_IMAGE=docker.io/arangodb/arangodb-starter:latest GW=172.28.0.1 docker network create arangodb --subnet 172.28.0.0/16 diff --git a/driver/src/test/java/com/arangodb/ArangoConfigTest.java b/driver/src/test/java/com/arangodb/ArangoConfigTest.java index f551fed76..b0acf1181 100644 --- a/driver/src/test/java/com/arangodb/ArangoConfigTest.java +++ b/driver/src/test/java/com/arangodb/ArangoConfigTest.java @@ -1,5 +1,6 @@ package com.arangodb; +import com.arangodb.http.HttpProtocolConfig; import com.arangodb.internal.ArangoDefaults; import com.arangodb.internal.config.ArangoConfig; import org.junit.jupiter.api.Test; @@ -8,7 +9,7 @@ public class ArangoConfigTest { @Test - void defaultValues() { + void ArangoConfigDefaultValues() { ArangoConfig cfg = new ArangoConfig(); assertThat(cfg.getHosts()).isEqualTo(ArangoDefaults.DEFAULT_HOSTS); assertThat(cfg.getProtocol()).isEqualTo(Protocol.HTTP2_JSON); @@ -31,5 +32,13 @@ void defaultValues() { assertThat(cfg.getCompression()).isEqualTo(ArangoDefaults.DEFAULT_COMPRESSION); assertThat(cfg.getCompressionThreshold()).isEqualTo(ArangoDefaults.DEFAULT_COMPRESSION_THRESHOLD); assertThat(cfg.getCompressionLevel()).isEqualTo(ArangoDefaults.DEFAULT_COMPRESSION_LEVEL); + assertThat(cfg.getProtocolConfig()).isNull(); } + + @Test + void HttpProtocolConfigDefaultValues() { + HttpProtocolConfig cfg = HttpProtocolConfig.builder().build(); + assertThat(cfg.getVertx()).isNull(); + } + } diff --git a/driver/src/test/java/com/arangodb/ArangoDBAsyncTest.java b/driver/src/test/java/com/arangodb/ArangoDBAsyncTest.java index 19f663805..a97f5f08b 100644 --- a/driver/src/test/java/com/arangodb/ArangoDBAsyncTest.java +++ b/driver/src/test/java/com/arangodb/ArangoDBAsyncTest.java @@ -234,6 +234,7 @@ void getAccessibleDatabasesFor(ArangoDBAsync arangoDB) throws ExecutionException @ParameterizedTest @MethodSource("asyncArangos") void createUser(ArangoDBAsync arangoDB) throws ExecutionException, InterruptedException { + assumeTrue(isSingleServer()); String username = "user-" + UUID.randomUUID(); final UserEntity result = arangoDB.createUser(username, PW, null).get(); assertThat(result.getUser()).isEqualTo(username); diff --git a/driver/src/test/java/perf/SimpleSyncPerfTest.java b/driver/src/test/java/perf/SimpleSyncPerfTest.java index 4e18b71f4..5dcb5188a 100644 --- a/driver/src/test/java/perf/SimpleSyncPerfTest.java +++ b/driver/src/test/java/perf/SimpleSyncPerfTest.java @@ -21,6 +21,7 @@ package perf; import com.arangodb.ArangoDB; +import com.arangodb.BaseJunit5; import com.arangodb.Protocol; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.params.ParameterizedTest; @@ -28,6 +29,8 @@ import java.util.Date; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + /** * @author Michele Rastelli */ @@ -44,6 +47,8 @@ private void doGetVersion(ArangoDB arangoDB) { @ParameterizedTest @EnumSource(Protocol.class) void getVersion(Protocol protocol) throws InterruptedException { + assumeTrue(!protocol.equals(Protocol.VST) || BaseJunit5.isLessThanVersion(3, 12)); + ArangoDB arangoDB = new ArangoDB.Builder() .host("172.28.0.1", 8529) .password("test") diff --git a/http/src/main/java/com/arangodb/http/HttpConnection.java b/http/src/main/java/com/arangodb/http/HttpConnection.java index 575ac940a..bb3e0f441 100644 --- a/http/src/main/java/com/arangodb/http/HttpConnection.java +++ b/http/src/main/java/com/arangodb/http/HttpConnection.java @@ -75,19 +75,19 @@ public class HttpConnection implements Connection { private static final String CONTENT_TYPE_VPACK = "application/x-velocypack"; private static final String USER_AGENT = getUserAgent(); private static final AtomicInteger THREAD_COUNT = new AtomicInteger(); - private String auth; + private volatile String auth; private final int compressionThreshold; private final Encoder encoder; private final WebClient client; private final Integer timeout; private final MultiMap commonHeaders = MultiMap.caseInsensitiveMultiMap(); - private final Vertx vertx; + private final Vertx vertxToClose; private static String getUserAgent() { return "JavaDriver/" + PackageVersion.VERSION + " (JVM/" + System.getProperty("java.specification.version") + ")"; } - HttpConnection(final ArangoConfig config, final HostDescription host) { + HttpConnection(final ArangoConfig config, final HostDescription host, final Vertx existingVertx) { super(); Protocol protocol = config.getProtocol(); ContentType contentType = ContentTypeFactory.of(protocol); @@ -108,14 +108,25 @@ private static String getUserAgent() { } commonHeaders.add("x-arango-driver", USER_AGENT); timeout = config.getTimeout(); - vertx = Vertx.vertx(new VertxOptions().setPreferNativeTransport(true).setEventLoopPoolSize(1)); - vertx.runOnContext(e -> { - Thread.currentThread().setName("adb-http-" + THREAD_COUNT.getAndIncrement()); - auth = new UsernamePasswordCredentials( - config.getUser(), Optional.ofNullable(config.getPassword()).orElse("") - ).toHttpAuthorization(); - LOGGER.debug("Created Vert.x context"); - }); + auth = new UsernamePasswordCredentials( + config.getUser(), Optional.ofNullable(config.getPassword()).orElse("") + ).toHttpAuthorization(); + + Vertx vertxToUse; + if (existingVertx != null) { + // reuse existing Vert.x + vertxToUse = existingVertx; + // Vert.x will not be closed when connection is closed + vertxToClose = null; + LOGGER.debug("Reusing existing Vert.x instance"); + } else { + // create a new Vert.x instance + LOGGER.debug("Creating new Vert.x instance"); + vertxToUse = Vertx.vertx(new VertxOptions().setPreferNativeTransport(true).setEventLoopPoolSize(1)); + vertxToUse.runOnContext(e -> Thread.currentThread().setName("adb-http-" + THREAD_COUNT.getAndIncrement())); + // Vert.x be closed when connection is closed + vertxToClose = vertxToUse; + } int intTtl = Optional.ofNullable(config.getConnectionTtl()) .map(ttl -> Math.toIntExact(ttl / 1000)) @@ -193,7 +204,7 @@ public SslContextFactory sslContextFactory() { }); } - client = WebClient.create(vertx, webClientOptions); + client = WebClient.create(vertxToUse, webClientOptions); } private static String buildUrl(final InternalRequest request) { @@ -229,7 +240,10 @@ private static void addHeader(final InternalRequest request, final HttpRequest executeAsync(@UnstableApi final InternalRequest request) { CompletableFuture rfuture = new CompletableFuture<>(); - vertx.runOnContext(e -> doExecute(request, rfuture)); + doExecute(request, rfuture); return rfuture; } @@ -308,7 +322,7 @@ private InternalResponse buildResponse(final HttpResponse httpResponse) @Override public void setJwt(String jwt) { if (jwt != null) { - vertx.runOnContext(e -> auth = new TokenCredentials(jwt).toHttpAuthorization()); + auth = new TokenCredentials(jwt).toHttpAuthorization(); } } diff --git a/http/src/main/java/com/arangodb/http/HttpConnectionFactory.java b/http/src/main/java/com/arangodb/http/HttpConnectionFactory.java index 8776c093c..03719882a 100644 --- a/http/src/main/java/com/arangodb/http/HttpConnectionFactory.java +++ b/http/src/main/java/com/arangodb/http/HttpConnectionFactory.java @@ -25,15 +25,31 @@ import com.arangodb.internal.config.ArangoConfig; import com.arangodb.internal.net.Connection; import com.arangodb.internal.net.ConnectionFactory; +import io.vertx.core.Vertx; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -/** - * @author Mark Vollmary - */ @UnstableApi public class HttpConnectionFactory implements ConnectionFactory { + private final Logger LOGGER = LoggerFactory.getLogger(HttpConnectionFactory.class); + + private final Vertx vertx; + + public HttpConnectionFactory(@UnstableApi final HttpProtocolConfig config) { + HttpProtocolConfig cfg = config != null ? config : HttpProtocolConfig.builder().build(); + vertx = cfg.getVertx(); + if (vertx == null && Vertx.currentContext() != null) { + LOGGER.warn("Found an existing Vert.x instance, you can reuse it by setting:\n" + + "new ArangoDB.Builder()\n" + + " // ...\n" + + " .protocolConfig(HttpProtocolConfig.builder().vertx(Vertx.currentContext().owner()).build())\n" + + " .build();\n"); + } + } + @Override @UnstableApi public Connection create(@UnstableApi final ArangoConfig config, final HostDescription host) { - return new HttpConnection(config, host); + return new HttpConnection(config, host, vertx); } } diff --git a/http/src/main/java/com/arangodb/http/HttpProtocolConfig.java b/http/src/main/java/com/arangodb/http/HttpProtocolConfig.java new file mode 100644 index 000000000..26c47f825 --- /dev/null +++ b/http/src/main/java/com/arangodb/http/HttpProtocolConfig.java @@ -0,0 +1,42 @@ +package com.arangodb.http; + +import com.arangodb.config.ProtocolConfig; +import io.vertx.core.Vertx; + +public final class HttpProtocolConfig implements ProtocolConfig { + private final Vertx vertx; + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private Vertx vertx; + + private Builder() { + } + + /** + * Set the Vert.x instance to use for creating HTTP connections. + * + * @param vertx the Vert.x instance to use + * @return this builder + */ + public Builder vertx(Vertx vertx) { + this.vertx = vertx; + return this; + } + + public HttpProtocolConfig build() { + return new HttpProtocolConfig(vertx); + } + } + + private HttpProtocolConfig(Vertx vertx) { + this.vertx = vertx; + } + + public Vertx getVertx() { + return vertx; + } +} diff --git a/http/src/main/java/com/arangodb/http/HttpProtocolProvider.java b/http/src/main/java/com/arangodb/http/HttpProtocolProvider.java index e204f0886..a85abe9d8 100644 --- a/http/src/main/java/com/arangodb/http/HttpProtocolProvider.java +++ b/http/src/main/java/com/arangodb/http/HttpProtocolProvider.java @@ -2,6 +2,7 @@ import com.arangodb.Protocol; import com.arangodb.arch.UnstableApi; +import com.arangodb.config.ProtocolConfig; import com.arangodb.internal.config.ArangoConfig; import com.arangodb.internal.net.CommunicationProtocol; import com.arangodb.internal.net.ConnectionFactory; @@ -22,8 +23,8 @@ public boolean supportsProtocol(Protocol protocol) { @Override @UnstableApi - public ConnectionFactory createConnectionFactory() { - return new HttpConnectionFactory(); + public ConnectionFactory createConnectionFactory(@UnstableApi ProtocolConfig config) { + return new HttpConnectionFactory((HttpProtocolConfig) config); } @Override diff --git a/resilience-tests/src/test/java/resilience/vertx/VertxTest.java b/resilience-tests/src/test/java/resilience/vertx/VertxTest.java new file mode 100644 index 000000000..f4cd37bf3 --- /dev/null +++ b/resilience-tests/src/test/java/resilience/vertx/VertxTest.java @@ -0,0 +1,106 @@ +package resilience.vertx; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.spi.ILoggingEvent; +import com.arangodb.ArangoDB; +import com.arangodb.http.HttpProtocolConfig; +import io.vertx.core.Vertx; +import org.junit.jupiter.api.Test; +import resilience.SingleServerTest; + +import java.util.concurrent.ExecutionException; + +import static org.assertj.core.api.Assertions.assertThat; + +public class VertxTest extends SingleServerTest { + + @Test + void managedVertx() { + ArangoDB adb = new ArangoDB.Builder() + .host("172.28.0.1", 8529) + .password("test") + .build(); + + adb.getVersion(); + adb.shutdown(); + + assertThat(logs.getLogs()) + .filteredOn(it -> it.getLoggerName().equals("com.arangodb.http.HttpConnection")) + .filteredOn(it -> it.getLevel().equals(Level.DEBUG)) + .map(ILoggingEvent::getFormattedMessage) + .anySatisfy(it -> assertThat(it).contains("Creating new Vert.x instance")) + .anySatisfy(it -> assertThat(it).contains("Closing Vert.x instance")); + } + + @Test + void reuseVertx() { + Vertx vertx = Vertx.vertx(); + ArangoDB adb = new ArangoDB.Builder() + .host("172.28.0.1", 8529) + .password("test") + .protocolConfig(HttpProtocolConfig.builder().vertx(vertx).build()) + .build(); + adb.getVersion(); + adb.shutdown(); + vertx.close(); + + assertThat(logs.getLogs()) + .filteredOn(it -> it.getLoggerName().equals("com.arangodb.http.HttpConnection")) + .filteredOn(it -> it.getLevel().equals(Level.DEBUG)) + .map(ILoggingEvent::getFormattedMessage) + .anySatisfy(it -> assertThat(it).contains("Reusing existing Vert.x instance")); + } + + @Test + void reuseVertxFromVertxThread() throws ExecutionException, InterruptedException { + Vertx vertx = Vertx.vertx(); + vertx.executeBlocking(() -> { + ArangoDB adb = new ArangoDB.Builder() + .host("172.28.0.1", 8529) + .password("test") + .protocolConfig(HttpProtocolConfig.builder().vertx(Vertx.currentContext().owner()).build()) + .build(); + adb.getVersion(); + adb.shutdown(); + return null; + }).toCompletionStage().toCompletableFuture().get(); + vertx.close(); + + assertThat(logs.getLogs()) + .filteredOn(it -> it.getLoggerName().equals("com.arangodb.http.HttpConnection")) + .filteredOn(it -> it.getLevel().equals(Level.DEBUG)) + .map(ILoggingEvent::getFormattedMessage) + .anySatisfy(it -> assertThat(it).contains("Reusing existing Vert.x instance")); + } + + @Test + void existingVertxNotUsed() throws ExecutionException, InterruptedException { + Vertx vertx = Vertx.vertx(); + vertx.executeBlocking(() -> { + ArangoDB adb = new ArangoDB.Builder() + .host("172.28.0.1", 8529) + .password("test") + .build(); + adb.getVersion(); + adb.shutdown(); + return null; + }).toCompletionStage().toCompletableFuture().get(); + vertx.close(); + + assertThat(logs.getLogs()) + .filteredOn(it -> it.getLoggerName().equals("com.arangodb.http.HttpConnectionFactory")) + .filteredOn(it -> it.getLevel().equals(Level.WARN)) + .map(ILoggingEvent::getFormattedMessage) + .anySatisfy(it -> assertThat(it) + .contains("Found an existing Vert.x instance, you can reuse it by setting:") + .contains(".protocolConfig(HttpProtocolConfig.builder().vertx(Vertx.currentContext().owner()).build())") + ); + assertThat(logs.getLogs()) + .filteredOn(it -> it.getLoggerName().equals("com.arangodb.http.HttpConnection")) + .filteredOn(it -> it.getLevel().equals(Level.DEBUG)) + .map(ILoggingEvent::getFormattedMessage) + .anySatisfy(it -> assertThat(it).contains("Creating new Vert.x instance")) + .anySatisfy(it -> assertThat(it).contains("Closing Vert.x instance")); + } + +}