diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java index ee4b3212cac..568fde56360 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java @@ -15,8 +15,10 @@ */ package org.testcontainers.couchbase; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.github.dockerjava.api.command.InspectContainerResponse; import com.github.dockerjava.api.model.ContainerNetwork; import lombok.Cleanup; @@ -35,11 +37,15 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; +import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.function.Predicate; import java.util.stream.Collectors; +import java.util.stream.StreamSupport; /** * The couchbase container initializes and configures a Couchbase Server single node cluster. @@ -168,7 +174,7 @@ protected void configure() { .map("healthy"::equals) .orElse(false); } catch (IOException e) { - logger().error("Unable to parse response {}", response); + logger().error("Unable to parse response: " + response, e); return false; } }) @@ -241,15 +247,10 @@ private void renameNode() { private void initializeServices() { logger().debug("Initializing couchbase services on host: {}", enabledServices); - final String services = enabledServices.stream().map(s -> { - switch (s) { - case KV: return "kv"; - case QUERY: return "n1ql"; - case INDEX: return "index"; - case SEARCH: return "fts"; - default: throw new IllegalStateException("Unknown service!"); - } - }).collect(Collectors.joining(",")); + final String services = enabledServices + .stream() + .map(CouchbaseService::getIdentifier) + .collect(Collectors.joining(",")); @Cleanup Response response = doHttpRequest(MGMT_PORT, "/node/controller/setupServices", "POST", new FormBody.Builder() .add("services", services) @@ -350,10 +351,11 @@ private void createBuckets() { checkSuccessfulResponse(response, "Could not create bucket " + bucket.getName()); new HttpWaitStrategy() - .forPath("/pools/default/buckets/" + bucket.getName()) + .forPath("/pools/default/b/" + bucket.getName()) .forPort(MGMT_PORT) .withBasicCredentials(username, password) .forStatusCode(200) + .forResponsePredicate(new AllServicesEnabledPredicate()) .waitUntilReady(this); if (enabledServices.contains(CouchbaseService.QUERY)) { @@ -450,4 +452,38 @@ private Response doHttpRequest(final int port, final String path, final String m throw new RuntimeException("Could not perform request against couchbase HTTP endpoint ", ex); } } + + /** + * In addition to getting a 200, we need to make sure that all services we need are enabled and available on + * the bucket. + *

+ * Fixes the issue observed in https://github.com/testcontainers/testcontainers-java/issues/2993 + */ + private class AllServicesEnabledPredicate implements Predicate { + + @Override + public boolean test(final String rawConfig) { + try { + for (JsonNode node : MAPPER.readTree(rawConfig).at("/nodesExt")) { + for (CouchbaseService enabledService : enabledServices) { + boolean found = false; + Iterator fieldNames = node.get("services").fieldNames(); + while (fieldNames.hasNext()) { + if (fieldNames.next().startsWith(enabledService.getIdentifier())) { + found = true; + } + } + if (!found) { + logger().trace("Service {} not yet part of config, retrying.", enabledService); + return false; + } + } + } + return true; + } catch (IOException ex) { + logger().error("Unable to parse response: " + rawConfig, ex); + return false; + } + } + } } diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java index d284c660709..c60fc6b71d0 100644 --- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java +++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseService.java @@ -24,21 +24,30 @@ public enum CouchbaseService { /** * Key-Value service. */ - KV, + KV("kv"), /** * Query (N1QL) service. */ - QUERY, + QUERY("n1ql"), /** * Search (FTS) service. */ - SEARCH, + SEARCH("fts"), /** * Indexing service (needed if QUERY is also used!). */ - INDEX + INDEX("index"); + private final String identifier; + + CouchbaseService(String identifier) { + this.identifier = identifier; + } + + String getIdentifier() { + return identifier; + } }