diff --git a/modules/couchbase/build.gradle b/modules/couchbase/build.gradle
index 08636089467..bc5b94dad24 100644
--- a/modules/couchbase/build.gradle
+++ b/modules/couchbase/build.gradle
@@ -2,8 +2,6 @@ description = "Testcontainers :: Couchbase"
dependencies {
api project(':testcontainers')
- // TODO use JDK's HTTP client and/or Apache HttpClient5
- shaded 'com.squareup.okhttp3:okhttp:5.1.0'
testImplementation 'com.couchbase.client:java-client:3.8.3'
testImplementation 'org.awaitility:awaitility:4.3.0'
diff --git a/modules/couchbase/src/main/java/org/testcontainers/couchbase/AuthInterceptor.java b/modules/couchbase/src/main/java/org/testcontainers/couchbase/AuthInterceptor.java
new file mode 100644
index 00000000000..9d508bd3b1d
--- /dev/null
+++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/AuthInterceptor.java
@@ -0,0 +1,70 @@
+package org.testcontainers.couchbase;
+
+import com.github.dockerjava.zerodep.shaded.org.apache.hc.core5.http.EntityDetails;
+import com.github.dockerjava.zerodep.shaded.org.apache.hc.core5.http.HttpException;
+import com.github.dockerjava.zerodep.shaded.org.apache.hc.core5.http.HttpRequest;
+import com.github.dockerjava.zerodep.shaded.org.apache.hc.core5.http.HttpRequestInterceptor;
+import com.github.dockerjava.zerodep.shaded.org.apache.hc.core5.http.protocol.HttpContext;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+
+/**
+ * HTTP request interceptor that adds Basic Authentication headers to HTTP requests.
+ *
+ * This interceptor checks if the "Authorization" header is already present in the request.
+ * If not, it adds a Basic Authentication header using the provided username and password.
+ * The credentials are Base64 encoded in the format "username:password".
+ *
+ *
+ * Example usage:
+ *
+ * {@code
+ * AuthInterceptor interceptor = new AuthInterceptor("admin", "password");
+ * // Register with HTTP client to automatically add auth headers
+ * }
+ *
+ *
+ * @see HttpRequestInterceptor
+ */
+class AuthInterceptor implements HttpRequestInterceptor {
+
+ private final String usr;
+
+ private final String pass;
+
+ /**
+ * Constructs a new AuthInterceptor with the specified credentials.
+ *
+ * @param usr the username for Basic Authentication
+ * @param pass the password for Basic Authentication
+ */
+ public AuthInterceptor(final String usr, final String pass) {
+ this.usr = usr;
+ this.pass = pass;
+ }
+
+ /**
+ * Processes the HTTP request by adding a Basic Authentication header if not already present.
+ *
+ * The method encodes the username and password using Base64 encoding and sets the
+ * "Authorization" header with the value "Basic {base64-encoded-credentials}".
+ *
+ *
+ * @param httpRequest the HTTP request to process
+ * @param entityDetails the entity details (if any)
+ * @param httpContext the HTTP context for the request
+ * @throws HttpException if an HTTP protocol error occurs
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ public void process(HttpRequest httpRequest, EntityDetails entityDetails, HttpContext httpContext)
+ throws HttpException, IOException {
+ if (!httpRequest.containsHeader("Authorization")) {
+ String authValue = "Basic " + Base64.getEncoder()
+ .encodeToString((usr + ":" + pass).getBytes(StandardCharsets.UTF_8));
+ httpRequest.setHeader("Authorization", authValue);
+ }
+ }
+}
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 14997d253af..0cf3a5d7f97 100644
--- a/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java
+++ b/modules/couchbase/src/main/java/org/testcontainers/couchbase/CouchbaseContainer.java
@@ -20,13 +20,17 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.dockerjava.api.command.InspectContainerResponse;
import com.github.dockerjava.api.model.ContainerNetwork;
-import lombok.Cleanup;
-import okhttp3.Credentials;
-import okhttp3.FormBody;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.RequestBody;
-import okhttp3.Response;
+import com.github.dockerjava.zerodep.shaded.org.apache.hc.client5.http.classic.methods.HttpGet;
+import com.github.dockerjava.zerodep.shaded.org.apache.hc.client5.http.classic.methods.HttpPost;
+import com.github.dockerjava.zerodep.shaded.org.apache.hc.client5.http.classic.methods.HttpPut;
+import com.github.dockerjava.zerodep.shaded.org.apache.hc.client5.http.entity.UrlEncodedFormEntity;
+import com.github.dockerjava.zerodep.shaded.org.apache.hc.client5.http.impl.classic.BasicHttpClientResponseHandler;
+import com.github.dockerjava.zerodep.shaded.org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import com.github.dockerjava.zerodep.shaded.org.apache.hc.client5.http.impl.classic.HttpClients;
+import com.github.dockerjava.zerodep.shaded.org.apache.hc.core5.http.NameValuePair;
+import com.github.dockerjava.zerodep.shaded.org.apache.hc.core5.http.io.HttpClientResponseHandler;
+import com.github.dockerjava.zerodep.shaded.org.apache.hc.core5.http.io.entity.EntityUtils;
+import com.github.dockerjava.zerodep.shaded.org.apache.hc.core5.http.message.BasicNameValuePair;
import org.rnorth.ducttape.unreliables.Unreliables;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.HttpWaitStrategy;
@@ -94,7 +98,9 @@ public class CouchbaseContainer extends GenericContainer {
private static final ObjectMapper MAPPER = new ObjectMapper();
- private static final OkHttpClient HTTP_CLIENT = new OkHttpClient();
+ private AuthInterceptor authInterceptor;
+
+ private final HttpClientResponseHandler httpBaseResponseHandler = new BasicHttpClientResponseHandler();
private String username = "Administrator";
@@ -134,6 +140,7 @@ public CouchbaseContainer(final String dockerImageName) {
/**
* Create a new couchbase container with the specified image name.
+ *
* @param dockerImageName the image name that should be used.
*/
public CouchbaseContainer(final DockerImageName dockerImageName) {
@@ -182,11 +189,11 @@ public CouchbaseContainer withServiceQuota(final CouchbaseService service, final
if (quotaMb < service.getMinimumQuotaMb()) {
throw new IllegalArgumentException(
"The custom quota (" +
- quotaMb +
- ") must not be smaller than the " +
- "minimum quota for the service (" +
- service.getMinimumQuotaMb() +
- ")"
+ quotaMb +
+ ") must not be smaller than the " +
+ "minimum quota for the service (" +
+ service.getMinimumQuotaMb() +
+ ")"
);
}
this.customServiceQuotas.put(service, quotaMb);
@@ -340,7 +347,7 @@ protected void containerIsStarting(InspectContainerResponse containerInfo, boole
@Override
protected void containerIsStarting(final InspectContainerResponse containerInfo) {
logger().debug("Couchbase container is starting, performing configuration.");
-
+ authInterceptor = new AuthInterceptor(username, password);
timePhase("waitUntilNodeIsOnline", this::waitUntilNodeIsOnline);
timePhase("initializeIsEnterprise", this::initializeIsEnterprise);
timePhase("initializeHasTlsPorts", this::initializeHasTlsPorts);
@@ -381,11 +388,10 @@ private void waitUntilNodeIsOnline() {
* Fetches edition (enterprise or community) of started container.
*/
private void initializeIsEnterprise() {
- @Cleanup
- Response response = doHttpRequest(MGMT_PORT, "/pools", "GET", null, true);
-
- try {
- isEnterprise = MAPPER.readTree(response.body().string()).get("isEnterprise").asBoolean();
+ try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+ String body = httpClient.execute(new HttpGet("http://" + getHost() + ":" + getMappedPort(MGMT_PORT) + "/pools"),
+ httpBaseResponseHandler);
+ isEnterprise = MAPPER.readTree(body).get("isEnterprise").asBoolean();
} catch (IOException e) {
throw new IllegalStateException("Couchbase /pools did not return valid JSON");
}
@@ -407,19 +413,19 @@ private void initializeIsEnterprise() {
* the "enterprise edition" flag.
*/
private void initializeHasTlsPorts() {
- @Cleanup
- Response response = doHttpRequest(MGMT_PORT, "/pools/default/nodeServices", "GET", null, true);
-
- try {
- String clusterTopology = response.body().string();
- hasTlsPorts =
- !MAPPER
- .readTree(clusterTopology)
- .path("nodesExt")
- .path(0)
- .path("services")
- .path("mgmtSSL")
- .isMissingNode();
+ try (CloseableHttpClient httpClient = HttpClients
+ .custom()
+ .addRequestInterceptorFirst(authInterceptor)
+ .build()) {
+ String body = httpClient.execute(new HttpGet("http://" + getHost() + ":" + getMappedPort(MGMT_PORT) + "/pools/default/nodeServices"),
+ httpBaseResponseHandler);
+ hasTlsPorts = !MAPPER
+ .readTree(body)
+ .path("nodesExt")
+ .path(0)
+ .path("services")
+ .path("mgmtSSL")
+ .isMissingNode();
} catch (IOException e) {
throw new IllegalStateException("Couchbase /pools/default/nodeServices did not return valid JSON");
}
@@ -433,17 +439,17 @@ private void initializeHasTlsPorts() {
*/
private void renameNode() {
logger().debug("Renaming Couchbase Node from localhost to {}", getHost());
+ HttpPost httpPost = new HttpPost("http://" + getHost() + ":" + getMappedPort(MGMT_PORT) + "/node/controller/rename");
- @Cleanup
- Response response = doHttpRequest(
- MGMT_PORT,
- "/node/controller/rename",
- "POST",
- new FormBody.Builder().add("hostname", getInternalIpAddress()).build(),
- false
- );
+ List formParams = new ArrayList<>();
+ formParams.add(new BasicNameValuePair("hostname", getInternalIpAddress()));
+ httpPost.setEntity(new UrlEncodedFormEntity(formParams));
- checkSuccessfulResponse(response, "Could not rename couchbase node");
+ try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+ httpClient.execute(httpPost, httpBaseResponseHandler);
+ } catch (IOException e) {
+ throw new IllegalStateException("Could not rename couchbase node");
+ }
}
/**
@@ -457,16 +463,17 @@ private void initializeServices() {
.map(CouchbaseService::getIdentifier)
.collect(Collectors.joining(","));
- @Cleanup
- Response response = doHttpRequest(
- MGMT_PORT,
- "/node/controller/setupServices",
- "POST",
- new FormBody.Builder().add("services", services).build(),
- false
- );
+ HttpPost httpPost = new HttpPost("http://" + getHost() + ":" + getMappedPort(MGMT_PORT) + "/node/controller/setupServices");
+
+ List formParams = new ArrayList<>();
+ formParams.add(new BasicNameValuePair("services", services));
+ httpPost.setEntity(new UrlEncodedFormEntity(formParams));
- checkSuccessfulResponse(response, "Could not enable couchbase services");
+ try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+ httpClient.execute(httpPost, httpBaseResponseHandler);
+ } catch (IOException e) {
+ throw new IllegalStateException("Could not enable couchbase services");
+ }
}
/**
@@ -477,7 +484,9 @@ private void initializeServices() {
private void setMemoryQuotas() {
logger().debug("Custom service memory quotas: {}", customServiceQuotas);
- final FormBody.Builder quotaBuilder = new FormBody.Builder();
+ final List formParams = new ArrayList<>();
+ final HttpPost httpPost = new HttpPost("http://" + getHost() + ":" + getMappedPort(MGMT_PORT) + "/pools/default");
+
for (CouchbaseService service : enabledServices) {
if (!service.hasQuota()) {
continue;
@@ -485,16 +494,19 @@ private void setMemoryQuotas() {
int quota = customServiceQuotas.getOrDefault(service, service.getMinimumQuotaMb());
if (CouchbaseService.KV.equals(service)) {
- quotaBuilder.add("memoryQuota", Integer.toString(quota));
+ formParams.add(new BasicNameValuePair("memoryQuota", Integer.toString(quota)));
} else {
- quotaBuilder.add(service.getIdentifier() + "MemoryQuota", Integer.toString(quota));
+ formParams.add(new BasicNameValuePair(service.getIdentifier() + "MemoryQuota", Integer.toString(quota)));
}
}
- @Cleanup
- Response response = doHttpRequest(MGMT_PORT, "/pools/default", "POST", quotaBuilder.build(), false);
+ httpPost.setEntity(new UrlEncodedFormEntity(formParams));
- checkSuccessfulResponse(response, "Could not configure service memory quotas");
+ try (final CloseableHttpClient httpClient = HttpClients.createDefault()) {
+ httpClient.execute(httpPost, httpBaseResponseHandler);
+ } catch (IOException e) {
+ throw new IllegalStateException("Could not configure service memory quotas");
+ }
}
/**
@@ -505,20 +517,20 @@ private void setMemoryQuotas() {
private void configureAdminUser() {
logger().debug("Configuring couchbase admin user with username: \"{}\"", username);
- @Cleanup
- Response response = doHttpRequest(
- MGMT_PORT,
- "/settings/web",
- "POST",
- new FormBody.Builder()
- .add("username", username)
- .add("password", password)
- .add("port", Integer.toString(MGMT_PORT))
- .build(),
- false
- );
+ final HttpPost httpPost = new HttpPost("http://" + getHost() + ":" + getMappedPort(MGMT_PORT) + "/settings/web");
+
+ final List formParams = new ArrayList<>();
+ formParams.add(new BasicNameValuePair("username", username));
+ formParams.add(new BasicNameValuePair("password", password));
+ formParams.add(new BasicNameValuePair("port", Integer.toString(MGMT_PORT)));
- checkSuccessfulResponse(response, "Could not configure couchbase admin user");
+ httpPost.setEntity(new UrlEncodedFormEntity(formParams));
+
+ try (final CloseableHttpClient httpClient = HttpClients.createDefault()) {
+ httpClient.execute(httpPost, httpBaseResponseHandler);
+ } catch (IOException e) {
+ throw new IllegalStateException("Could not configure couchbase admin user");
+ }
}
/**
@@ -531,60 +543,61 @@ private void configureAdminUser() {
private void configureExternalPorts() {
logger().debug("Mapping external ports to the alternate address configuration");
- final FormBody.Builder builder = new FormBody.Builder();
- builder.add("hostname", getHost());
- builder.add("mgmt", Integer.toString(getMappedPort(MGMT_PORT)));
+ final List formParams = new ArrayList<>();
+
+ formParams.add(new BasicNameValuePair("hostname", getHost()));
+ formParams.add(new BasicNameValuePair("mgmt", Integer.toString(getMappedPort(MGMT_PORT))));
if (hasTlsPorts) {
- builder.add("mgmtSSL", Integer.toString(getMappedPort(MGMT_SSL_PORT)));
+ formParams.add(new BasicNameValuePair("mgmtSSL", Integer.toString(getMappedPort(MGMT_SSL_PORT))));
}
if (enabledServices.contains(CouchbaseService.KV)) {
- builder.add("kv", Integer.toString(getMappedPort(KV_PORT)));
- builder.add("capi", Integer.toString(getMappedPort(VIEW_PORT)));
+ formParams.add(new BasicNameValuePair("kv", Integer.toString(getMappedPort(KV_PORT))));
+ formParams.add(new BasicNameValuePair("capi", Integer.toString(getMappedPort(VIEW_PORT))));
if (hasTlsPorts) {
- builder.add("kvSSL", Integer.toString(getMappedPort(KV_SSL_PORT)));
- builder.add("capiSSL", Integer.toString(getMappedPort(VIEW_SSL_PORT)));
+ formParams.add(new BasicNameValuePair("kvSSL", Integer.toString(getMappedPort(KV_SSL_PORT))));
+ formParams.add(new BasicNameValuePair("capiSSL", Integer.toString(getMappedPort(VIEW_SSL_PORT))));
}
}
if (enabledServices.contains(CouchbaseService.QUERY)) {
- builder.add("n1ql", Integer.toString(getMappedPort(QUERY_PORT)));
+ formParams.add(new BasicNameValuePair("n1ql", Integer.toString(getMappedPort(QUERY_PORT))));
if (hasTlsPorts) {
- builder.add("n1qlSSL", Integer.toString(getMappedPort(QUERY_SSL_PORT)));
+ formParams.add(new BasicNameValuePair("n1qlSSL", Integer.toString(getMappedPort(QUERY_SSL_PORT))));
}
}
if (enabledServices.contains(CouchbaseService.SEARCH)) {
- builder.add("fts", Integer.toString(getMappedPort(SEARCH_PORT)));
+ formParams.add(new BasicNameValuePair("fts", Integer.toString(getMappedPort(SEARCH_PORT))));
if (hasTlsPorts) {
- builder.add("ftsSSL", Integer.toString(getMappedPort(SEARCH_SSL_PORT)));
+ formParams.add(new BasicNameValuePair("ftsSSL", Integer.toString(getMappedPort(SEARCH_SSL_PORT))));
}
}
if (enabledServices.contains(CouchbaseService.ANALYTICS)) {
- builder.add("cbas", Integer.toString(getMappedPort(ANALYTICS_PORT)));
+ formParams.add(new BasicNameValuePair("cbas", Integer.toString(getMappedPort(ANALYTICS_PORT))));
if (hasTlsPorts) {
- builder.add("cbasSSL", Integer.toString(getMappedPort(ANALYTICS_SSL_PORT)));
+ formParams.add(new BasicNameValuePair("cbasSSL", Integer.toString(getMappedPort(ANALYTICS_SSL_PORT))));
}
}
if (enabledServices.contains(CouchbaseService.EVENTING)) {
- builder.add("eventingAdminPort", Integer.toString(getMappedPort(EVENTING_PORT)));
+ formParams.add(new BasicNameValuePair("eventingAdminPort", Integer.toString(getMappedPort(EVENTING_PORT))));
if (hasTlsPorts) {
- builder.add("eventingSSL", Integer.toString(getMappedPort(EVENTING_SSL_PORT)));
+ formParams.add(new BasicNameValuePair("eventingSSL", Integer.toString(getMappedPort(EVENTING_SSL_PORT))));
}
}
- @Cleanup
- Response response = doHttpRequest(
- MGMT_PORT,
- "/node/controller/setupAlternateAddresses/external",
- "PUT",
- builder.build(),
- true
- );
+ final HttpPut httpPut = new HttpPut("http://" + getHost() + ":" + getMappedPort(MGMT_PORT) + "/node/controller/setupAlternateAddresses/external");
+ httpPut.setEntity(new UrlEncodedFormEntity(formParams));
- checkSuccessfulResponse(response, "Could not configure external ports");
+ try (final CloseableHttpClient httpClient = HttpClients.custom()
+ .addRequestInterceptorFirst(authInterceptor)
+ .build()) {
+ httpClient.execute(httpPut, httpBaseResponseHandler);
+ } catch (IOException e) {
+ throw new IllegalStateException("Could not configure external ports");
+ }
}
/**
@@ -593,16 +606,21 @@ private void configureExternalPorts() {
private void configureIndexer() {
logger().debug("Configuring the indexer service");
- @Cleanup
- Response response = doHttpRequest(
- MGMT_PORT,
- "/settings/indexes",
- "POST",
- new FormBody.Builder().add("storageMode", isEnterprise ? "memory_optimized" : "forestdb").build(),
- true
- );
+ final HttpPost httpPost = new HttpPost("http://" + getHost() + ":" + getMappedPort(MGMT_PORT) + "/settings/indexes");
+
+ final List formParams = new ArrayList<>();
+ formParams.add(new BasicNameValuePair("storageMode", isEnterprise ? "memory_optimized" : "forestdb"));
- checkSuccessfulResponse(response, "Could not configure the indexing service");
+ httpPost.setEntity(new UrlEncodedFormEntity(formParams));
+
+ try (final CloseableHttpClient httpClient = HttpClients
+ .custom()
+ .addRequestInterceptorFirst(authInterceptor)
+ .build()) {
+ httpClient.execute(httpPost, httpBaseResponseHandler);
+ } catch (IOException e) {
+ throw new IllegalStateException("Could not configure the indexing service");
+ }
}
/**
@@ -614,21 +632,23 @@ private void createBuckets() {
for (BucketDefinition bucket : buckets) {
logger().debug("Creating bucket \"{}\"", bucket.getName());
- @Cleanup
- Response response = doHttpRequest(
- MGMT_PORT,
- "/pools/default/buckets",
- "POST",
- new FormBody.Builder()
- .add("name", bucket.getName())
- .add("ramQuotaMB", Integer.toString(bucket.getQuota()))
- .add("flushEnabled", bucket.hasFlushEnabled() ? "1" : "0")
- .add("replicaNumber", Integer.toString(bucket.getNumReplicas()))
- .build(),
- true
- );
+ final HttpPost httpPost = new HttpPost("http://" + getHost() + ":" + getMappedPort(MGMT_PORT) + "/pools/default/buckets");
- checkSuccessfulResponse(response, "Could not create bucket " + bucket.getName());
+ final List formParams = new ArrayList<>();
+ formParams.add(new BasicNameValuePair("name", bucket.getName()));
+ formParams.add(new BasicNameValuePair("ramQuotaMB", Integer.toString(bucket.getQuota())));
+ formParams.add(new BasicNameValuePair("flushEnabled", bucket.hasFlushEnabled() ? "1" : "0"));
+ formParams.add(new BasicNameValuePair("replicaNumber", Integer.toString(bucket.getNumReplicas())));
+
+ httpPost.setEntity(new UrlEncodedFormEntity(formParams));
+
+ try (final CloseableHttpClient httpClient = HttpClients.custom()
+ .addRequestInterceptorFirst(authInterceptor)
+ .build()) {
+ httpClient.execute(httpPost, httpBaseResponseHandler);
+ } catch (IOException e) {
+ throw new IllegalStateException("Could not create bucket " + bucket.getName());
+ }
timePhase(
"createBucket:" + bucket.getName() + ":waitForAllServicesEnabled",
@@ -653,33 +673,30 @@ private void createBuckets() {
1,
TimeUnit.MINUTES,
() -> {
- @Cleanup
- Response queryResponse = doHttpRequest(
- QUERY_PORT,
- "/query/service",
- "POST",
- new FormBody.Builder()
- .add(
- "statement",
- "SELECT COUNT(*) > 0 as present FROM system:keyspaces WHERE name = \"" +
- bucket.getName() +
- "\""
- )
- .build(),
- true
- );
-
- String body = queryResponse.body() != null ? queryResponse.body().string() : null;
- checkSuccessfulResponse(
- queryResponse,
- "Could not poll query service state for bucket: " + bucket.getName()
+ final HttpPost selectQueryServiceHttp = new HttpPost(
+ "http://" + getHost() + ":" + getMappedPort(QUERY_PORT) + "/query/service"
);
- return Optional
- .of(MAPPER.readTree(body))
- .map(n -> n.at("/results/0/present"))
- .map(JsonNode::asBoolean)
- .orElse(false);
+ final List queryFormParams = new ArrayList<>();
+ queryFormParams.add(new BasicNameValuePair(
+ "statement",
+ "SELECT COUNT(*) > 0 as present FROM system:keyspaces WHERE name = \"" +
+ bucket.getName() +
+ "\""));
+ selectQueryServiceHttp.setEntity(new UrlEncodedFormEntity(queryFormParams));
+
+ try (final CloseableHttpClient httpClient = HttpClients.custom()
+ .addRequestInterceptorFirst(authInterceptor)
+ .build()) {
+ String body = httpClient.execute(selectQueryServiceHttp, httpBaseResponseHandler);
+ return Optional
+ .of(MAPPER.readTree(body))
+ .map(n -> n.at("/results/0/present"))
+ .map(JsonNode::asBoolean)
+ .orElse(false);
+ } catch (IllegalStateException e) {
+ throw new IllegalStateException("Could not poll query service state for bucket: " + bucket.getName());
+ }
}
);
}
@@ -688,27 +705,32 @@ private void createBuckets() {
if (bucket.hasPrimaryIndex()) {
if (enabledServices.contains(CouchbaseService.QUERY)) {
- @Cleanup
- Response queryResponse = doHttpRequest(
- QUERY_PORT,
- "/query/service",
- "POST",
- new FormBody.Builder()
- .add("statement", "CREATE PRIMARY INDEX on `" + bucket.getName() + "`")
- .build(),
- true
+
+ final HttpPost queryhttpPost = new HttpPost(
+ "http://" + getHost() + ":" + getMappedPort(QUERY_PORT) + "/query/service"
);
- try {
- checkSuccessfulResponse(
- queryResponse,
- "Could not create primary index for bucket " + bucket.getName()
- );
- } catch (IllegalStateException ex) {
- // potentially ignore the error, the index will be eventually built.
- if (!ex.getMessage().contains("Index creation will be retried in background")) {
- throw ex;
- }
+ final List queryFormParams = new ArrayList<>();
+ queryFormParams.add(new BasicNameValuePair(
+ "statement", "CREATE PRIMARY INDEX on `" + bucket.getName() + "`")
+ );
+ queryhttpPost.setEntity(new UrlEncodedFormEntity(queryFormParams));
+
+ try (final CloseableHttpClient httpClient = HttpClients.custom()
+ .addRequestInterceptorFirst(authInterceptor)
+ .build()) {
+ httpClient.execute(queryhttpPost, response -> {
+ int statusCode = response.getCode();
+ boolean isValid = statusCode >= 200 && statusCode < 300;
+ String body = EntityUtils.toString(response.getEntity());
+ if (!isValid && !body.contains("Index creation will be retried in background")) {
+ throw new IllegalStateException("Cannot create index");
+ }
+ return body;
+ });
+
+ } catch (IOException e) {
+ throw new IllegalStateException("Could not create primary index for bucket: " + bucket.getName());
}
timePhase(
@@ -718,33 +740,32 @@ private void createBuckets() {
1,
TimeUnit.MINUTES,
() -> {
- @Cleanup
- Response stateResponse = doHttpRequest(
- QUERY_PORT,
- "/query/service",
- "POST",
- new FormBody.Builder()
- .add(
- "statement",
- "SELECT count(*) > 0 AS online FROM system:indexes where keyspace_id = \"" +
- bucket.getName() +
- "\" and is_primary = true and state = \"online\""
- )
- .build(),
- true
- );
- String body = stateResponse.body() != null ? stateResponse.body().string() : null;
- checkSuccessfulResponse(
- stateResponse,
- "Could not poll primary index state for bucket: " + bucket.getName()
+ final HttpPost selectIndexesQueryHttp = new HttpPost(
+ "http://" + getHost() + ":" + getMappedPort(QUERY_PORT) + "/query/service"
);
- return Optional
- .of(MAPPER.readTree(body))
- .map(n -> n.at("/results/0/online"))
- .map(JsonNode::asBoolean)
- .orElse(false);
+ final List selectIndexesQueryForm = new ArrayList<>();
+ selectIndexesQueryForm.add(new BasicNameValuePair(
+ "statement",
+ "SELECT count(*) > 0 AS online FROM system:indexes where keyspace_id = \"" +
+ bucket.getName() +
+ "\" and is_primary = true and state = \"online\""));
+
+ selectIndexesQueryHttp.setEntity(new UrlEncodedFormEntity(selectIndexesQueryForm));
+
+ try (final CloseableHttpClient httpClient = HttpClients.custom()
+ .addRequestInterceptorFirst(authInterceptor)
+ .build()) {
+ String body = httpClient.execute(selectIndexesQueryHttp, httpBaseResponseHandler);
+ return Optional
+ .of(MAPPER.readTree(body))
+ .map(n -> n.at("/results/0/online"))
+ .map(JsonNode::asBoolean)
+ .orElse(false);
+ } catch (IllegalStateException e) {
+ throw new IllegalStateException("Could not poll primary index state for bucket: " + bucket.getName());
+ }
}
);
}
@@ -774,27 +795,6 @@ private String getInternalIpAddress() {
.orElseThrow(() -> new IllegalStateException("No network available to extract the internal IP from!"));
}
- /**
- * Helper method to check if the response is successful and release the body if needed.
- *
- * @param response the response to check.
- * @param message the message that should be part of the exception of not successful.
- */
- private void checkSuccessfulResponse(final Response response, final String message) {
- if (!response.isSuccessful()) {
- String body = null;
- if (response.body() != null) {
- try {
- body = response.body().string();
- } catch (IOException e) {
- logger().debug("Unable to read body of response: {}", response, e);
- }
- }
-
- throw new IllegalStateException(message + ": " + response + ", body=" + (body == null ? "" : body));
- }
- }
-
/**
* Checks if already running and if so raises an exception to prevent too-late setters.
*/
@@ -804,47 +804,10 @@ private void checkNotRunning() {
}
}
- /**
- * Helper method to perform a request against a couchbase server HTTP endpoint.
- *
- * @param port the (unmapped) original port that should be used.
- * @param path the relative http path.
- * @param method the http method to use.
- * @param body if present, will be part of the payload.
- * @param auth if authentication with the admin user and password should be used.
- * @return the response of the request.
- */
- private Response doHttpRequest(
- final int port,
- final String path,
- final String method,
- final RequestBody body,
- final boolean auth
- ) {
- try {
- Request.Builder requestBuilder = new Request.Builder()
- .url("http://" + getHost() + ":" + getMappedPort(port) + path);
-
- if (auth) {
- requestBuilder = requestBuilder.header("Authorization", Credentials.basic(username, password));
- }
-
- if (body == null) {
- requestBuilder = requestBuilder.get();
- } else {
- requestBuilder = requestBuilder.method(method, body);
- }
-
- return HTTP_CLIENT.newCall(requestBuilder.build()).execute();
- } catch (Exception ex) {
- throw new RuntimeException("Could not perform request against couchbase HTTP endpoint ", ex);
- }
- }
-
/**
* Helper method which times an individual phase and logs it for debugging and optimization purposes.
*
- * @param name the name of the phase.
+ * @param name the name of the phase.
* @param toTime the runnable that should be timed.
*/
private void timePhase(final String name, final Runnable toTime) {
@@ -859,7 +822,7 @@ private void timePhase(final String name, final Runnable toTime) {
* 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
+ * Fixes the issue observed in https://github.com/testcontainers/testcontainers-java/issues/2993
*/
private class AllServicesEnabledPredicate implements Predicate {