This is an automated email from the ASF dual-hosted git repository. ycai pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/cassandra-sidecar.git
The following commit(s) were added to refs/heads/trunk by this push: new 9d61f356 CASSANDRASC-118: Support sending json request (#112) 9d61f356 is described below commit 9d61f3568b7961de3f95e567d461e5103441a161 Author: Yifan Cai <52585731+yifa...@users.noreply.github.com> AuthorDate: Sat Apr 13 07:04:52 2024 -0700 CASSANDRASC-118: Support sending json request (#112) Patch by Yifan Cai; Reviewed by Francisco Guerrero for CASSANDRASC-118 --- CHANGES.txt | 1 + client/build.gradle | 1 + .../cassandra/sidecar/client/RequestExecutor.java | 8 +- .../client/request/CassandraJmxHealthRequest.java | 2 +- .../request/CassandraNativeHealthRequest.java | 2 +- .../client/request/CreateRestoreJobRequest.java | 5 +- .../request/CreateRestoreJobSliceRequest.java | 4 +- .../sidecar/client/request/GossipInfoRequest.java | 2 +- .../client/request/ImportSSTableRequest.java | 2 +- .../{DecodableRequest.java => JsonRequest.java} | 37 +++------- ...hRequest.java => JsonResponseBytesDecoder.java} | 35 +++++---- .../client/request/NodeSettingsRequest.java | 2 +- .../cassandra/sidecar/client/request/Request.java | 16 ++++ ...yloadRequest.java => ResponseBytesDecoder.java} | 15 +++- .../client/request/RestoreJobSummaryRequest.java | 2 +- .../sidecar/client/request/RingRequest.java | 2 +- .../sidecar/client/request/SchemaRequest.java | 2 +- .../client/request/SidecarHealthRequest.java | 2 +- .../sidecar/client/request/SnapshotRequest.java | 2 +- .../sidecar/client/request/TimeSkewRequest.java | 2 +- .../client/request/TokenRangeReplicasRequest.java | 2 +- .../client/request/UpdateRestoreJobRequest.java | 4 +- .../sidecar/client/request/JsonRequestTest.java} | 36 ++++----- ...Test.java => JsonResponseBytesDecoderTest.java} | 29 +------- .../sidecar/client/SidecarClientTest.java | 85 ++++++++++++++++------ .../cassandra/sidecar/client/VertxHttpClient.java | 31 +++++--- 26 files changed, 183 insertions(+), 148 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 43873923..76b571a8 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,5 +1,6 @@ 1.0.0 ----- + * Support sending json request (CASSANDRASC-118) * Add FilteringMetricRegistry to allow filtering of metrics (CASSANDRASC-115) * Allow for JmxClient to be extensible (CASSANDRASC-116) * Improve observability in Sidecar (CASSANDRASC-111) diff --git a/client/build.gradle b/client/build.gradle index 202a3a16..718b585e 100644 --- a/client/build.gradle +++ b/client/build.gradle @@ -86,6 +86,7 @@ dependencies { testFixturesImplementation("org.assertj:assertj-core:3.24.2") testFixturesImplementation('org.mockito:mockito-core:4.10.0') testFixturesImplementation('com.squareup.okhttp3:mockwebserver:4.10.0') + testFixturesImplementation(group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "${project.jacksonVersion}") testFixturesCompileOnly(group: 'io.netty', name: 'netty-codec-http', version: '4.1.69.Final') } diff --git a/client/src/main/java/org/apache/cassandra/sidecar/client/RequestExecutor.java b/client/src/main/java/org/apache/cassandra/sidecar/client/RequestExecutor.java index 3480dca0..d80225f3 100644 --- a/client/src/main/java/org/apache/cassandra/sidecar/client/RequestExecutor.java +++ b/client/src/main/java/org/apache/cassandra/sidecar/client/RequestExecutor.java @@ -32,8 +32,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import io.netty.handler.codec.http.HttpResponseStatus; -import org.apache.cassandra.sidecar.client.request.DecodableRequest; import org.apache.cassandra.sidecar.client.request.Request; +import org.apache.cassandra.sidecar.client.request.ResponseBytesDecoder; import static java.util.Objects.requireNonNull; @@ -344,10 +344,10 @@ public class RequestExecutor implements AutoCloseable try { - if (request instanceof DecodableRequest) + ResponseBytesDecoder<?> responseDecoder = request.responseBytesDecoder(); + if (responseDecoder != null) { - DecodableRequest<T> decodableRequest = (DecodableRequest<T>) request; - future.complete(decodableRequest.decode(response.raw())); + future.complete((T) responseDecoder.decode(response.raw())); } else { diff --git a/client/src/main/java/org/apache/cassandra/sidecar/client/request/CassandraJmxHealthRequest.java b/client/src/main/java/org/apache/cassandra/sidecar/client/request/CassandraJmxHealthRequest.java index 1d5644a8..946e0a86 100644 --- a/client/src/main/java/org/apache/cassandra/sidecar/client/request/CassandraJmxHealthRequest.java +++ b/client/src/main/java/org/apache/cassandra/sidecar/client/request/CassandraJmxHealthRequest.java @@ -25,7 +25,7 @@ import org.apache.cassandra.sidecar.common.data.HealthResponse; /** * Represents a request to retrieve the connectivity health checks performed against the Cassandra JMX protocol */ -public class CassandraJmxHealthRequest extends DecodableRequest<HealthResponse> +public class CassandraJmxHealthRequest extends JsonRequest<HealthResponse> { /** * Constructs a request to retrieve the Cassandra JMX health diff --git a/client/src/main/java/org/apache/cassandra/sidecar/client/request/CassandraNativeHealthRequest.java b/client/src/main/java/org/apache/cassandra/sidecar/client/request/CassandraNativeHealthRequest.java index 35960c9d..83a9667a 100644 --- a/client/src/main/java/org/apache/cassandra/sidecar/client/request/CassandraNativeHealthRequest.java +++ b/client/src/main/java/org/apache/cassandra/sidecar/client/request/CassandraNativeHealthRequest.java @@ -25,7 +25,7 @@ import org.apache.cassandra.sidecar.common.data.HealthResponse; /** * Represents a request to retrieve the connectivity health checks performed against the Cassandra native protocol */ -public class CassandraNativeHealthRequest extends DecodableRequest<HealthResponse> +public class CassandraNativeHealthRequest extends JsonRequest<HealthResponse> { /** * Constructs a request to retrieve the Cassandra native health diff --git a/client/src/main/java/org/apache/cassandra/sidecar/client/request/CreateRestoreJobRequest.java b/client/src/main/java/org/apache/cassandra/sidecar/client/request/CreateRestoreJobRequest.java index b1203895..c569911a 100644 --- a/client/src/main/java/org/apache/cassandra/sidecar/client/request/CreateRestoreJobRequest.java +++ b/client/src/main/java/org/apache/cassandra/sidecar/client/request/CreateRestoreJobRequest.java @@ -26,8 +26,7 @@ import org.apache.cassandra.sidecar.common.data.CreateRestoreJobResponsePayload; /** * Represents a request to create a restore job */ -public class CreateRestoreJobRequest extends DecodableRequest<CreateRestoreJobResponsePayload> -implements JsonPayloadRequest +public class CreateRestoreJobRequest extends JsonRequest<CreateRestoreJobResponsePayload> { private final CreateRestoreJobRequestPayload requestPayload; @@ -51,7 +50,7 @@ implements JsonPayloadRequest } @Override - public Object json() + public Object requestBody() { return requestPayload; } diff --git a/client/src/main/java/org/apache/cassandra/sidecar/client/request/CreateRestoreJobSliceRequest.java b/client/src/main/java/org/apache/cassandra/sidecar/client/request/CreateRestoreJobSliceRequest.java index 7c40c658..38ede8b8 100644 --- a/client/src/main/java/org/apache/cassandra/sidecar/client/request/CreateRestoreJobSliceRequest.java +++ b/client/src/main/java/org/apache/cassandra/sidecar/client/request/CreateRestoreJobSliceRequest.java @@ -27,7 +27,7 @@ import org.apache.cassandra.sidecar.common.data.CreateSliceRequestPayload; /** * Represents a request to create a restore job slice */ -public class CreateRestoreJobSliceRequest extends Request implements JsonPayloadRequest +public class CreateRestoreJobSliceRequest extends Request { private final CreateSliceRequestPayload payload; @@ -59,7 +59,7 @@ public class CreateRestoreJobSliceRequest extends Request implements JsonPayload } @Override - public Object json() + public Object requestBody() { return payload; } diff --git a/client/src/main/java/org/apache/cassandra/sidecar/client/request/GossipInfoRequest.java b/client/src/main/java/org/apache/cassandra/sidecar/client/request/GossipInfoRequest.java index 17d7cda7..7c739f43 100644 --- a/client/src/main/java/org/apache/cassandra/sidecar/client/request/GossipInfoRequest.java +++ b/client/src/main/java/org/apache/cassandra/sidecar/client/request/GossipInfoRequest.java @@ -25,7 +25,7 @@ import org.apache.cassandra.sidecar.common.data.GossipInfoResponse; /** * Represents a request to retrieve the Cassandra gossip information */ -public class GossipInfoRequest extends DecodableRequest<GossipInfoResponse> +public class GossipInfoRequest extends JsonRequest<GossipInfoResponse> { /** * Constructs a request to retrieve the Cassandra gossip information diff --git a/client/src/main/java/org/apache/cassandra/sidecar/client/request/ImportSSTableRequest.java b/client/src/main/java/org/apache/cassandra/sidecar/client/request/ImportSSTableRequest.java index 42e44957..09598994 100644 --- a/client/src/main/java/org/apache/cassandra/sidecar/client/request/ImportSSTableRequest.java +++ b/client/src/main/java/org/apache/cassandra/sidecar/client/request/ImportSSTableRequest.java @@ -29,7 +29,7 @@ import org.apache.cassandra.sidecar.common.data.SSTableImportResponse; /** * Represents a request to import SSTable components previously uploaded for an upload identifier */ -public class ImportSSTableRequest extends DecodableRequest<SSTableImportResponse> +public class ImportSSTableRequest extends JsonRequest<SSTableImportResponse> { /** * Constructs a decodable request with the provided {@code requestURI} diff --git a/client/src/main/java/org/apache/cassandra/sidecar/client/request/DecodableRequest.java b/client/src/main/java/org/apache/cassandra/sidecar/client/request/JsonRequest.java similarity index 52% rename from client/src/main/java/org/apache/cassandra/sidecar/client/request/DecodableRequest.java rename to client/src/main/java/org/apache/cassandra/sidecar/client/request/JsonRequest.java index f9fec279..291adceb 100644 --- a/client/src/main/java/org/apache/cassandra/sidecar/client/request/DecodableRequest.java +++ b/client/src/main/java/org/apache/cassandra/sidecar/client/request/JsonRequest.java @@ -18,53 +18,36 @@ package org.apache.cassandra.sidecar.client.request; -import java.io.IOException; import java.lang.reflect.ParameterizedType; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.ObjectMapper; - /** - * A request that can decode to the type {@code <T>} + * Json request that returns json response * - * @param <T> the type to decode + * @param <T> response type */ -public abstract class DecodableRequest<T> extends Request +public abstract class JsonRequest<T> extends Request { - static final ObjectMapper MAPPER = new ObjectMapper() - // ignore all the properties that are not declared - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - private final JavaType javaType = MAPPER.constructType(((ParameterizedType) this.getClass().getGenericSuperclass()) - .getActualTypeArguments()[0]); + private final JsonResponseBytesDecoder<T> responseDecoder; /** * Constructs a decodable request with the provided {@code requestURI} * * @param requestURI the URI of the request */ - protected DecodableRequest(String requestURI) + protected JsonRequest(String requestURI) { super(requestURI); + Class<T> type = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]; + this.responseDecoder = new JsonResponseBytesDecoder<>(type); } - /** - * Decodes the provided {@code bytes} to an instance of the type {@code <T>} - * - * @param bytes the raw bytes of the response - * @return the decoded instance for the given {@code bytes} - * @throws IOException when the decoder is unable to decode successfully - */ - public T decode(byte[] bytes) throws IOException + @Override + public ResponseBytesDecoder<T> responseBytesDecoder() { - if (bytes == null) - { - return null; - } - return MAPPER.readValue(bytes, javaType); + return responseDecoder; } @Override diff --git a/client/src/main/java/org/apache/cassandra/sidecar/client/request/CassandraJmxHealthRequest.java b/client/src/main/java/org/apache/cassandra/sidecar/client/request/JsonResponseBytesDecoder.java similarity index 52% copy from client/src/main/java/org/apache/cassandra/sidecar/client/request/CassandraJmxHealthRequest.java copy to client/src/main/java/org/apache/cassandra/sidecar/client/request/JsonResponseBytesDecoder.java index 1d5644a8..6bf14c0a 100644 --- a/client/src/main/java/org/apache/cassandra/sidecar/client/request/CassandraJmxHealthRequest.java +++ b/client/src/main/java/org/apache/cassandra/sidecar/client/request/JsonResponseBytesDecoder.java @@ -18,29 +18,34 @@ package org.apache.cassandra.sidecar.client.request; -import io.netty.handler.codec.http.HttpMethod; -import org.apache.cassandra.sidecar.common.ApiEndpointsV1; -import org.apache.cassandra.sidecar.common.data.HealthResponse; +import java.io.IOException; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; /** - * Represents a request to retrieve the connectivity health checks performed against the Cassandra JMX protocol + * Decoder for json response body bytes + * @param <T> expected java type */ -public class CassandraJmxHealthRequest extends DecodableRequest<HealthResponse> +public class JsonResponseBytesDecoder<T> implements ResponseBytesDecoder<T> { - /** - * Constructs a request to retrieve the Cassandra JMX health - */ - public CassandraJmxHealthRequest() + private static final ObjectMapper MAPPER = new ObjectMapper() + // ignore all the properties that are not declared + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + private final Class<T> type; + + public JsonResponseBytesDecoder(Class<T> type) { - super(ApiEndpointsV1.CASSANDRA_JMX_HEALTH_ROUTE); + this.type = type; } - /** - * {@inheritDoc} - */ @Override - public HttpMethod method() + public T decode(byte[] bytes) throws IOException { - return HttpMethod.GET; + if (bytes == null) + { + return null; + } + return MAPPER.readValue(bytes, type); } } diff --git a/client/src/main/java/org/apache/cassandra/sidecar/client/request/NodeSettingsRequest.java b/client/src/main/java/org/apache/cassandra/sidecar/client/request/NodeSettingsRequest.java index 0a274800..c9914673 100644 --- a/client/src/main/java/org/apache/cassandra/sidecar/client/request/NodeSettingsRequest.java +++ b/client/src/main/java/org/apache/cassandra/sidecar/client/request/NodeSettingsRequest.java @@ -25,7 +25,7 @@ import org.apache.cassandra.sidecar.common.NodeSettings; /** * Represents a request to retrieve the node settings */ -public class NodeSettingsRequest extends DecodableRequest<NodeSettings> +public class NodeSettingsRequest extends JsonRequest<NodeSettings> { /** * Constructs a request to retrieve the node settings diff --git a/client/src/main/java/org/apache/cassandra/sidecar/client/request/Request.java b/client/src/main/java/org/apache/cassandra/sidecar/client/request/Request.java index c7cb480f..51ee5626 100644 --- a/client/src/main/java/org/apache/cassandra/sidecar/client/request/Request.java +++ b/client/src/main/java/org/apache/cassandra/sidecar/client/request/Request.java @@ -79,6 +79,22 @@ public abstract class Request return requestURI; } + /** + * @return the request body. Returns null, when there is no request body. + */ + public Object requestBody() + { + return null; + } + + /** + * @return the response bytes decoder if configured, or null + */ + public ResponseBytesDecoder<?> responseBytesDecoder() + { + return null; + } + /** * {@inheritDoc} */ diff --git a/client/src/main/java/org/apache/cassandra/sidecar/client/request/JsonPayloadRequest.java b/client/src/main/java/org/apache/cassandra/sidecar/client/request/ResponseBytesDecoder.java similarity index 63% rename from client/src/main/java/org/apache/cassandra/sidecar/client/request/JsonPayloadRequest.java rename to client/src/main/java/org/apache/cassandra/sidecar/client/request/ResponseBytesDecoder.java index 5a6086ca..b5a4ae19 100644 --- a/client/src/main/java/org/apache/cassandra/sidecar/client/request/JsonPayloadRequest.java +++ b/client/src/main/java/org/apache/cassandra/sidecar/client/request/ResponseBytesDecoder.java @@ -18,13 +18,20 @@ package org.apache.cassandra.sidecar.client.request; +import java.io.IOException; + /** - * A request that contains json payload + * Decode response bytes into given java type {@code <T>} + * @param <T> expected java type */ -public interface JsonPayloadRequest +public interface ResponseBytesDecoder<T> { /** - * @return the JSON payload for the request + * Decodes the provided {@code bytes} to an instance of the type {@code <T>} + * + * @param bytes the raw bytes of the response + * @return the decoded instance for the given {@code bytes}, or null for null input + * @throws IOException when the decoder is unable to decode successfully */ - Object json(); + T decode(byte[] bytes) throws IOException; } diff --git a/client/src/main/java/org/apache/cassandra/sidecar/client/request/RestoreJobSummaryRequest.java b/client/src/main/java/org/apache/cassandra/sidecar/client/request/RestoreJobSummaryRequest.java index bd358a62..9126d66d 100644 --- a/client/src/main/java/org/apache/cassandra/sidecar/client/request/RestoreJobSummaryRequest.java +++ b/client/src/main/java/org/apache/cassandra/sidecar/client/request/RestoreJobSummaryRequest.java @@ -27,7 +27,7 @@ import org.apache.cassandra.sidecar.common.data.RestoreJobSummaryResponsePayload /** * Represents a request to retrieve the summary of a restore job */ -public class RestoreJobSummaryRequest extends DecodableRequest<RestoreJobSummaryResponsePayload> +public class RestoreJobSummaryRequest extends JsonRequest<RestoreJobSummaryResponsePayload> { /** * Constructs a Sidecar request with the given {@code requestURI}. Defaults to {@code ssl} enabled. diff --git a/client/src/main/java/org/apache/cassandra/sidecar/client/request/RingRequest.java b/client/src/main/java/org/apache/cassandra/sidecar/client/request/RingRequest.java index 5c835ef2..1f02a338 100644 --- a/client/src/main/java/org/apache/cassandra/sidecar/client/request/RingRequest.java +++ b/client/src/main/java/org/apache/cassandra/sidecar/client/request/RingRequest.java @@ -25,7 +25,7 @@ import org.apache.cassandra.sidecar.common.data.RingResponse; /** * Represents a request to retrieve the Cassandra ring information */ -public class RingRequest extends DecodableRequest<RingResponse> +public class RingRequest extends JsonRequest<RingResponse> { /** * Constructs a request to retrieve the Cassandra ring information diff --git a/client/src/main/java/org/apache/cassandra/sidecar/client/request/SchemaRequest.java b/client/src/main/java/org/apache/cassandra/sidecar/client/request/SchemaRequest.java index 09413020..625707bd 100644 --- a/client/src/main/java/org/apache/cassandra/sidecar/client/request/SchemaRequest.java +++ b/client/src/main/java/org/apache/cassandra/sidecar/client/request/SchemaRequest.java @@ -25,7 +25,7 @@ import org.apache.cassandra.sidecar.common.data.SchemaResponse; /** * Represents a request to retrieve the schema */ -public class SchemaRequest extends DecodableRequest<SchemaResponse> +public class SchemaRequest extends JsonRequest<SchemaResponse> { /** * Constructs a request to retrieve the full Cassandra schema diff --git a/client/src/main/java/org/apache/cassandra/sidecar/client/request/SidecarHealthRequest.java b/client/src/main/java/org/apache/cassandra/sidecar/client/request/SidecarHealthRequest.java index 49aa139f..e6c1a2e1 100644 --- a/client/src/main/java/org/apache/cassandra/sidecar/client/request/SidecarHealthRequest.java +++ b/client/src/main/java/org/apache/cassandra/sidecar/client/request/SidecarHealthRequest.java @@ -25,7 +25,7 @@ import org.apache.cassandra.sidecar.common.data.HealthResponse; /** * Represents a request to retrieve the Sidecar health */ -public class SidecarHealthRequest extends DecodableRequest<HealthResponse> +public class SidecarHealthRequest extends JsonRequest<HealthResponse> { /** * Constructs a request to retrieve the Sidecar health diff --git a/client/src/main/java/org/apache/cassandra/sidecar/client/request/SnapshotRequest.java b/client/src/main/java/org/apache/cassandra/sidecar/client/request/SnapshotRequest.java index c3cdc678..485ff543 100644 --- a/client/src/main/java/org/apache/cassandra/sidecar/client/request/SnapshotRequest.java +++ b/client/src/main/java/org/apache/cassandra/sidecar/client/request/SnapshotRequest.java @@ -26,7 +26,7 @@ import org.jetbrains.annotations.Nullable; * * @param <T> the type of the decodable request */ -abstract class SnapshotRequest<T> extends DecodableRequest<T> +abstract class SnapshotRequest<T> extends JsonRequest<T> { SnapshotRequest(String keyspace, String table, String snapshotName) { diff --git a/client/src/main/java/org/apache/cassandra/sidecar/client/request/TimeSkewRequest.java b/client/src/main/java/org/apache/cassandra/sidecar/client/request/TimeSkewRequest.java index 586c8456..99df1914 100644 --- a/client/src/main/java/org/apache/cassandra/sidecar/client/request/TimeSkewRequest.java +++ b/client/src/main/java/org/apache/cassandra/sidecar/client/request/TimeSkewRequest.java @@ -25,7 +25,7 @@ import org.apache.cassandra.sidecar.common.data.TimeSkewResponse; /** * Represents a request to retrieve information from the time skew endpoint */ -public class TimeSkewRequest extends DecodableRequest<TimeSkewResponse> +public class TimeSkewRequest extends JsonRequest<TimeSkewResponse> { /** * Constructs a new request to retrieve information from the time skew endpoint diff --git a/client/src/main/java/org/apache/cassandra/sidecar/client/request/TokenRangeReplicasRequest.java b/client/src/main/java/org/apache/cassandra/sidecar/client/request/TokenRangeReplicasRequest.java index cc7f8034..143a3960 100644 --- a/client/src/main/java/org/apache/cassandra/sidecar/client/request/TokenRangeReplicasRequest.java +++ b/client/src/main/java/org/apache/cassandra/sidecar/client/request/TokenRangeReplicasRequest.java @@ -25,7 +25,7 @@ import org.apache.cassandra.sidecar.common.data.TokenRangeReplicasResponse; /** * Represents a request to retrieve information from the token-range replicas endpoint */ -public class TokenRangeReplicasRequest extends DecodableRequest<TokenRangeReplicasResponse> +public class TokenRangeReplicasRequest extends JsonRequest<TokenRangeReplicasResponse> { /** * Constructs a new request to retrieve information by keyspace from token-range replicas endpoint diff --git a/client/src/main/java/org/apache/cassandra/sidecar/client/request/UpdateRestoreJobRequest.java b/client/src/main/java/org/apache/cassandra/sidecar/client/request/UpdateRestoreJobRequest.java index eba2a0e5..919689ab 100644 --- a/client/src/main/java/org/apache/cassandra/sidecar/client/request/UpdateRestoreJobRequest.java +++ b/client/src/main/java/org/apache/cassandra/sidecar/client/request/UpdateRestoreJobRequest.java @@ -27,7 +27,7 @@ import org.apache.cassandra.sidecar.common.data.UpdateRestoreJobRequestPayload; /** * Represents a request to update a restore job */ -public class UpdateRestoreJobRequest extends Request implements JsonPayloadRequest +public class UpdateRestoreJobRequest extends Request { private final UpdateRestoreJobRequestPayload requestPayload; @@ -53,7 +53,7 @@ public class UpdateRestoreJobRequest extends Request implements JsonPayloadReque } @Override - public Object json() + public Object requestBody() { return requestPayload; } diff --git a/client/src/main/java/org/apache/cassandra/sidecar/client/request/NodeSettingsRequest.java b/client/src/test/java/org/apache/cassandra/sidecar/client/request/JsonRequestTest.java similarity index 62% copy from client/src/main/java/org/apache/cassandra/sidecar/client/request/NodeSettingsRequest.java copy to client/src/test/java/org/apache/cassandra/sidecar/client/request/JsonRequestTest.java index 0a274800..c756807c 100644 --- a/client/src/main/java/org/apache/cassandra/sidecar/client/request/NodeSettingsRequest.java +++ b/client/src/test/java/org/apache/cassandra/sidecar/client/request/JsonRequestTest.java @@ -18,29 +18,29 @@ package org.apache.cassandra.sidecar.client.request; + +import org.junit.jupiter.api.Test; + import io.netty.handler.codec.http.HttpMethod; -import org.apache.cassandra.sidecar.common.ApiEndpointsV1; import org.apache.cassandra.sidecar.common.NodeSettings; -/** - * Represents a request to retrieve the node settings - */ -public class NodeSettingsRequest extends DecodableRequest<NodeSettings> +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +class JsonRequestTest { - /** - * Constructs a request to retrieve the node settings - */ - public NodeSettingsRequest() + @Test + void testHeadersAreImmutable() { - super(ApiEndpointsV1.NODE_SETTINGS_ROUTE); - } + JsonRequest<NodeSettings> instance = new JsonRequest<NodeSettings>("https://cassandra-sidecar.com/api/test") + { + @Override + public HttpMethod method() + { + return HttpMethod.GET; + } + }; - /** - * {@inheritDoc} - */ - @Override - public HttpMethod method() - { - return HttpMethod.GET; + assertThatExceptionOfType(UnsupportedOperationException.class) + .isThrownBy(() -> instance.headers().put("not", "allowed")); } } diff --git a/client/src/test/java/org/apache/cassandra/sidecar/client/request/DecodableRequestTest.java b/client/src/test/java/org/apache/cassandra/sidecar/client/request/JsonResponseBytesDecoderTest.java similarity index 72% rename from client/src/test/java/org/apache/cassandra/sidecar/client/request/DecodableRequestTest.java rename to client/src/test/java/org/apache/cassandra/sidecar/client/request/JsonResponseBytesDecoderTest.java index e37dc9ab..cb9e2e1e 100644 --- a/client/src/test/java/org/apache/cassandra/sidecar/client/request/DecodableRequestTest.java +++ b/client/src/test/java/org/apache/cassandra/sidecar/client/request/JsonResponseBytesDecoderTest.java @@ -21,34 +21,18 @@ package org.apache.cassandra.sidecar.client.request; import java.io.IOException; import java.nio.charset.StandardCharsets; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import io.netty.handler.codec.http.HttpMethod; import org.apache.cassandra.sidecar.common.NodeSettings; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; /** - * Unit tests for the {@link DecodableRequest} class + * Unit tests for the {@link JsonRequest} class */ -class DecodableRequestTest +class JsonResponseBytesDecoderTest { - DecodableRequest<NodeSettings> instance; - - @BeforeEach - void setup() - { - instance = new DecodableRequest<NodeSettings>("https://cassandra-sidecar.com/api/test") - { - @Override - public HttpMethod method() - { - return HttpMethod.GET; - } - }; - } + JsonResponseBytesDecoder<NodeSettings> instance = new JsonResponseBytesDecoder<>(NodeSettings.class); @Test void testDecode() throws IOException @@ -71,11 +55,4 @@ class DecodableRequestTest assertThat(nodeSettings.partitioner()).isEqualTo("partitioner-value"); assertThat(nodeSettings.releaseVersion()).isEqualTo("1.0-TEST"); } - - @Test - void testHeadersAreImmutable() - { - assertThatExceptionOfType(UnsupportedOperationException.class) - .isThrownBy(() -> instance.headers().put("not", "allowed")); - } } diff --git a/client/src/testFixtures/java/org/apache/cassandra/sidecar/client/SidecarClientTest.java b/client/src/testFixtures/java/org/apache/cassandra/sidecar/client/SidecarClientTest.java index e06b7091..1854e7aa 100644 --- a/client/src/testFixtures/java/org/apache/cassandra/sidecar/client/SidecarClientTest.java +++ b/client/src/testFixtures/java/org/apache/cassandra/sidecar/client/SidecarClientTest.java @@ -21,6 +21,7 @@ package org.apache.cassandra.sidecar.client; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; @@ -34,6 +35,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.function.Consumer; import java.util.stream.Collectors; import org.junit.jupiter.api.AfterEach; @@ -41,6 +43,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; +import com.fasterxml.jackson.databind.ObjectMapper; import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpHeaderValues; import okhttp3.mockwebserver.MockResponse; @@ -80,6 +83,9 @@ import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST; import static io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR; import static io.netty.handler.codec.http.HttpResponseStatus.OK; import static io.netty.handler.codec.http.HttpResponseStatus.PARTIAL_CONTENT; +import static org.apache.cassandra.sidecar.common.ApiEndpointsV1.JOB_ID_PATH_PARAM; +import static org.apache.cassandra.sidecar.common.ApiEndpointsV1.KEYSPACE_PATH_PARAM; +import static org.apache.cassandra.sidecar.common.ApiEndpointsV1.TABLE_PATH_PARAM; import static org.apache.cassandra.sidecar.common.http.SidecarHttpHeaderNames.CONTENT_XXHASH32; import static org.apache.cassandra.sidecar.common.http.SidecarHttpHeaderNames.CONTENT_XXHASH32_SEED; import static org.assertj.core.api.Assertions.assertThat; @@ -283,7 +289,7 @@ abstract class SidecarClientTest assertThat(result.keyspace()).isEqualTo("cycling"); assertThat(result.schema()).isEqualTo("CREATE KEYSPACE sample_ks.sample_table ..."); - validateResponseServed(ApiEndpointsV1.KEYSPACE_SCHEMA_ROUTE.replaceAll(ApiEndpointsV1.KEYSPACE_PATH_PARAM, + validateResponseServed(ApiEndpointsV1.KEYSPACE_SCHEMA_ROUTE.replaceAll(KEYSPACE_PATH_PARAM, "cycling")); } @@ -312,7 +318,7 @@ abstract class SidecarClientTest assertThat(entry.fqdn()).isEqualTo("local"); assertThat(entry.hostId()).isEqualTo("000"); - validateResponseServed(ApiEndpointsV1.RING_ROUTE_PER_KEYSPACE.replaceAll(ApiEndpointsV1.KEYSPACE_PATH_PARAM, + validateResponseServed(ApiEndpointsV1.RING_ROUTE_PER_KEYSPACE.replaceAll(KEYSPACE_PATH_PARAM, "cycling")); } @@ -450,7 +456,7 @@ abstract class SidecarClientTest assertThat(instanceMetadata.datacenter()).isEqualTo("datacenter1"); validateResponseServed(ApiEndpointsV1.KEYSPACE_TOKEN_MAPPING_ROUTE.replaceAll( - ApiEndpointsV1.KEYSPACE_PATH_PARAM, keyspace)); + KEYSPACE_PATH_PARAM, keyspace)); } @Test @@ -484,7 +490,7 @@ abstract class SidecarClientTest assertThat(mockWebServer.getRequestCount()).isEqualTo(1); RecordedRequest request = mockWebServer.takeRequest(); assertThat(request.getPath()).isEqualTo(ApiEndpointsV1.SNAPSHOTS_ROUTE - .replaceAll(ApiEndpointsV1.KEYSPACE_PATH_PARAM, "cycling") + .replaceAll(KEYSPACE_PATH_PARAM, "cycling") .replaceAll(ApiEndpointsV1.TABLE_PATH_PARAM, "cyclist_name") .replaceAll(ApiEndpointsV1.SNAPSHOT_PATH_PARAM, "2023.04.11") + "?includeSecondaryIndexFiles=true"); @@ -522,7 +528,7 @@ abstract class SidecarClientTest assertThat(mockWebServer.getRequestCount()).isEqualTo(1); RecordedRequest request = mockWebServer.takeRequest(); assertThat(request.getPath()).isEqualTo(ApiEndpointsV1.SNAPSHOTS_ROUTE - .replaceAll(ApiEndpointsV1.KEYSPACE_PATH_PARAM, "cycling") + .replaceAll(KEYSPACE_PATH_PARAM, "cycling") .replaceAll(ApiEndpointsV1.TABLE_PATH_PARAM, "cyclist_name") .replaceAll(ApiEndpointsV1.SNAPSHOT_PATH_PARAM, "2023.04.11")); } @@ -542,7 +548,7 @@ abstract class SidecarClientTest assertThat(mockWebServer.getRequestCount()).isEqualTo(1); RecordedRequest request = mockWebServer.takeRequest(); assertThat(request.getPath()).isEqualTo(ApiEndpointsV1.SNAPSHOTS_ROUTE - .replaceAll(ApiEndpointsV1.KEYSPACE_PATH_PARAM, "cycling") + .replaceAll(KEYSPACE_PATH_PARAM, "cycling") .replaceAll(ApiEndpointsV1.TABLE_PATH_PARAM, "cyclist_name") .replaceAll(ApiEndpointsV1.SNAPSHOT_PATH_PARAM, "2023.04.11")); assertThat(request.getMethod()).isEqualTo("DELETE"); @@ -562,7 +568,7 @@ abstract class SidecarClientTest assertThat(mockWebServer.getRequestCount()).isEqualTo(1); RecordedRequest request = mockWebServer.takeRequest(); assertThat(request.getPath()).isEqualTo(ApiEndpointsV1.SNAPSHOTS_ROUTE - .replaceAll(ApiEndpointsV1.KEYSPACE_PATH_PARAM, "cycling") + .replaceAll(KEYSPACE_PATH_PARAM, "cycling") .replaceAll(ApiEndpointsV1.TABLE_PATH_PARAM, "cyclist_name") .replaceAll(ApiEndpointsV1.SNAPSHOT_PATH_PARAM, "2023.04.11")); assertThat(request.getMethod()).isEqualTo("PUT"); @@ -582,7 +588,7 @@ abstract class SidecarClientTest assertThat(mockWebServer.getRequestCount()).isEqualTo(1); RecordedRequest request = mockWebServer.takeRequest(); String expected = ApiEndpointsV1.SNAPSHOTS_ROUTE - .replaceAll(ApiEndpointsV1.KEYSPACE_PATH_PARAM, "cycling") + .replaceAll(KEYSPACE_PATH_PARAM, "cycling") .replaceAll(ApiEndpointsV1.TABLE_PATH_PARAM, "cyclist_name") .replaceAll(ApiEndpointsV1.SNAPSHOT_PATH_PARAM, "2023.04.11") + "?ttl=2d"; assertThat(request.getPath()).isEqualTo(expected); @@ -634,7 +640,7 @@ abstract class SidecarClientTest assertThat(mockWebServer.getRequestCount()).isEqualTo(1); RecordedRequest request = mockWebServer.takeRequest(); assertThat(request.getPath()).isEqualTo(ApiEndpointsV1.SSTABLE_IMPORT_ROUTE - .replaceAll(ApiEndpointsV1.KEYSPACE_PATH_PARAM, "cycling") + .replaceAll(KEYSPACE_PATH_PARAM, "cycling") .replaceAll(ApiEndpointsV1.TABLE_PATH_PARAM, "cyclist_name") .replaceAll(ApiEndpointsV1.UPLOAD_ID_PATH_PARAM, "0000-0000")); assertThat(request.getMethod()).isEqualTo("PUT"); @@ -670,7 +676,7 @@ abstract class SidecarClientTest assertThat(mockWebServer.getRequestCount()).isEqualTo(5); RecordedRequest request = mockWebServer.takeRequest(); assertThat(request.getPath()).isEqualTo(ApiEndpointsV1.SSTABLE_IMPORT_ROUTE - .replaceAll(ApiEndpointsV1.KEYSPACE_PATH_PARAM, "cycling") + .replaceAll(KEYSPACE_PATH_PARAM, "cycling") .replaceAll(ApiEndpointsV1.TABLE_PATH_PARAM, "cyclist_name") .replaceAll(ApiEndpointsV1.UPLOAD_ID_PATH_PARAM, "0000-0000")); assertThat(request.getMethod()).isEqualTo("PUT"); @@ -715,7 +721,7 @@ abstract class SidecarClientTest assertThat(request.getPath()) .isEqualTo(ApiEndpointsV1.SSTABLE_UPLOAD_ROUTE .replaceAll(ApiEndpointsV1.UPLOAD_ID_PATH_PARAM, "0000-0000") - .replaceAll(ApiEndpointsV1.KEYSPACE_PATH_PARAM, "cycling") + .replaceAll(KEYSPACE_PATH_PARAM, "cycling") .replaceAll(ApiEndpointsV1.TABLE_PATH_PARAM, "cyclist_name") .replaceAll(ApiEndpointsV1.COMPONENT_PATH_PARAM, "nb-1-big-TOC.txt")); assertThat(request.getMethod()).isEqualTo("PUT"); @@ -748,7 +754,7 @@ abstract class SidecarClientTest assertThat(request.getPath()) .isEqualTo(ApiEndpointsV1.SSTABLE_UPLOAD_ROUTE .replaceAll(ApiEndpointsV1.UPLOAD_ID_PATH_PARAM, "0000-0000") - .replaceAll(ApiEndpointsV1.KEYSPACE_PATH_PARAM, "cycling") + .replaceAll(KEYSPACE_PATH_PARAM, "cycling") .replaceAll(ApiEndpointsV1.TABLE_PATH_PARAM, "cyclist_name") .replaceAll(ApiEndpointsV1.COMPONENT_PATH_PARAM, "nb-1-big-TOC.txt")); assertThat(request.getMethod()).isEqualTo("PUT"); @@ -782,7 +788,7 @@ abstract class SidecarClientTest assertThat(request.getPath()) .isEqualTo(ApiEndpointsV1.SSTABLE_UPLOAD_ROUTE .replaceAll(ApiEndpointsV1.UPLOAD_ID_PATH_PARAM, "0000-0000") - .replaceAll(ApiEndpointsV1.KEYSPACE_PATH_PARAM, "cycling") + .replaceAll(KEYSPACE_PATH_PARAM, "cycling") .replaceAll(ApiEndpointsV1.TABLE_PATH_PARAM, "cyclist_name") .replaceAll(ApiEndpointsV1.COMPONENT_PATH_PARAM, "nb-1-big-TOC.txt")); assertThat(request.getMethod()).isEqualTo("PUT"); @@ -817,7 +823,7 @@ abstract class SidecarClientTest assertThat(request.getPath()) .isEqualTo(ApiEndpointsV1.SSTABLE_UPLOAD_ROUTE .replaceAll(ApiEndpointsV1.UPLOAD_ID_PATH_PARAM, "0000-0000") - .replaceAll(ApiEndpointsV1.KEYSPACE_PATH_PARAM, "cycling") + .replaceAll(KEYSPACE_PATH_PARAM, "cycling") .replaceAll(ApiEndpointsV1.TABLE_PATH_PARAM, "cyclist_name") .replaceAll(ApiEndpointsV1.COMPONENT_PATH_PARAM, "nb-1-big-TOC.txt")); assertThat(request.getMethod()).isEqualTo("PUT"); @@ -895,7 +901,7 @@ abstract class SidecarClientTest RecordedRequest request = server.takeRequest(); assertThat(request.getPath()) .isEqualTo(ApiEndpointsV1.COMPONENTS_ROUTE - .replaceAll(ApiEndpointsV1.KEYSPACE_PATH_PARAM, "cycling") + .replaceAll(KEYSPACE_PATH_PARAM, "cycling") .replaceAll(ApiEndpointsV1.TABLE_PATH_PARAM, "cyclist_name") .replaceAll(ApiEndpointsV1.SNAPSHOT_PATH_PARAM, "2023.04.12") .replaceAll(ApiEndpointsV1.COMPONENT_PATH_PARAM, "nb-203-big-Data.db")); @@ -974,7 +980,7 @@ abstract class SidecarClientTest RecordedRequest request = server.takeRequest(); assertThat(request.getPath()) .isEqualTo(ApiEndpointsV1.COMPONENTS_ROUTE - .replaceAll(ApiEndpointsV1.KEYSPACE_PATH_PARAM, "cycling") + .replaceAll(KEYSPACE_PATH_PARAM, "cycling") .replaceAll(ApiEndpointsV1.TABLE_PATH_PARAM, "cyclist_name") .replaceAll(ApiEndpointsV1.SNAPSHOT_PATH_PARAM, "2023.04.12") .replaceAll(ApiEndpointsV1.COMPONENT_PATH_PARAM, "nb-203-big-Data.db")); @@ -1057,7 +1063,7 @@ abstract class SidecarClientTest RecordedRequest request = server.takeRequest(); assertThat(request.getPath()) .isEqualTo(ApiEndpointsV1.COMPONENTS_ROUTE - .replaceAll(ApiEndpointsV1.KEYSPACE_PATH_PARAM, "cycling") + .replaceAll(KEYSPACE_PATH_PARAM, "cycling") .replaceAll(ApiEndpointsV1.TABLE_PATH_PARAM, "cyclist_name") .replaceAll(ApiEndpointsV1.SNAPSHOT_PATH_PARAM, "2023.04.12") .replaceAll(ApiEndpointsV1.COMPONENT_PATH_PARAM, "nb-203-big-Data.db")); @@ -1126,7 +1132,7 @@ abstract class SidecarClientTest RecordedRequest request3 = server.takeRequest(); assertThat(request3.getPath()) .isEqualTo(ApiEndpointsV1.COMPONENTS_ROUTE - .replaceAll(ApiEndpointsV1.KEYSPACE_PATH_PARAM, "cycling") + .replaceAll(KEYSPACE_PATH_PARAM, "cycling") .replaceAll(ApiEndpointsV1.TABLE_PATH_PARAM, "cyclist_name") .replaceAll(ApiEndpointsV1.SNAPSHOT_PATH_PARAM, "2023.04.12") .replaceAll(ApiEndpointsV1.COMPONENT_PATH_PARAM, "nb-203-big-Data.db")); @@ -1206,13 +1212,14 @@ abstract class SidecarClientTest } @Test - void testAcceptCreateRestoreJobRequest() + void testAcceptCreateRestoreJobRequest() throws Exception { + String jobIdStr = "8e5799a4-d277-11ed-8d85-6916bb9b8056"; enqueue(new MockResponse() .setResponseCode(OK.code()) - .setBody("{\"jobId\":\"8e5799a4-d277-11ed-8d85-6916bb9b8056\",\"status\":\"CREATED\"}")); + .setBody("{\"jobId\":\"" + jobIdStr + "\",\"status\":\"CREATED\"}")); - UUID jobId = UUID.fromString("8e5799a4-d277-11ed-8d85-6916bb9b8056"); + UUID jobId = UUID.fromString(jobIdStr); long expireAt = System.currentTimeMillis() + 10000; RestoreJobSecrets secrets = RestoreJobSecretsGen.genRestoreJobSecrets(); CreateRestoreJobRequestPayload requestPayload = CreateRestoreJobRequestPayload.builder(secrets, expireAt) @@ -1226,17 +1233,30 @@ abstract class SidecarClientTest assertThat(responsePayload).isNotNull(); assertThat(responsePayload.jobId()).isEqualTo(jobId); assertThat(responsePayload.status()).isEqualTo("CREATED"); + + ObjectMapper mapper = new ObjectMapper(); + String expectedReqBodyString = mapper.writeValueAsString(requestPayload); + validateResponseServed(ApiEndpointsV1.CREATE_RESTORE_JOB_ROUTE + .replaceAll(KEYSPACE_PATH_PARAM, "cycling") + .replaceAll(TABLE_PATH_PARAM, "rank_by_year_and_name") + .replaceAll(JOB_ID_PATH_PARAM, jobIdStr), + recordedRequest -> { + String reqBodyString = recordedRequest.getBody() + .readString(Charset.defaultCharset()); + assertThat(reqBodyString).isEqualTo(expectedReqBodyString); + }); } @Test - void testCreateRestoreJobShouldNotRetryOnDifferentHostWithBadRequest() + void testCreateRestoreJobShouldNotRetryOnDifferentHostWithBadRequest() throws Exception { + String jobIdStr = "8e5799a4-d277-11ed-8d85-6916bb9b8056"; enqueue(new MockResponse() .setResponseCode(BAD_REQUEST.code()) .setBody("{\"status\":\"Fail\"," + "\"message\":\"Error while decoding values, check your request body\"}")); - UUID jobId = UUID.fromString("8e5799a4-d277-11ed-8d85-6916bb9b8056"); + UUID jobId = UUID.fromString(jobIdStr); long expireAt = System.currentTimeMillis() + 10000; RestoreJobSecrets secrets = RestoreJobSecretsGen.genRestoreJobSecrets(); CreateRestoreJobRequestPayload requestPayload = CreateRestoreJobRequestPayload.builder(secrets, expireAt) @@ -1249,6 +1269,18 @@ abstract class SidecarClientTest .withCauseInstanceOf(RetriesExhaustedException.class) .withMessageContaining("Unable to complete request '/api/v1/keyspaces/" + "badkeyspace/tables/bad_table/restore-jobs' after 1 attempt"); + + ObjectMapper mapper = new ObjectMapper(); + String expectedReqBodyString = mapper.writeValueAsString(requestPayload); + validateResponseServed(ApiEndpointsV1.CREATE_RESTORE_JOB_ROUTE + .replaceAll(KEYSPACE_PATH_PARAM, "badkeyspace") + .replaceAll(TABLE_PATH_PARAM, "bad_table") + .replaceAll(JOB_ID_PATH_PARAM, jobIdStr), + recordedRequest -> { + String reqBodyString = recordedRequest.getBody() + .readString(Charset.defaultCharset()); + assertThat(reqBodyString).isEqualTo(expectedReqBodyString); + }); } private void enqueue(MockResponse response) @@ -1260,6 +1292,12 @@ abstract class SidecarClientTest } private void validateResponseServed(String expectedEndpointPath) throws InterruptedException + { + validateResponseServed(expectedEndpointPath, req -> { }); + } + + private void validateResponseServed(String expectedEndpointPath, + Consumer<RecordedRequest> serverReceivedRequestVerifier) throws InterruptedException { for (MockWebServer server : servers) { @@ -1267,6 +1305,7 @@ abstract class SidecarClientTest { assertThat(server.getRequestCount()).isEqualTo(1); RecordedRequest request = server.takeRequest(); + serverReceivedRequestVerifier.accept(request); assertThat(request.getPath()).isEqualTo(expectedEndpointPath); return; } diff --git a/vertx-client/src/main/java/org/apache/cassandra/sidecar/client/VertxHttpClient.java b/vertx-client/src/main/java/org/apache/cassandra/sidecar/client/VertxHttpClient.java index 02a07c38..ecc6ebd2 100644 --- a/vertx-client/src/main/java/org/apache/cassandra/sidecar/client/VertxHttpClient.java +++ b/vertx-client/src/main/java/org/apache/cassandra/sidecar/client/VertxHttpClient.java @@ -130,22 +130,29 @@ public class VertxHttpClient implements HttpClient protected CompletableFuture<HttpResponse> executeInternal(SidecarInstance sidecarInstance, RequestContext context) { - HttpRequest<Buffer> vertxRequest = vertxRequest(sidecarInstance, context); - Promise<HttpResponse> promise = Promise.promise(); - vertxRequest.ssl(config.ssl()) - .timeout(config.timeoutMillis()) - .send() - .onFailure(promise::fail) - .onSuccess(response -> { - byte[] raw = response.body() != null ? response.body().getBytes() : null; - promise.complete(new HttpResponseImpl(response.statusCode(), + Future<HttpRequest<Buffer>> future = Future.future(promise -> promise.complete(vertxRequest(sidecarInstance, context) + .ssl(config.ssl()) + .timeout(config.timeoutMillis()))); + + return future + .compose(vertxRequest -> { + Request request = context.request(); + if (request.requestBody() != null) + { + return vertxRequest.sendJson(request.requestBody()); + } + return vertxRequest.send(); + }) + .map(response -> { + byte[] raw = response.body() != null ? response.body().getBytes() : null; + return (HttpResponse) new HttpResponseImpl(response.statusCode(), response.statusMessage(), raw, mapHeaders(response.headers()), sidecarInstance - )); - }); - return promise.future().toCompletionStage().toCompletableFuture(); + ); + }) + .toCompletionStage().toCompletableFuture(); } protected CompletableFuture<HttpResponse> executeUploadFileInternal(SidecarInstance sidecarInstance, --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org For additional commands, e-mail: commits-h...@cassandra.apache.org