From d0b39cea608a467e677d73f4fbe013f7e75d6b9c Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Tue, 14 Oct 2025 15:48:05 +0200 Subject: [PATCH 01/28] Add the Response Handing Params container and implement error_trace handling Signed-off-by: Sergei Ustimenko --- .../opensearch/transport/grpc/GrpcPlugin.java | 14 +++-- .../grpc/Netty4GrpcServerTransport.java | 6 ++ .../listeners/BulkRequestActionListener.java | 12 ++-- .../SearchRequestActionListener.java | 12 ++-- .../bulk/BulkItemResponseProtoUtils.java | 7 ++- .../document/bulk/BulkResponseProtoUtils.java | 5 +- .../common/DocWriteResponseProtoUtils.java | 5 +- .../document/common/ShardInfoProtoUtils.java | 9 +-- .../exceptions/ResponseHandlingParams.java | 36 ++++++++++++ .../OpenSearchExceptionProtoUtils.java | 25 ++++---- ...ardOperationFailedExceptionProtoUtils.java | 27 ++++----- ...ionResponseShardInfoFailureProtoUtils.java | 5 +- ...ardOperationFailedExceptionProtoUtils.java | 11 ++-- .../ShardSearchFailureProtoUtils.java | 5 +- .../SnapshotShardFailureProtoUtils.java | 17 ++++-- .../search/ProtoActionsProtoUtils.java | 6 +- .../search/SearchResponseProtoUtils.java | 24 ++++---- .../search/ShardStatisticsProtoUtils.java | 6 +- .../grpc/services/DocumentServiceImpl.java | 11 +++- .../grpc/services/SearchServiceImpl.java | 15 +++-- .../transport/grpc/util/GrpcErrorHandler.java | 58 +++++++++++-------- 21 files changed, 208 insertions(+), 108 deletions(-) create mode 100644 modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/ResponseHandlingParams.java diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/GrpcPlugin.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/GrpcPlugin.java index 47db838ef4fb4..4db1343f1418e 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/GrpcPlugin.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/GrpcPlugin.java @@ -56,6 +56,7 @@ import static org.opensearch.transport.grpc.Netty4GrpcServerTransport.GRPC_TRANSPORT_SETTING_KEY; import static org.opensearch.transport.grpc.Netty4GrpcServerTransport.SETTING_GRPC_BIND_HOST; +import static org.opensearch.transport.grpc.Netty4GrpcServerTransport.SETTING_GRPC_DETAILED_ERRORS_ENABLED; import static org.opensearch.transport.grpc.Netty4GrpcServerTransport.SETTING_GRPC_EXECUTOR_COUNT; import static org.opensearch.transport.grpc.Netty4GrpcServerTransport.SETTING_GRPC_HOST; import static org.opensearch.transport.grpc.Netty4GrpcServerTransport.SETTING_GRPC_KEEPALIVE_TIMEOUT; @@ -205,9 +206,10 @@ public Map> getAuxTransports( throw new IllegalStateException("createComponents must be called before getAuxTransports to initialize the registry"); } + boolean detailedErrorsEnabled = SETTING_GRPC_DETAILED_ERRORS_ENABLED.get(settings); List grpcServices = registerGRPCServices( - new DocumentServiceImpl(client), - new SearchServiceImpl(client, queryUtils) + new DocumentServiceImpl(client, detailedErrorsEnabled), + new SearchServiceImpl(client, queryUtils, detailedErrorsEnabled) ); return Collections.singletonMap( GRPC_TRANSPORT_SETTING_KEY, @@ -248,9 +250,10 @@ public Map> getSecureAuxTransports( throw new IllegalStateException("createComponents must be called before getSecureAuxTransports to initialize the registry"); } + boolean detailedErrorsEnabled = SETTING_GRPC_DETAILED_ERRORS_ENABLED.get(settings); List grpcServices = registerGRPCServices( - new DocumentServiceImpl(client), - new SearchServiceImpl(client, queryUtils) + new DocumentServiceImpl(client, detailedErrorsEnabled), + new SearchServiceImpl(client, queryUtils, detailedErrorsEnabled) ); return Collections.singletonMap( GRPC_SECURE_TRANSPORT_SETTING_KEY, @@ -295,7 +298,8 @@ public List> getSettings() { SETTING_GRPC_MAX_MSG_SIZE, SETTING_GRPC_MAX_CONNECTION_AGE, SETTING_GRPC_MAX_CONNECTION_IDLE, - SETTING_GRPC_KEEPALIVE_TIMEOUT + SETTING_GRPC_KEEPALIVE_TIMEOUT, + SETTING_GRPC_DETAILED_ERRORS_ENABLED ); } diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/Netty4GrpcServerTransport.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/Netty4GrpcServerTransport.java index de2fb0079c652..73d5fc2c9128a 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/Netty4GrpcServerTransport.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/Netty4GrpcServerTransport.java @@ -186,6 +186,12 @@ public class Netty4GrpcServerTransport extends AuxTransport { Setting.Property.NodeScope ); + public static final Setting SETTING_GRPC_DETAILED_ERRORS_ENABLED = Setting.boolSetting( + "grpc.detailed_errors.enabled", + true, + Setting.Property.NodeScope + ); + /** * Port range on which servers bind. */ diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListener.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListener.java index 6e1f6306c2aae..14110c199fd3d 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListener.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListener.java @@ -13,6 +13,7 @@ import org.opensearch.action.bulk.BulkResponse; import org.opensearch.core.action.ActionListener; import org.opensearch.transport.grpc.proto.response.document.bulk.BulkResponseProtoUtils; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import org.opensearch.transport.grpc.util.GrpcErrorHandler; import java.io.IOException; @@ -26,15 +27,18 @@ public class BulkRequestActionListener implements ActionListener { private static final Logger logger = LogManager.getLogger(BulkRequestActionListener.class); private final StreamObserver responseObserver; + private final ResponseHandlingParams params; /** * Creates a new BulkRequestActionListener. * * @param responseObserver The gRPC stream observer to send the response back to the client + * @param params */ - public BulkRequestActionListener(StreamObserver responseObserver) { + public BulkRequestActionListener(StreamObserver responseObserver, ResponseHandlingParams params) { super(); this.responseObserver = responseObserver; + this.params = params; } /** @@ -47,12 +51,12 @@ public BulkRequestActionListener(StreamObserver responseObserver; + private final ResponseHandlingParams params; + /** * Constructs a new SearchRequestActionListener. * * @param responseObserver the gRPC stream observer to send the search response to */ - public SearchRequestActionListener(StreamObserver responseObserver) { + public SearchRequestActionListener(StreamObserver responseObserver, ResponseHandlingParams params) { super(); this.responseObserver = responseObserver; + this.params = params; } @Override public void onResponse(SearchResponse response) { // Search execution succeeded. Convert the opensearch internal response to protobuf try { - org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(response); + org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(response, params); responseObserver.onNext(protoResponse); responseObserver.onCompleted(); } catch (RuntimeException | IOException e) { logger.error("Failed to convert search response to protobuf: " + e.getMessage()); - StatusRuntimeException grpcError = GrpcErrorHandler.convertToGrpcError(e); + StatusRuntimeException grpcError = GrpcErrorHandler.convertToGrpcError(e, params); responseObserver.onError(grpcError); } } @@ -55,7 +59,7 @@ public void onResponse(SearchResponse response) { @Override public void onFailure(Exception e) { logger.debug("SearchRequestActionListener failed to process search request: " + e.getMessage()); - StatusRuntimeException grpcError = GrpcErrorHandler.convertToGrpcError(e); + StatusRuntimeException grpcError = GrpcErrorHandler.convertToGrpcError(e, params); responseObserver.onError(grpcError); } } diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtils.java index aba831ef632e3..eab4349eb57f3 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtils.java @@ -19,6 +19,7 @@ import org.opensearch.protobufs.ResponseItem; import org.opensearch.transport.grpc.proto.response.document.common.DocWriteResponseProtoUtils; import org.opensearch.transport.grpc.proto.response.document.get.GetResultProtoUtils; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import org.opensearch.transport.grpc.proto.response.exceptions.opensearchexception.OpenSearchExceptionProtoUtils; import org.opensearch.transport.grpc.util.RestToGrpcStatusConverter; @@ -45,12 +46,12 @@ private BulkItemResponseProtoUtils() { * @throws IOException if there's an error during conversion * */ - public static ResponseItem toProto(BulkItemResponse response) throws IOException { + public static ResponseItem toProto(BulkItemResponse response, ResponseHandlingParams params) throws IOException { ResponseItem.Builder responseItemBuilder; if (response.isFailed() == false) { DocWriteResponse docResponse = response.getResponse(); - responseItemBuilder = DocWriteResponseProtoUtils.toProto(docResponse); + responseItemBuilder = DocWriteResponseProtoUtils.toProto(docResponse, params); int grpcStatusCode = RestToGrpcStatusConverter.getGrpcStatusCode(docResponse.status()); responseItemBuilder.setStatus(grpcStatusCode); @@ -67,7 +68,7 @@ public static ResponseItem toProto(BulkItemResponse response) throws IOException int grpcStatusCode = RestToGrpcStatusConverter.getGrpcStatusCode(failure.getStatus()); responseItemBuilder.setStatus(grpcStatusCode); - ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(failure.getCause()); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(failure.getCause(), params); responseItemBuilder.setError(errorCause); } diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkResponseProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkResponseProtoUtils.java index 0522ad9bb5740..beca944e7feda 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkResponseProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkResponseProtoUtils.java @@ -11,6 +11,7 @@ import org.opensearch.action.bulk.BulkResponse; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import java.io.IOException; @@ -33,7 +34,7 @@ private BulkResponseProtoUtils() { * @return A Protocol Buffer BulkResponse representation * @throws IOException if there's an error during conversion */ - public static org.opensearch.protobufs.BulkResponse toProto(BulkResponse response) throws IOException { + public static org.opensearch.protobufs.BulkResponse toProto(BulkResponse response, ResponseHandlingParams params) throws IOException { // System.out.println("=== grpc bulk response=" + response.toString()); org.opensearch.protobufs.BulkResponse.Builder bulkResponse = org.opensearch.protobufs.BulkResponse.newBuilder(); @@ -51,7 +52,7 @@ public static org.opensearch.protobufs.BulkResponse toProto(BulkResponse respons // Add individual item responses for each operation in the bulk request for (BulkItemResponse bulkItemResponse : response.getItems()) { - org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto(bulkItemResponse); + org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto(bulkItemResponse, params); org.opensearch.protobufs.Item.Builder itemBuilder = org.opensearch.protobufs.Item.newBuilder(); // Wrap ResponseItem in Item based on operation type diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtils.java index 57f2cad3f90d8..efb7ec7eed89f 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtils.java @@ -14,6 +14,7 @@ import org.opensearch.protobufs.NullValue; import org.opensearch.protobufs.ResponseItem; import org.opensearch.protobufs.ShardInfo; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import java.io.IOException; @@ -36,7 +37,7 @@ private DocWriteResponseProtoUtils() { * @return A ResponseItem.Builder with the DocWriteResponse data * */ - public static ResponseItem.Builder toProto(DocWriteResponse response) throws IOException { + public static ResponseItem.Builder toProto(DocWriteResponse response, ResponseHandlingParams params) throws IOException { ResponseItem.Builder responseItem = ResponseItem.newBuilder(); // Set the index name @@ -60,7 +61,7 @@ public static ResponseItem.Builder toProto(DocWriteResponse response) throws IOE responseItem.setForcedRefresh(true); } // Handle shard information - ShardInfo shardInfo = ShardInfoProtoUtils.toProto(response.getShardInfo()); + ShardInfo shardInfo = ShardInfoProtoUtils.toProto(response.getShardInfo(), params); responseItem.setXShards(shardInfo); // Set sequence number and primary term if available diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtils.java index 7b519ad6153cd..7f1f2a7ff7303 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtils.java @@ -12,6 +12,7 @@ import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.protobufs.ShardFailure; import org.opensearch.protobufs.ShardInfo; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import org.opensearch.transport.grpc.proto.response.exceptions.opensearchexception.OpenSearchExceptionProtoUtils; import java.io.IOException; @@ -33,7 +34,7 @@ private ShardInfoProtoUtils() { * @return The protobuf representation of the shard information * @throws IOException If there's an error during conversion */ - public static ShardInfo toProto(ReplicationResponse.ShardInfo shardInfo) throws IOException { + public static ShardInfo toProto(ReplicationResponse.ShardInfo shardInfo, ResponseHandlingParams params) throws IOException { ShardInfo.Builder shardInfoBuilder = ShardInfo.newBuilder(); shardInfoBuilder.setTotal(shardInfo.getTotal()); shardInfoBuilder.setSuccessful(shardInfo.getSuccessful()); @@ -41,7 +42,7 @@ public static ShardInfo toProto(ReplicationResponse.ShardInfo shardInfo) throws // Add any shard failures for (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) { - shardInfoBuilder.addFailures(toProto(failure)); + shardInfoBuilder.addFailures(toProto(failure, params)); } return shardInfoBuilder.build(); @@ -55,12 +56,12 @@ public static ShardInfo toProto(ReplicationResponse.ShardInfo shardInfo) throws * @return The protobuf representation of the shard failure * @throws IOException If there's an error during conversion */ - private static ShardFailure toProto(ReplicationResponse.ShardInfo.Failure failure) throws IOException { + private static ShardFailure toProto(ReplicationResponse.ShardInfo.Failure failure, ResponseHandlingParams params) throws IOException { ShardFailure.Builder shardFailure = ShardFailure.newBuilder(); shardFailure.setIndex(failure.index()); shardFailure.setShard(failure.shardId()); shardFailure.setNode(failure.nodeId()); - shardFailure.setReason(OpenSearchExceptionProtoUtils.generateThrowableProto(failure.getCause())); + shardFailure.setReason(OpenSearchExceptionProtoUtils.generateThrowableProto(failure.getCause(), params)); shardFailure.setStatus(failure.status().name()); shardFailure.setPrimary(failure.primary()); return shardFailure.build(); diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/ResponseHandlingParams.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/ResponseHandlingParams.java new file mode 100644 index 0000000000000..c879419dd4739 --- /dev/null +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/ResponseHandlingParams.java @@ -0,0 +1,36 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.transport.grpc.proto.response.exceptions; + +public class ResponseHandlingParams { + + private final TracingLevel errorTracingLevel; + + public ResponseHandlingParams(boolean detailedErrorsEnabled, boolean errorTracesRequested) { + this.errorTracingLevel = getTracingLevel(detailedErrorsEnabled, errorTracesRequested); + } + + public TracingLevel getErrorTracingLevel() { + return errorTracingLevel; + } + + private static TracingLevel getTracingLevel(boolean detailedErrorsEnabled, boolean errorTracesRequested) { + if (detailedErrorsEnabled == false && errorTracesRequested) { + return TracingLevel.TRACING_DISABLED; + } + return errorTracesRequested ? TracingLevel.DETAILED_TRACE : TracingLevel.SUMMARY; + } + + public enum TracingLevel { + SUMMARY, + DETAILED_TRACE, + TRACING_DISABLED + } + +} diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/opensearchexception/OpenSearchExceptionProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/opensearchexception/OpenSearchExceptionProtoUtils.java index d5606c8f91831..d0fc4ba833722 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/opensearchexception/OpenSearchExceptionProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/opensearchexception/OpenSearchExceptionProtoUtils.java @@ -26,6 +26,7 @@ import org.opensearch.transport.grpc.proto.response.exceptions.CircuitBreakingExceptionProtoUtils; import org.opensearch.transport.grpc.proto.response.exceptions.FailedNodeExceptionProtoUtils; import org.opensearch.transport.grpc.proto.response.exceptions.ParsingExceptionProtoUtils; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import org.opensearch.transport.grpc.proto.response.exceptions.ResponseLimitBreachedExceptionProtoUtils; import org.opensearch.transport.grpc.proto.response.exceptions.ScriptExceptionProtoUtils; import org.opensearch.transport.grpc.proto.response.exceptions.SearchParseExceptionProtoUtils; @@ -59,10 +60,10 @@ private OpenSearchExceptionProtoUtils() { * @return A Protocol Buffer ErrorCause representation * @throws IOException if there's an error during conversion */ - public static ErrorCause toProto(OpenSearchException exception) throws IOException { + public static ErrorCause toProto(OpenSearchException exception, ResponseHandlingParams params) throws IOException { Throwable ex = ExceptionsHelper.unwrapCause(exception); if (ex != exception) { - return generateThrowableProto(ex); + return generateThrowableProto(ex, params); } else { return innerToProto( exception, @@ -70,7 +71,8 @@ public static ErrorCause toProto(OpenSearchException exception) throws IOExcepti exception.getMessage(), exception.getHeaders(), exception.getMetadata(), - exception.getCause() + exception.getCause(), + params ); } } @@ -86,13 +88,13 @@ public static ErrorCause toProto(OpenSearchException exception) throws IOExcepti * @return A Protocol Buffer ErrorCause representation * @throws IOException if there's an error during conversion */ - public static ErrorCause generateThrowableProto(Throwable t) throws IOException { + public static ErrorCause generateThrowableProto(Throwable t, ResponseHandlingParams params) throws IOException { t = ExceptionsHelper.unwrapCause(t); if (t instanceof OpenSearchException) { - return toProto((OpenSearchException) t); + return toProto((OpenSearchException) t, params); } else { - return innerToProto(t, getExceptionName(t), t.getMessage(), emptyMap(), emptyMap(), t.getCause()); + return innerToProto(t, getExceptionName(t), t.getMessage(), emptyMap(), emptyMap(), t.getCause(), params); } } @@ -115,7 +117,8 @@ public static ErrorCause innerToProto( String message, Map> headers, Map> metadata, - Throwable cause + Throwable cause, + ResponseHandlingParams params ) throws IOException { ErrorCause.Builder errorCauseBuilder = ErrorCause.newBuilder(); @@ -146,7 +149,7 @@ public static ErrorCause innerToProto( } if (cause != null) { - errorCauseBuilder.setCausedBy(generateThrowableProto(cause)); + errorCauseBuilder.setCausedBy(generateThrowableProto(cause, params)); } if (headers.isEmpty() == false) { @@ -157,13 +160,15 @@ public static ErrorCause innerToProto( } // Add stack trace - errorCauseBuilder.setStackTrace(ExceptionsHelper.stackTrace(throwable)); + if (params.getErrorTracingLevel() == ResponseHandlingParams.TracingLevel.DETAILED_TRACE) { + errorCauseBuilder.setStackTrace(ExceptionsHelper.stackTrace(throwable)); + } // Add suppressed exceptions Throwable[] allSuppressed = throwable.getSuppressed(); if (allSuppressed.length > 0) { for (Throwable suppressed : allSuppressed) { - errorCauseBuilder.addSuppressed(generateThrowableProto(suppressed)); + errorCauseBuilder.addSuppressed(generateThrowableProto(suppressed, params)); } } diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtils.java index e58782e35d057..297764cc1486a 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtils.java @@ -14,6 +14,7 @@ import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.protobufs.ShardFailure; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import org.opensearch.transport.grpc.proto.response.exceptions.opensearchexception.OpenSearchExceptionProtoUtils; import java.io.IOException; @@ -35,17 +36,17 @@ private DefaultShardOperationFailedExceptionProtoUtils() { * @param exception The DefaultShardOperationFailedException to convert * @return A Protocol Buffer Struct containing the exception metadata */ - public static ShardFailure toProto(DefaultShardOperationFailedException exception) throws IOException { + public static ShardFailure toProto(DefaultShardOperationFailedException exception, ResponseHandlingParams params) throws IOException { ShardFailure.Builder shardFailureBuilder = ShardFailure.newBuilder(); if (exception instanceof AddIndexBlockResponse.AddBlockShardResult.Failure) { - innerToProto(shardFailureBuilder, (AddIndexBlockResponse.AddBlockShardResult.Failure) exception); + innerToProto(shardFailureBuilder, (AddIndexBlockResponse.AddBlockShardResult.Failure) exception, params); } else if (exception instanceof IndicesShardStoresResponse.Failure) { - innerToProto(shardFailureBuilder, (IndicesShardStoresResponse.Failure) exception); + innerToProto(shardFailureBuilder, (IndicesShardStoresResponse.Failure) exception, params); } else if (exception instanceof CloseIndexResponse.ShardResult.Failure) { - innerToProto(shardFailureBuilder, (CloseIndexResponse.ShardResult.Failure) exception); + innerToProto(shardFailureBuilder, (CloseIndexResponse.ShardResult.Failure) exception, params); } else { - parentInnerToProto(shardFailureBuilder, exception); + parentInnerToProto(shardFailureBuilder, exception, params); } return shardFailureBuilder.build(); } @@ -58,12 +59,12 @@ public static ShardFailure toProto(DefaultShardOperationFailedException exceptio * @param exception The AddIndexBlockResponse.AddBlockShardResult.Failure to convert * @throws IOException if there's an error during conversion */ - public static void innerToProto(ShardFailure.Builder shardFailureBuilder, AddIndexBlockResponse.AddBlockShardResult.Failure exception) + public static void innerToProto(ShardFailure.Builder shardFailureBuilder, AddIndexBlockResponse.AddBlockShardResult.Failure exception,ResponseHandlingParams params) throws IOException { if (exception.getNodeId() != null) { shardFailureBuilder.setNode(exception.getNodeId()); } - parentInnerToProto(shardFailureBuilder, exception); + parentInnerToProto(shardFailureBuilder, exception, params); } /** @@ -74,10 +75,10 @@ public static void innerToProto(ShardFailure.Builder shardFailureBuilder, AddInd * @param exception The IndicesShardStoresResponse.Failure to convert * @throws IOException if there's an error during conversion */ - public static void innerToProto(ShardFailure.Builder shardFailureBuilder, IndicesShardStoresResponse.Failure exception) + public static void innerToProto(ShardFailure.Builder shardFailureBuilder, IndicesShardStoresResponse.Failure exception, ResponseHandlingParams params) throws IOException { shardFailureBuilder.setNode(exception.nodeId()); - parentInnerToProto(shardFailureBuilder, exception); + parentInnerToProto(shardFailureBuilder, exception, params); } /** @@ -88,12 +89,12 @@ public static void innerToProto(ShardFailure.Builder shardFailureBuilder, Indice * @param exception The CloseIndexResponse.ShardResult.Failure to convert * @throws IOException if there's an error during conversion */ - public static void innerToProto(ShardFailure.Builder shardFailureBuilder, CloseIndexResponse.ShardResult.Failure exception) + public static void innerToProto(ShardFailure.Builder shardFailureBuilder, CloseIndexResponse.ShardResult.Failure exception, ResponseHandlingParams params) throws IOException { if (exception.getNodeId() != null) { shardFailureBuilder.setNode(exception.getNodeId()); } - parentInnerToProto(shardFailureBuilder, exception); + parentInnerToProto(shardFailureBuilder, exception, params); } /** @@ -104,7 +105,7 @@ public static void innerToProto(ShardFailure.Builder shardFailureBuilder, CloseI * @param exception The DefaultShardOperationFailedException to convert * @throws IOException if there's an error during conversion */ - public static void parentInnerToProto(ShardFailure.Builder shardFailureBuilder, DefaultShardOperationFailedException exception) + public static void parentInnerToProto(ShardFailure.Builder shardFailureBuilder, DefaultShardOperationFailedException exception, ResponseHandlingParams params) throws IOException { shardFailureBuilder.setShard(exception.shardId()); if (exception.index() != null) { @@ -112,7 +113,7 @@ public static void parentInnerToProto(ShardFailure.Builder shardFailureBuilder, } shardFailureBuilder.setStatus(exception.status().name()); if (exception.reason() != null) { - shardFailureBuilder.setReason(OpenSearchExceptionProtoUtils.generateThrowableProto(exception.getCause())); + shardFailureBuilder.setReason(OpenSearchExceptionProtoUtils.generateThrowableProto(exception.getCause(), params)); } } } diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ReplicationResponseShardInfoFailureProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ReplicationResponseShardInfoFailureProtoUtils.java index deb1e2fcf4cd1..baa295552e2ed 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ReplicationResponseShardInfoFailureProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ReplicationResponseShardInfoFailureProtoUtils.java @@ -11,6 +11,7 @@ import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.protobufs.ShardFailure; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import org.opensearch.transport.grpc.proto.response.exceptions.opensearchexception.OpenSearchExceptionProtoUtils; import java.io.IOException; @@ -31,7 +32,7 @@ private ReplicationResponseShardInfoFailureProtoUtils() { * @param exception The ReplicationResponse.ShardInfo.Failure to convert metadata from * @return A map containing the exception's metadata as ObjectMap.Value objects */ - public static ShardFailure toProto(ReplicationResponse.ShardInfo.Failure exception) throws IOException { + public static ShardFailure toProto(ReplicationResponse.ShardInfo.Failure exception, ResponseHandlingParams params) throws IOException { ShardFailure.Builder shardFailure = ShardFailure.newBuilder(); if (exception.index() != null) { shardFailure.setIndex(exception.index()); @@ -40,7 +41,7 @@ public static ShardFailure toProto(ReplicationResponse.ShardInfo.Failure excepti if (exception.nodeId() != null) { shardFailure.setNode(exception.nodeId()); } - shardFailure.setReason(OpenSearchExceptionProtoUtils.generateThrowableProto(exception.getCause())); + shardFailure.setReason(OpenSearchExceptionProtoUtils.generateThrowableProto(exception.getCause(), params)); shardFailure.setStatus(exception.status().name()); shardFailure.setPrimary(exception.primary()); return shardFailure.build(); diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtils.java index b2c60d4ab7044..f55aeb5b45fbc 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtils.java @@ -15,6 +15,7 @@ import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.protobufs.ShardFailure; import org.opensearch.snapshots.SnapshotShardFailure; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import java.io.IOException; @@ -34,15 +35,15 @@ private ShardOperationFailedExceptionProtoUtils() { * @param exception The ShardOperationFailedException to convert metadata from * @return ShardFailure */ - public static ShardFailure toProto(ShardOperationFailedException exception) throws IOException { + public static ShardFailure toProto(ShardOperationFailedException exception, ResponseHandlingParams params) throws IOException { if (exception instanceof ShardSearchFailure) { - return ShardSearchFailureProtoUtils.toProto((ShardSearchFailure) exception); + return ShardSearchFailureProtoUtils.toProto((ShardSearchFailure) exception, params); } else if (exception instanceof SnapshotShardFailure) { - return SnapshotShardFailureProtoUtils.toProto((SnapshotShardFailure) exception); + return SnapshotShardFailureProtoUtils.toProto((SnapshotShardFailure) exception, params); } else if (exception instanceof DefaultShardOperationFailedException) { - return DefaultShardOperationFailedExceptionProtoUtils.toProto((DefaultShardOperationFailedException) exception); + return DefaultShardOperationFailedExceptionProtoUtils.toProto((DefaultShardOperationFailedException) exception, params); } else if (exception instanceof ReplicationResponse.ShardInfo.Failure) { - return ReplicationResponseShardInfoFailureProtoUtils.toProto((ReplicationResponse.ShardInfo.Failure) exception); + return ReplicationResponseShardInfoFailureProtoUtils.toProto((ReplicationResponse.ShardInfo.Failure) exception, params); } else { throw new UnsupportedOperationException( "Unsupported ShardOperationFailedException " + exception.getClass().getName() + "cannot be converted to proto." diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardSearchFailureProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardSearchFailureProtoUtils.java index 4d8c4555f7389..65c76ba6b9b40 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardSearchFailureProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardSearchFailureProtoUtils.java @@ -11,6 +11,7 @@ import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.protobufs.ShardFailure; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import org.opensearch.transport.grpc.proto.response.exceptions.opensearchexception.OpenSearchExceptionProtoUtils; import java.io.IOException; @@ -31,14 +32,14 @@ private ShardSearchFailureProtoUtils() { * @param exception The ShardSearchFailure to convert * @return A Protocol Buffer Struct containing the exception metadata */ - public static ShardFailure toProto(ShardSearchFailure exception) throws IOException { + public static ShardFailure toProto(ShardSearchFailure exception, ResponseHandlingParams params) throws IOException { ShardFailure.Builder shardFailure = ShardFailure.newBuilder(); shardFailure.setShard(exception.shardId()); shardFailure.setIndex(exception.index()); if (exception.shard() != null && exception.shard().getNodeId() != null) { shardFailure.setNode(exception.shard().getNodeId()); } - shardFailure.setReason(OpenSearchExceptionProtoUtils.generateThrowableProto(exception.getCause())); + shardFailure.setReason(OpenSearchExceptionProtoUtils.generateThrowableProto(exception.getCause(), params)); return shardFailure.build(); } } diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/SnapshotShardFailureProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/SnapshotShardFailureProtoUtils.java index a5cf33fad567a..acbfa1593a39b 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/SnapshotShardFailureProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/SnapshotShardFailureProtoUtils.java @@ -7,10 +7,14 @@ */ package org.opensearch.transport.grpc.proto.response.exceptions.shardoperationfailedexception; +import java.io.IOException; + import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.protobufs.ShardFailure; import org.opensearch.snapshots.SnapshotShardFailure; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; +import org.opensearch.transport.grpc.proto.response.exceptions.opensearchexception.OpenSearchExceptionProtoUtils; /** * Utility class for converting SnapshotShardFailure objects to Protocol Buffers. @@ -28,15 +32,18 @@ private SnapshotShardFailureProtoUtils() { * @param exception The SnapshotShardFailure to convert * @return A Protocol Buffer Struct containing the exception metadata */ - public static ShardFailure toProto(SnapshotShardFailure exception) { + public static ShardFailure toProto(SnapshotShardFailure exception, ResponseHandlingParams params) throws IOException { ShardFailure.Builder shardFailure = ShardFailure.newBuilder(); - shardFailure.setIndex(exception.index()); + if (exception.index() != null) { + shardFailure.setIndex(exception.index()); + } // shardFailure.setIndexUuid(exception.index()); // TODO no field called index_uuid in ShardFailure protos shardFailure.setShard(exception.shardId()); - // shardFailure.setReason(exception.reason()); // TODO ErrorCause type in ShardFailure, not string - shardFailure.setIndex(exception.index()); - shardFailure.setNode(exception.nodeId()); + if (exception.nodeId() != null) { + shardFailure.setNode(exception.nodeId()); + } shardFailure.setStatus(exception.status().name()); + shardFailure.setReason(OpenSearchExceptionProtoUtils.generateThrowableProto(exception.getCause(), params)); return shardFailure.build(); } } diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/ProtoActionsProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/ProtoActionsProtoUtils.java index 5913c858d7d6d..fd44fcb06482e 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/ProtoActionsProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/ProtoActionsProtoUtils.java @@ -13,6 +13,7 @@ import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.protobufs.SearchResponse; import org.opensearch.rest.action.RestActions; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import java.io.IOException; @@ -44,8 +45,9 @@ protected static void buildBroadcastShardsHeader( int successful, int skipped, int failed, - ShardOperationFailedException[] shardFailures + ShardOperationFailedException[] shardFailures, + ResponseHandlingParams params ) throws IOException { - searchResponseProtoBuilder.setXShards(ShardStatisticsProtoUtils.getShardStats(total, successful, skipped, failed, shardFailures)); + searchResponseProtoBuilder.setXShards(ShardStatisticsProtoUtils.getShardStats(total, successful, skipped, failed, shardFailures, params)); } } diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtils.java index 287d1f47b9126..8d888129d07a8 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtils.java @@ -7,14 +7,15 @@ */ package org.opensearch.transport.grpc.proto.response.search; +import java.io.IOException; +import java.util.Map; + import org.opensearch.action.search.SearchPhaseName; import org.opensearch.action.search.SearchResponse; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.protobufs.ClusterStatistics; - -import java.io.IOException; -import java.util.Map; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; /** * Utility class for converting SearchResponse objects to Protocol Buffers. @@ -35,9 +36,9 @@ private SearchResponseProtoUtils() { * @return A Protocol Buffer SearchResponse representation * @throws IOException if there's an error during conversion */ - public static org.opensearch.protobufs.SearchResponse toProto(SearchResponse response) throws IOException { + public static org.opensearch.protobufs.SearchResponse toProto(SearchResponse response, ResponseHandlingParams params) throws IOException { org.opensearch.protobufs.SearchResponse.Builder searchResponseProtoBuilder = org.opensearch.protobufs.SearchResponse.newBuilder(); - toProto(response, searchResponseProtoBuilder); + toProto(response, searchResponseProtoBuilder, params); return searchResponseProtoBuilder.build(); } @@ -47,9 +48,11 @@ public static org.opensearch.protobufs.SearchResponse toProto(SearchResponse res * * @param response The SearchResponse to convert * @param searchResponseProtoBuilder The builder to populate with the SearchResponse data + * @param params * @throws IOException if there's an error during conversion */ - public static void toProto(SearchResponse response, org.opensearch.protobufs.SearchResponse.Builder searchResponseProtoBuilder) + public static void toProto(SearchResponse response, org.opensearch.protobufs.SearchResponse.Builder searchResponseProtoBuilder, + ResponseHandlingParams params) throws IOException { // Set optional fields only if they exist @@ -86,7 +89,8 @@ public static void toProto(SearchResponse response, org.opensearch.protobufs.Sea response.getSuccessfulShards(), response.getSkippedShards(), response.getFailedShards(), - response.getShardFailures() + response.getShardFailures(), + params ); // Add clusters information @@ -189,9 +193,9 @@ protected static void toProto( if (clusters.getTotal() > 0) { // Create and populate the cluster statistics builder ClusterStatistics.Builder clusterStatistics = ClusterStatistics.newBuilder() - .setTotal(clusters.getTotal()) - .setSuccessful(clusters.getSuccessful()) - .setSkipped(clusters.getSkipped()); + .setTotal(clusters.getTotal()) + .setSuccessful(clusters.getSuccessful()) + .setSkipped(clusters.getSkipped()); // Set the clusters field in the response builder protoResponseBuilder.setXClusters(clusterStatistics.build()); diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/ShardStatisticsProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/ShardStatisticsProtoUtils.java index 05aad90870ad4..18f64015b89f8 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/ShardStatisticsProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/ShardStatisticsProtoUtils.java @@ -14,6 +14,7 @@ import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.protobufs.ShardStatistics; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import org.opensearch.transport.grpc.proto.response.exceptions.shardoperationfailedexception.ShardOperationFailedExceptionProtoUtils; import java.io.IOException; @@ -46,7 +47,8 @@ protected static ShardStatistics getShardStats( int successful, int skipped, int failed, - ShardOperationFailedException[] shardFailures + ShardOperationFailedException[] shardFailures, + ResponseHandlingParams params ) throws IOException { ShardStatistics.Builder shardStats = ShardStatistics.newBuilder(); shardStats.setTotal(total); @@ -57,7 +59,7 @@ protected static ShardStatistics getShardStats( shardStats.setFailed(failed); if (CollectionUtils.isEmpty(shardFailures) == false) { for (ShardOperationFailedException shardFailure : ExceptionsHelper.groupBy(shardFailures)) { - shardStats.addFailures(ShardOperationFailedExceptionProtoUtils.toProto(shardFailure)); + shardStats.addFailures(ShardOperationFailedExceptionProtoUtils.toProto(shardFailure, params)); } } return shardStats.build(); diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/services/DocumentServiceImpl.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/services/DocumentServiceImpl.java index e1348bc78961f..5add67652d7ed 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/services/DocumentServiceImpl.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/services/DocumentServiceImpl.java @@ -14,6 +14,7 @@ import org.opensearch.transport.client.Client; import org.opensearch.transport.grpc.listeners.BulkRequestActionListener; import org.opensearch.transport.grpc.proto.request.document.bulk.BulkRequestProtoUtils; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import org.opensearch.transport.grpc.util.GrpcErrorHandler; import io.grpc.StatusRuntimeException; @@ -25,14 +26,17 @@ public class DocumentServiceImpl extends DocumentServiceGrpc.DocumentServiceImplBase { private static final Logger logger = LogManager.getLogger(DocumentServiceImpl.class); private final Client client; + private final boolean detailedErrorsEnabled; /** * Creates a new DocumentServiceImpl. * * @param client Client for executing actions on the local node + * @param detailedErrorsEnabled */ - public DocumentServiceImpl(Client client) { + public DocumentServiceImpl(Client client, boolean detailedErrorsEnabled) { this.client = client; + this.detailedErrorsEnabled = detailedErrorsEnabled; } /** @@ -43,13 +47,14 @@ public DocumentServiceImpl(Client client) { */ @Override public void bulk(org.opensearch.protobufs.BulkRequest request, StreamObserver responseObserver) { + ResponseHandlingParams params = new ResponseHandlingParams(detailedErrorsEnabled, request.getGlobalParams().getErrorTrace()); try { org.opensearch.action.bulk.BulkRequest bulkRequest = BulkRequestProtoUtils.prepareRequest(request); - BulkRequestActionListener listener = new BulkRequestActionListener(responseObserver); + BulkRequestActionListener listener = new BulkRequestActionListener(responseObserver, params); client.bulk(bulkRequest, listener); } catch (RuntimeException e) { logger.debug("DocumentServiceImpl failed: {} - {}", e.getClass().getSimpleName(), e.getMessage()); - StatusRuntimeException grpcError = GrpcErrorHandler.convertToGrpcError(e); + StatusRuntimeException grpcError = GrpcErrorHandler.convertToGrpcError(e, params); responseObserver.onError(grpcError); } } diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/services/SearchServiceImpl.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/services/SearchServiceImpl.java index f5bca635c19ab..9ba15955c129f 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/services/SearchServiceImpl.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/services/SearchServiceImpl.java @@ -8,6 +8,8 @@ package org.opensearch.transport.grpc.services; +import java.io.IOException; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.opensearch.protobufs.services.SearchServiceGrpc; @@ -15,10 +17,9 @@ import org.opensearch.transport.grpc.listeners.SearchRequestActionListener; import org.opensearch.transport.grpc.proto.request.search.SearchRequestProtoUtils; import org.opensearch.transport.grpc.proto.request.search.query.AbstractQueryBuilderProtoUtils; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import org.opensearch.transport.grpc.util.GrpcErrorHandler; -import java.io.IOException; - import io.grpc.StatusRuntimeException; import io.grpc.stub.StreamObserver; @@ -31,6 +32,7 @@ public class SearchServiceImpl extends SearchServiceGrpc.SearchServiceImplBase { private static final Logger logger = LogManager.getLogger(SearchServiceImpl.class); private final Client client; private final AbstractQueryBuilderProtoUtils queryUtils; + private final boolean detailedErrorsEnabled; /** * Creates a new SearchServiceImpl. @@ -38,7 +40,7 @@ public class SearchServiceImpl extends SearchServiceGrpc.SearchServiceImplBase { * @param client Client for executing actions on the local node * @param queryUtils Query utils instance for parsing protobuf queries */ - public SearchServiceImpl(Client client, AbstractQueryBuilderProtoUtils queryUtils) { + public SearchServiceImpl(Client client, AbstractQueryBuilderProtoUtils queryUtils, boolean detailedErrorsEnabled) { if (client == null) { throw new IllegalArgumentException("Client cannot be null"); } @@ -48,6 +50,7 @@ public SearchServiceImpl(Client client, AbstractQueryBuilderProtoUtils queryUtil this.client = client; this.queryUtils = queryUtils; + this.detailedErrorsEnabled = detailedErrorsEnabled; } /** @@ -61,14 +64,14 @@ public void search( org.opensearch.protobufs.SearchRequest request, StreamObserver responseObserver ) { - + ResponseHandlingParams params = new ResponseHandlingParams(detailedErrorsEnabled, request.getGlobalParams().getErrorTrace()); try { org.opensearch.action.search.SearchRequest searchRequest = SearchRequestProtoUtils.prepareRequest(request, client, queryUtils); - SearchRequestActionListener listener = new SearchRequestActionListener(responseObserver); + SearchRequestActionListener listener = new SearchRequestActionListener(responseObserver, params); client.search(searchRequest, listener); } catch (RuntimeException | IOException e) { logger.debug("SearchServiceImpl failed to process search request, request=" + request + ", error=" + e.getMessage()); - StatusRuntimeException grpcError = GrpcErrorHandler.convertToGrpcError(e); + StatusRuntimeException grpcError = GrpcErrorHandler.convertToGrpcError(e, params); responseObserver.onError(grpcError); } } diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java index d72ccfc117db5..b766ac0737088 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java @@ -8,8 +8,8 @@ package org.opensearch.transport.grpc.util; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.core.exc.InputCoercionException; +import java.io.IOException; +import java.util.concurrent.TimeoutException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -21,9 +21,9 @@ import org.opensearch.core.concurrency.OpenSearchRejectedExecutionException; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; - -import java.io.IOException; -import java.util.concurrent.TimeoutException; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.exc.InputCoercionException; import io.grpc.Status; import io.grpc.StatusRuntimeException; @@ -44,56 +44,57 @@ private GrpcErrorHandler() { * with enhanced XContent details for OpenSearchExceptions and full stack traces for debugging. * * @param e The exception to convert + * @param params * @return StatusRuntimeException with appropriate gRPC status and enhanced error details */ - public static StatusRuntimeException convertToGrpcError(Exception e) { + public static StatusRuntimeException convertToGrpcError(Exception e, ResponseHandlingParams params) { + ResponseHandlingParams.TracingLevel errorTracingLevel = params.getErrorTracingLevel(); // ========== OpenSearch Business Logic Exceptions ========== // Custom OpenSearch exceptions which extend {@link OpenSearchException}. // Uses {@link RestToGrpcStatusConverter} for REST -> gRPC status mapping and // follows {@link OpenSearchException#generateFailureXContent} unwrapping logic if (e instanceof OpenSearchException) { - return handleOpenSearchException((OpenSearchException) e); + return handleOpenSearchException((OpenSearchException) e, errorTracingLevel); } - // ========== OpenSearch Core System Exceptions ========== // Low-level OpenSearch exceptions that don't extend OpenSearchException - include full details else if (e instanceof OpenSearchRejectedExecutionException) { - return Status.RESOURCE_EXHAUSTED.withDescription(ExceptionsHelper.stackTrace(e)).asRuntimeException(); + return Status.RESOURCE_EXHAUSTED.withDescription(getErrorDescriptionRespectingTracingLevel(e, errorTracingLevel)).asRuntimeException(); } else if (e instanceof NotXContentException) { - return Status.INVALID_ARGUMENT.withDescription(ExceptionsHelper.stackTrace(e)).asRuntimeException(); + return Status.INVALID_ARGUMENT.withDescription(getErrorDescriptionRespectingTracingLevel(e, errorTracingLevel)).asRuntimeException(); } else if (e instanceof NotCompressedException) { - return Status.INVALID_ARGUMENT.withDescription(ExceptionsHelper.stackTrace(e)).asRuntimeException(); + return Status.INVALID_ARGUMENT.withDescription(getErrorDescriptionRespectingTracingLevel(e, errorTracingLevel)).asRuntimeException(); } // ========== 3. Third-party Library Exceptions ========== // External library exceptions (Jackson JSON parsing) - include full details else if (e instanceof InputCoercionException) { - return Status.INVALID_ARGUMENT.withDescription(ExceptionsHelper.stackTrace(e)).asRuntimeException(); + return Status.INVALID_ARGUMENT.withDescription(getErrorDescriptionRespectingTracingLevel(e, errorTracingLevel)).asRuntimeException(); } else if (e instanceof JsonParseException) { - return Status.INVALID_ARGUMENT.withDescription(ExceptionsHelper.stackTrace(e)).asRuntimeException(); + return Status.INVALID_ARGUMENT.withDescription(getErrorDescriptionRespectingTracingLevel(e, errorTracingLevel)).asRuntimeException(); } // ========== 4. Standard Java Exceptions ========== // Generic Java runtime exceptions - include full exception details for debugging else if (e instanceof IllegalArgumentException) { - return Status.INVALID_ARGUMENT.withDescription(ExceptionsHelper.stackTrace(e)).asRuntimeException(); + return Status.INVALID_ARGUMENT.withDescription(getErrorDescriptionRespectingTracingLevel(e, errorTracingLevel)).asRuntimeException(); } else if (e instanceof IllegalStateException) { - return Status.FAILED_PRECONDITION.withDescription(ExceptionsHelper.stackTrace(e)).asRuntimeException(); + return Status.FAILED_PRECONDITION.withDescription(getErrorDescriptionRespectingTracingLevel(e, errorTracingLevel)).asRuntimeException(); } else if (e instanceof SecurityException) { - return Status.PERMISSION_DENIED.withDescription(ExceptionsHelper.stackTrace(e)).asRuntimeException(); + return Status.PERMISSION_DENIED.withDescription(getErrorDescriptionRespectingTracingLevel(e, errorTracingLevel)).asRuntimeException(); } else if (e instanceof TimeoutException) { - return Status.DEADLINE_EXCEEDED.withDescription(ExceptionsHelper.stackTrace(e)).asRuntimeException(); + return Status.DEADLINE_EXCEEDED.withDescription(getErrorDescriptionRespectingTracingLevel(e, errorTracingLevel)).asRuntimeException(); } else if (e instanceof InterruptedException) { - return Status.CANCELLED.withDescription(ExceptionsHelper.stackTrace(e)).asRuntimeException(); + return Status.CANCELLED.withDescription(getErrorDescriptionRespectingTracingLevel(e, errorTracingLevel)).asRuntimeException(); } else if (e instanceof IOException) { - return Status.INTERNAL.withDescription(ExceptionsHelper.stackTrace(e)).asRuntimeException(); + return Status.INTERNAL.withDescription(getErrorDescriptionRespectingTracingLevel(e, errorTracingLevel)).asRuntimeException(); } // ========== 5. Unknown/Unmapped Exceptions ========== // Safety fallback for any unexpected exception to {@code Status.INTERNAL} with full debugging info else { logger.warn("Unmapped exception type: {}, treating as INTERNAL error", e.getClass().getSimpleName()); - return Status.INTERNAL.withDescription(ExceptionsHelper.stackTrace(e)).asRuntimeException(); + return Status.INTERNAL.withDescription(getErrorDescriptionRespectingTracingLevel(e, errorTracingLevel)).asRuntimeException(); } } @@ -106,7 +107,7 @@ else if (e instanceof IllegalArgumentException) { * @param ose The OpenSearchException to convert * @return StatusRuntimeException with mapped gRPC status and HTTP-identical error message */ - private static StatusRuntimeException handleOpenSearchException(OpenSearchException ose) { + private static StatusRuntimeException handleOpenSearchException(OpenSearchException ose, ResponseHandlingParams.TracingLevel params) { Status grpcStatus = RestToGrpcStatusConverter.convertRestToGrpcStatus(ose.status()); // Use existing HTTP logic but enhance description with metadata from XContent @@ -114,7 +115,7 @@ private static StatusRuntimeException handleOpenSearchException(OpenSearchExcept String baseDescription = ExceptionsHelper.summaryMessage(unwrapped); // Extract metadata using the same XContent infrastructure as HTTP - String enhancedDescription = enhanceDescriptionWithXContentMetadata(unwrapped, baseDescription); + String enhancedDescription = enhanceDescriptionWithXContentMetadata(unwrapped, baseDescription, params); return grpcStatus.withDescription(enhancedDescription).asRuntimeException(); } @@ -129,7 +130,7 @@ private static StatusRuntimeException handleOpenSearchException(OpenSearchExcept * @param baseDescription The base description from ExceptionsHelper.summaryMessage() * @return Enhanced description with full JSON metadata from XContent */ - private static String enhanceDescriptionWithXContentMetadata(Throwable exception, String baseDescription) { + private static String enhanceDescriptionWithXContentMetadata(Throwable exception, String baseDescription, ResponseHandlingParams.TracingLevel tracingLevel) { try { // Use the exact same method as HTTP error responses try (XContentBuilder builder = XContentFactory.jsonBuilder()) { @@ -138,7 +139,8 @@ private static String enhanceDescriptionWithXContentMetadata(Throwable exception // Use the same method as HTTP REST responses (BytesRestResponse.build) // This includes root_cause analysis, just like HTTP - OpenSearchException.generateFailureXContent(builder, ToXContent.EMPTY_PARAMS, (Exception) exception, true); + boolean shouldExposeDetailedStackTrace = tracingLevel == ResponseHandlingParams.TracingLevel.DETAILED_TRACE; + OpenSearchException.generateFailureXContent(builder, ToXContent.EMPTY_PARAMS, (Exception) exception, shouldExposeDetailedStackTrace); // Add status field like HTTP does org.opensearch.core.rest.RestStatus restStatus = ExceptionsHelper.status((Exception) exception); @@ -162,4 +164,12 @@ private static String enhanceDescriptionWithXContentMetadata(Throwable exception return baseDescription; } } + + private static String getErrorDescriptionRespectingTracingLevel(Throwable exception, ResponseHandlingParams.TracingLevel tracingLevel) { + if (tracingLevel == ResponseHandlingParams.TracingLevel.DETAILED_TRACE) { + return ExceptionsHelper.stackTrace(exception); + } + return exception.getMessage(); + } + } From 6c1c71db89be51bddcf3163882efb9e6eb75c2d1 Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Wed, 15 Oct 2025 11:48:37 +0200 Subject: [PATCH 02/28] Issue-19639 Add separate grpc.detailed_errors.enabled error handling setting for gRPC Signed-off-by: Sergei Ustimenko --- .../opensearch/transport/grpc/GrpcPlugin.java | 11 ++-- .../grpc/Netty4GrpcServerTransport.java | 13 ++++ .../grpc/services/DocumentServiceImpl.java | 6 +- .../grpc/services/SearchServiceImpl.java | 7 +- .../transport/grpc/util/GrpcErrorHandler.java | 14 ++++ .../grpc/services/SearchServiceImplTests.java | 63 +++++++++++++----- .../document/DocumentServiceImplTests.java | 66 ++++++++++++++----- 7 files changed, 139 insertions(+), 41 deletions(-) diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/GrpcPlugin.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/GrpcPlugin.java index 47db838ef4fb4..50c1c36ec8e0c 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/GrpcPlugin.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/GrpcPlugin.java @@ -56,6 +56,7 @@ import static org.opensearch.transport.grpc.Netty4GrpcServerTransport.GRPC_TRANSPORT_SETTING_KEY; import static org.opensearch.transport.grpc.Netty4GrpcServerTransport.SETTING_GRPC_BIND_HOST; +import static org.opensearch.transport.grpc.Netty4GrpcServerTransport.SETTING_GRPC_DETAILED_ERRORS_ENABLED; import static org.opensearch.transport.grpc.Netty4GrpcServerTransport.SETTING_GRPC_EXECUTOR_COUNT; import static org.opensearch.transport.grpc.Netty4GrpcServerTransport.SETTING_GRPC_HOST; import static org.opensearch.transport.grpc.Netty4GrpcServerTransport.SETTING_GRPC_KEEPALIVE_TIMEOUT; @@ -205,9 +206,10 @@ public Map> getAuxTransports( throw new IllegalStateException("createComponents must be called before getAuxTransports to initialize the registry"); } + boolean detailedErrorsEnabled = SETTING_GRPC_DETAILED_ERRORS_ENABLED.get(settings); List grpcServices = registerGRPCServices( - new DocumentServiceImpl(client), - new SearchServiceImpl(client, queryUtils) + new DocumentServiceImpl(client, detailedErrorsEnabled), + new SearchServiceImpl(client, queryUtils, detailedErrorsEnabled) ); return Collections.singletonMap( GRPC_TRANSPORT_SETTING_KEY, @@ -248,9 +250,10 @@ public Map> getSecureAuxTransports( throw new IllegalStateException("createComponents must be called before getSecureAuxTransports to initialize the registry"); } + boolean detailedErrorsEnabled = SETTING_GRPC_DETAILED_ERRORS_ENABLED.get(settings); List grpcServices = registerGRPCServices( - new DocumentServiceImpl(client), - new SearchServiceImpl(client, queryUtils) + new DocumentServiceImpl(client, detailedErrorsEnabled), + new SearchServiceImpl(client, queryUtils, detailedErrorsEnabled) ); return Collections.singletonMap( GRPC_SECURE_TRANSPORT_SETTING_KEY, diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/Netty4GrpcServerTransport.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/Netty4GrpcServerTransport.java index de2fb0079c652..eebb8933aebad 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/Netty4GrpcServerTransport.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/Netty4GrpcServerTransport.java @@ -186,6 +186,19 @@ public class Netty4GrpcServerTransport extends AuxTransport { Setting.Property.NodeScope ); + /** + * Requests that require detailed error tracing via {@code error_trace} will + * include relevant error details for better debugging in case this setting is enabled. + * Otherwise,when this setting is disabled, only an error summary is included + * when {@code error_trace} is omitted or disabled and an error response is generated in case + * it is enabled. + */ + public static final Setting SETTING_GRPC_DETAILED_ERRORS_ENABLED = Setting.boolSetting( + "grpc.detailed_errors.enabled", + true, + Setting.Property.NodeScope + ); + /** * Port range on which servers bind. */ diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/services/DocumentServiceImpl.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/services/DocumentServiceImpl.java index e1348bc78961f..0607c9d830ff0 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/services/DocumentServiceImpl.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/services/DocumentServiceImpl.java @@ -25,14 +25,17 @@ public class DocumentServiceImpl extends DocumentServiceGrpc.DocumentServiceImplBase { private static final Logger logger = LogManager.getLogger(DocumentServiceImpl.class); private final Client client; + private final boolean detailedErrorsEnabled; /** * Creates a new DocumentServiceImpl. * * @param client Client for executing actions on the local node + * @param detailedErrorsEnabled Whether detailed error tracing is enabled */ - public DocumentServiceImpl(Client client) { + public DocumentServiceImpl(Client client, boolean detailedErrorsEnabled) { this.client = client; + this.detailedErrorsEnabled = detailedErrorsEnabled; } /** @@ -44,6 +47,7 @@ public DocumentServiceImpl(Client client) { @Override public void bulk(org.opensearch.protobufs.BulkRequest request, StreamObserver responseObserver) { try { + GrpcErrorHandler.validateErrorTracingConfiguration(detailedErrorsEnabled, request.getGlobalParams()); org.opensearch.action.bulk.BulkRequest bulkRequest = BulkRequestProtoUtils.prepareRequest(request); BulkRequestActionListener listener = new BulkRequestActionListener(responseObserver); client.bulk(bulkRequest, listener); diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/services/SearchServiceImpl.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/services/SearchServiceImpl.java index f5bca635c19ab..9a5246bebef08 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/services/SearchServiceImpl.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/services/SearchServiceImpl.java @@ -31,14 +31,16 @@ public class SearchServiceImpl extends SearchServiceGrpc.SearchServiceImplBase { private static final Logger logger = LogManager.getLogger(SearchServiceImpl.class); private final Client client; private final AbstractQueryBuilderProtoUtils queryUtils; + private final boolean detailedErrorsEnabled; /** * Creates a new SearchServiceImpl. * * @param client Client for executing actions on the local node * @param queryUtils Query utils instance for parsing protobuf queries + * @param detailedErrorsEnabled Whether detailed error tracing is enabled */ - public SearchServiceImpl(Client client, AbstractQueryBuilderProtoUtils queryUtils) { + public SearchServiceImpl(Client client, AbstractQueryBuilderProtoUtils queryUtils, boolean detailedErrorsEnabled) { if (client == null) { throw new IllegalArgumentException("Client cannot be null"); } @@ -48,6 +50,7 @@ public SearchServiceImpl(Client client, AbstractQueryBuilderProtoUtils queryUtil this.client = client; this.queryUtils = queryUtils; + this.detailedErrorsEnabled = detailedErrorsEnabled; } /** @@ -61,8 +64,8 @@ public void search( org.opensearch.protobufs.SearchRequest request, StreamObserver responseObserver ) { - try { + GrpcErrorHandler.validateErrorTracingConfiguration(detailedErrorsEnabled, request.getGlobalParams()); org.opensearch.action.search.SearchRequest searchRequest = SearchRequestProtoUtils.prepareRequest(request, client, queryUtils); SearchRequestActionListener listener = new SearchRequestActionListener(responseObserver); client.search(searchRequest, listener); diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java index d72ccfc117db5..f16b9170454ee 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java @@ -21,6 +21,7 @@ import org.opensearch.core.concurrency.OpenSearchRejectedExecutionException; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.protobufs.GlobalParams; import java.io.IOException; import java.util.concurrent.TimeoutException; @@ -38,6 +39,19 @@ private GrpcErrorHandler() { // Utility class, no instances } + /** + * Validates if error tracing is allowed based on server configuration and request parameters. + * + * @param detailedErrorsEnabled Whether detailed errors are enabled on the server + * @param globalRequestParams The global parameters from the gRPC request + * @throws IllegalArgumentException if error tracing is requested but disabled by the server side + */ + public static void validateErrorTracingConfiguration(boolean detailedErrorsEnabled, GlobalParams globalRequestParams) { + if (detailedErrorsEnabled == false && globalRequestParams.getErrorTrace()) { + throw new IllegalArgumentException("error traces in responses are disabled."); + } + } + /** * Converts an exception to an appropriate gRPC StatusRuntimeException. * Uses comprehensive exception type mapping for granular gRPC status codes, diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/SearchServiceImplTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/SearchServiceImplTests.java index d6225299c4284..1eabd26abad3c 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/SearchServiceImplTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/SearchServiceImplTests.java @@ -8,23 +8,24 @@ package org.opensearch.transport.grpc.services; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; + +import java.io.IOException; + +import org.junit.Before; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.opensearch.protobufs.SearchRequest; import org.opensearch.protobufs.SearchRequestBody; import org.opensearch.test.OpenSearchTestCase; import org.opensearch.transport.client.node.NodeClient; import org.opensearch.transport.grpc.proto.request.search.query.AbstractQueryBuilderProtoUtils; import org.opensearch.transport.grpc.proto.request.search.query.QueryBuilderProtoTestUtils; -import org.junit.Before; - -import java.io.IOException; +import io.grpc.StatusRuntimeException; import io.grpc.stub.StreamObserver; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.verify; public class SearchServiceImplTests extends OpenSearchTestCase { @@ -41,19 +42,19 @@ public class SearchServiceImplTests extends OpenSearchTestCase { public void setup() throws IOException { MockitoAnnotations.openMocks(this); queryUtils = QueryBuilderProtoTestUtils.createQueryUtils(); - service = new SearchServiceImpl(client, queryUtils); + service = new SearchServiceImpl(client, queryUtils, true); } public void testConstructorWithNullClient() { // Test that constructor throws IllegalArgumentException when client is null - IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () -> new SearchServiceImpl(null, queryUtils)); + IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () -> new SearchServiceImpl(null, queryUtils, true)); assertEquals("Client cannot be null", exception.getMessage()); } public void testConstructorWithNullQueryUtils() { // Test that constructor throws IllegalArgumentException when queryUtils is null - IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () -> new SearchServiceImpl(client, null)); + IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () -> new SearchServiceImpl(client, null, true)); assertEquals("Query utils cannot be null", exception.getMessage()); } @@ -61,12 +62,12 @@ public void testConstructorWithNullQueryUtils() { public void testConstructorWithBothNull() { // Test that constructor throws IllegalArgumentException when both parameters are null // Should fail on the first null check (client) - IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () -> new SearchServiceImpl(null, null)); + IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () -> new SearchServiceImpl(null, null, true)); assertEquals("Client cannot be null", exception.getMessage()); } - public void testSearchSuccess() throws IOException { + public void testSearchSuccess() { // Create a test request SearchRequest request = createTestSearchRequest(); @@ -77,7 +78,7 @@ public void testSearchSuccess() throws IOException { verify(client).search(any(org.opensearch.action.search.SearchRequest.class), any()); } - public void testSearchWithException() throws IOException { + public void testSearchWithException() { // Create a test request SearchRequest request = createTestSearchRequest(); @@ -91,7 +92,37 @@ public void testSearchWithException() throws IOException { verify(responseObserver).onError(any()); } + public void testErrorTracingConfigValidationFailsWhenServerSettingIsDisabledAndRequestRequiresTracing() { + // Setup request and the service, server setting is off and request requires tracing + SearchRequest request = createTestSearchRequest(); + SearchServiceImpl serviceWithDisabledErrorsTracing = new SearchServiceImpl(client, queryUtils, false); + + // Call search method + serviceWithDisabledErrorsTracing.search(request, responseObserver); + + // Verify that responseObserver.onError reports request parameter must be disabled + verify(responseObserver).onError(any(StatusRuntimeException.class)); + } + + public void testErrorTracingConfigValidationPassesWhenServerSettingIsDisabledAndRequestSkipsTracing() { + // Setup request and the service, server setting is off and request skips tracing + SearchRequest request = createTestSearchRequest().toBuilder().setGlobalParams( + org.opensearch.protobufs.GlobalParams.newBuilder().setErrorTrace(false) + ).build(); + SearchServiceImpl serviceWithDisabledErrorsTracing = new SearchServiceImpl(client, queryUtils, false); + + // Call search method + serviceWithDisabledErrorsTracing.search(request, responseObserver); + + // Verify that client.search was called + verify(client).search(any(org.opensearch.action.search.SearchRequest.class), any()); + } + private SearchRequest createTestSearchRequest() { - return SearchRequest.newBuilder().addIndex("test-index").setRequestBody(SearchRequestBody.newBuilder().setSize(10).build()).build(); + return SearchRequest.newBuilder() + .addIndex("test-index") + .setRequestBody(SearchRequestBody.newBuilder().setSize(10).build()) + .setGlobalParams(org.opensearch.protobufs.GlobalParams.newBuilder().setErrorTrace(true).build()) + .build(); } } diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java index 663cb4e24c18a..b406bca83af70 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java @@ -8,24 +8,25 @@ package org.opensearch.transport.grpc.services.document; -import com.google.protobuf.ByteString; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; + +import java.io.IOException; + +import org.junit.Before; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.opensearch.protobufs.BulkRequest; import org.opensearch.protobufs.BulkRequestBody; import org.opensearch.protobufs.IndexOperation; import org.opensearch.test.OpenSearchTestCase; import org.opensearch.transport.client.node.NodeClient; import org.opensearch.transport.grpc.services.DocumentServiceImpl; -import org.junit.Before; - -import java.io.IOException; +import com.google.protobuf.ByteString; +import io.grpc.StatusRuntimeException; import io.grpc.stub.StreamObserver; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.verify; public class DocumentServiceImplTests extends OpenSearchTestCase { @@ -40,10 +41,10 @@ public class DocumentServiceImplTests extends OpenSearchTestCase { @Before public void setup() throws IOException { MockitoAnnotations.openMocks(this); - service = new DocumentServiceImpl(client); + service = new DocumentServiceImpl(client, true); } - public void testBulkSuccess() throws IOException { + public void testBulkSuccess() { // Create a test request BulkRequest request = createTestBulkRequest(); @@ -54,7 +55,7 @@ public void testBulkSuccess() throws IOException { verify(client).bulk(any(org.opensearch.action.bulk.BulkRequest.class), any()); } - public void testBulkError() throws IOException { + public void testBulkError() { // Create a test request BulkRequest request = createTestBulkRequest(); @@ -68,14 +69,43 @@ public void testBulkError() throws IOException { verify(responseObserver).onError(any(RuntimeException.class)); } + public void testErrorTracingConfigValidationFailsWhenServerSettingIsDisabledAndRequestRequiresTracing() { + // Setup request and the service, server setting is off and request requires tracing + BulkRequest request = createTestBulkRequest(); + DocumentServiceImpl serviceWithDisabledErrorsTracing = new DocumentServiceImpl(client, false); + + // Call bulk method + serviceWithDisabledErrorsTracing.bulk(request, responseObserver); + + // Verify that an error was sent + verify(responseObserver).onError(any(StatusRuntimeException.class)); + } + + public void testErrorTracingConfigValidationPassesWhenServerSettingIsDisabledAndRequestSkipsTracing() { + // Setup request and the service, server setting is off and request does not require tracing + BulkRequest request = createTestBulkRequest().toBuilder().setGlobalParams( + org.opensearch.protobufs.GlobalParams.newBuilder().setErrorTrace(false) + ).build(); + DocumentServiceImpl serviceWithDisabledErrorsTracing = new DocumentServiceImpl(client, false); + + // Call bulk method + serviceWithDisabledErrorsTracing.bulk(request, responseObserver); + + // Verify that client.bulk was called + verify(client).bulk(any(org.opensearch.action.bulk.BulkRequest.class), any()); + } + private BulkRequest createTestBulkRequest() { IndexOperation indexOp = IndexOperation.newBuilder().setXIndex("test-index").setXId("test-id").build(); BulkRequestBody requestBody = BulkRequestBody.newBuilder() - .setOperationContainer(org.opensearch.protobufs.OperationContainer.newBuilder().setIndex(indexOp).build()) - .setObject(ByteString.copyFromUtf8("{\"field\":\"value\"}")) - .build(); - - return BulkRequest.newBuilder().addRequestBody(requestBody).build(); + .setOperationContainer(org.opensearch.protobufs.OperationContainer.newBuilder().setIndex(indexOp).build()) + .setObject(ByteString.copyFromUtf8("{\"field\":\"value\"}")) + .build(); + + return BulkRequest.newBuilder() + .addRequestBody(requestBody) + .setGlobalParams(org.opensearch.protobufs.GlobalParams.newBuilder().setErrorTrace(true)) + .build(); } } From 702f7d902128af216da7e108cfebdc00c8b84b6e Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Wed, 15 Oct 2025 12:01:44 +0200 Subject: [PATCH 03/28] Add the CHANGELOG.md entry Signed-off-by: Sergei Ustimenko --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0d35c921ccd5..45196d2d5e2df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,8 +9,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Add a mapper for context aware segments grouping criteria ([#19233](https://github.com/opensearch-project/OpenSearch/pull/19233)) - Return full error for GRPC error response ([#19568](https://github.com/opensearch-project/OpenSearch/pull/19568)) - Add pluggable gRPC interceptors with explicit ordering([#19005](https://github.com/opensearch-project/OpenSearch/pull/19005)) - - Add metrics for the merged segment warmer feature ([#18929](https://github.com/opensearch-project/OpenSearch/pull/18929)) +- Add separate grpc.detailed_errors.enabled error handling setting for gRPC ([#19644](https://github.com/opensearch-project/OpenSearch/pull/19644)) ### Changed - Faster `terms` query creation for `keyword` field with index and docValues enabled ([#19350](https://github.com/opensearch-project/OpenSearch/pull/19350)) From 63928491975374ccac9177cadce1aba1aae401e4 Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Wed, 15 Oct 2025 12:45:35 +0200 Subject: [PATCH 04/28] Polish formatting Signed-off-by: Sergei Ustimenko --- .../grpc/services/SearchServiceImplTests.java | 37 +++++++++--------- .../document/DocumentServiceImplTests.java | 38 +++++++++---------- 2 files changed, 39 insertions(+), 36 deletions(-) diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/SearchServiceImplTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/SearchServiceImplTests.java index 1eabd26abad3c..857536e642714 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/SearchServiceImplTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/SearchServiceImplTests.java @@ -8,24 +8,24 @@ package org.opensearch.transport.grpc.services; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.verify; - -import java.io.IOException; - -import org.junit.Before; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; import org.opensearch.protobufs.SearchRequest; import org.opensearch.protobufs.SearchRequestBody; import org.opensearch.test.OpenSearchTestCase; import org.opensearch.transport.client.node.NodeClient; import org.opensearch.transport.grpc.proto.request.search.query.AbstractQueryBuilderProtoUtils; import org.opensearch.transport.grpc.proto.request.search.query.QueryBuilderProtoTestUtils; +import org.junit.Before; + +import java.io.IOException; import io.grpc.StatusRuntimeException; import io.grpc.stub.StreamObserver; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; public class SearchServiceImplTests extends OpenSearchTestCase { @@ -47,7 +47,10 @@ public void setup() throws IOException { public void testConstructorWithNullClient() { // Test that constructor throws IllegalArgumentException when client is null - IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () -> new SearchServiceImpl(null, queryUtils, true)); + IllegalArgumentException exception = expectThrows( + IllegalArgumentException.class, + () -> new SearchServiceImpl(null, queryUtils, true) + ); assertEquals("Client cannot be null", exception.getMessage()); } @@ -106,9 +109,9 @@ public void testErrorTracingConfigValidationFailsWhenServerSettingIsDisabledAndR public void testErrorTracingConfigValidationPassesWhenServerSettingIsDisabledAndRequestSkipsTracing() { // Setup request and the service, server setting is off and request skips tracing - SearchRequest request = createTestSearchRequest().toBuilder().setGlobalParams( - org.opensearch.protobufs.GlobalParams.newBuilder().setErrorTrace(false) - ).build(); + SearchRequest request = createTestSearchRequest().toBuilder() + .setGlobalParams(org.opensearch.protobufs.GlobalParams.newBuilder().setErrorTrace(false)) + .build(); SearchServiceImpl serviceWithDisabledErrorsTracing = new SearchServiceImpl(client, queryUtils, false); // Call search method @@ -120,9 +123,9 @@ public void testErrorTracingConfigValidationPassesWhenServerSettingIsDisabledAnd private SearchRequest createTestSearchRequest() { return SearchRequest.newBuilder() - .addIndex("test-index") - .setRequestBody(SearchRequestBody.newBuilder().setSize(10).build()) - .setGlobalParams(org.opensearch.protobufs.GlobalParams.newBuilder().setErrorTrace(true).build()) - .build(); + .addIndex("test-index") + .setRequestBody(SearchRequestBody.newBuilder().setSize(10).build()) + .setGlobalParams(org.opensearch.protobufs.GlobalParams.newBuilder().setErrorTrace(true).build()) + .build(); } } diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java index b406bca83af70..9bd2b9a55493e 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java @@ -8,25 +8,25 @@ package org.opensearch.transport.grpc.services.document; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.verify; - -import java.io.IOException; - -import org.junit.Before; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import com.google.protobuf.ByteString; import org.opensearch.protobufs.BulkRequest; import org.opensearch.protobufs.BulkRequestBody; import org.opensearch.protobufs.IndexOperation; import org.opensearch.test.OpenSearchTestCase; import org.opensearch.transport.client.node.NodeClient; import org.opensearch.transport.grpc.services.DocumentServiceImpl; -import com.google.protobuf.ByteString; +import org.junit.Before; + +import java.io.IOException; import io.grpc.StatusRuntimeException; import io.grpc.stub.StreamObserver; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; public class DocumentServiceImplTests extends OpenSearchTestCase { @@ -83,9 +83,9 @@ public void testErrorTracingConfigValidationFailsWhenServerSettingIsDisabledAndR public void testErrorTracingConfigValidationPassesWhenServerSettingIsDisabledAndRequestSkipsTracing() { // Setup request and the service, server setting is off and request does not require tracing - BulkRequest request = createTestBulkRequest().toBuilder().setGlobalParams( - org.opensearch.protobufs.GlobalParams.newBuilder().setErrorTrace(false) - ).build(); + BulkRequest request = createTestBulkRequest().toBuilder() + .setGlobalParams(org.opensearch.protobufs.GlobalParams.newBuilder().setErrorTrace(false)) + .build(); DocumentServiceImpl serviceWithDisabledErrorsTracing = new DocumentServiceImpl(client, false); // Call bulk method @@ -99,13 +99,13 @@ private BulkRequest createTestBulkRequest() { IndexOperation indexOp = IndexOperation.newBuilder().setXIndex("test-index").setXId("test-id").build(); BulkRequestBody requestBody = BulkRequestBody.newBuilder() - .setOperationContainer(org.opensearch.protobufs.OperationContainer.newBuilder().setIndex(indexOp).build()) - .setObject(ByteString.copyFromUtf8("{\"field\":\"value\"}")) - .build(); + .setOperationContainer(org.opensearch.protobufs.OperationContainer.newBuilder().setIndex(indexOp).build()) + .setObject(ByteString.copyFromUtf8("{\"field\":\"value\"}")) + .build(); return BulkRequest.newBuilder() - .addRequestBody(requestBody) - .setGlobalParams(org.opensearch.protobufs.GlobalParams.newBuilder().setErrorTrace(true)) - .build(); + .addRequestBody(requestBody) + .setGlobalParams(org.opensearch.protobufs.GlobalParams.newBuilder().setErrorTrace(true)) + .build(); } } From d54aa0d6cd0b5d13c7f3f8596ec647af257f5742 Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Sat, 25 Oct 2025 13:52:44 +0200 Subject: [PATCH 05/28] Polish docs for the setting Signed-off-by: Sergei Ustimenko --- .../transport/grpc/Netty4GrpcServerTransport.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/Netty4GrpcServerTransport.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/Netty4GrpcServerTransport.java index eebb8933aebad..c3deedff0093f 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/Netty4GrpcServerTransport.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/Netty4GrpcServerTransport.java @@ -187,11 +187,10 @@ public class Netty4GrpcServerTransport extends AuxTransport { ); /** - * Requests that require detailed error tracing via {@code error_trace} will - * include relevant error details for better debugging in case this setting is enabled. - * Otherwise,when this setting is disabled, only an error summary is included - * when {@code error_trace} is omitted or disabled and an error response is generated in case - * it is enabled. + * Enables detailed error message for gRPC requests. If enabled, returns detailed + * error information when requested via {@code error_trace} parameter in the request scope. + * Otherwise, only a summary is generated. The case when the detailed error trace is requested + * but server explicitly turned it off, the error response is generated. */ public static final Setting SETTING_GRPC_DETAILED_ERRORS_ENABLED = Setting.boolSetting( "grpc.detailed_errors.enabled", From bf4d92f6bd51850ea86bd6dee32fbf6f9a2b3cc2 Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Sat, 25 Oct 2025 13:59:38 +0200 Subject: [PATCH 06/28] Apply formatting Signed-off-by: Sergei Ustimenko --- .../org/opensearch/transport/grpc/GrpcPlugin.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/GrpcPlugin.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/GrpcPlugin.java index c53cd73ed01c1..0c24f7920baab 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/GrpcPlugin.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/GrpcPlugin.java @@ -212,7 +212,10 @@ public Map> getAuxTransports( boolean detailedErrorsEnabled = SETTING_GRPC_DETAILED_ERRORS_ENABLED.get(settings); return Collections.singletonMap(GRPC_TRANSPORT_SETTING_KEY, () -> { List grpcServices = new ArrayList<>( - List.of(new DocumentServiceImpl(client, detailedErrorsEnabled), new SearchServiceImpl(client, queryUtils, detailedErrorsEnabled)) + List.of( + new DocumentServiceImpl(client, detailedErrorsEnabled), + new SearchServiceImpl(client, queryUtils, detailedErrorsEnabled) + ) ); for (GrpcServiceFactory serviceFac : servicesFactory) { List pluginServices = serviceFac.initClient(client) @@ -264,8 +267,11 @@ public Map> getSecureAuxTransports( return Collections.singletonMap(GRPC_SECURE_TRANSPORT_SETTING_KEY, () -> { boolean detailedErrorsEnabled = SETTING_GRPC_DETAILED_ERRORS_ENABLED.get(settings); - List grpcServices = new ArrayList<>( - List.of(new DocumentServiceImpl(client, detailedErrorsEnabled), new SearchServiceImpl(client, queryUtils, detailedErrorsEnabled)) + List grpcServices = new ArrayList<>( + List.of( + new DocumentServiceImpl(client, detailedErrorsEnabled), + new SearchServiceImpl(client, queryUtils, detailedErrorsEnabled) + ) ); for (GrpcServiceFactory serviceFac : servicesFactory) { List pluginServices = serviceFac.initClient(client) From b3303280cb4f2bb79c66aa06fc01e0a5a9f9f421 Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Tue, 4 Nov 2025 12:51:11 +0100 Subject: [PATCH 07/28] Apply formatting Signed-off-by: Sergei Ustimenko --- .../grpc/services/document/DocumentServiceImplTests.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java index 9ba13cadfb99d..744d56d200013 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java @@ -104,10 +104,10 @@ private BulkRequest createTestBulkRequest() { .build(); BulkRequestBody requestBody = BulkRequestBody.newBuilder() - .setOperationContainer(org.opensearch.protobufs.OperationContainer.newBuilder().setIndex(indexOp).build()) - .setGlobalParams(org.opensearch.protobufs.GlobalParams.newBuilder().setErrorTrace(true)) - .setObject(ByteString.copyFromUtf8("{\"field\":\"value\"}")) - .build(); + .setOperationContainer(org.opensearch.protobufs.OperationContainer.newBuilder().setIndex(indexOp).build()) + .setGlobalParams(org.opensearch.protobufs.GlobalParams.newBuilder().setErrorTrace(true)) + .setObject(ByteString.copyFromUtf8("{\"field\":\"value\"}")) + .build(); return BulkRequest.newBuilder().addBulkRequestBody(requestBody).build(); } From f6d8f9a958620fc0293511a19bfca84d804fe016 Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Tue, 4 Nov 2025 16:31:35 +0100 Subject: [PATCH 08/28] Polish tests and add more test cases to verify error summary trimming Signed-off-by: Sergei Ustimenko --- .../listeners/BulkRequestActionListener.java | 2 +- .../SearchRequestActionListener.java | 1 + .../exceptions/ResponseHandlingParams.java | 4 + .../transport/grpc/GrpcPluginTests.java | 2 +- .../BulkRequestActionListenerTests.java | 3 +- .../SearchRequestActionListenerTests.java | 12 +-- .../response/BulkResponseProtoUtilsTests.java | 7 +- .../bulk/BulkItemResponseProtoUtilsTests.java | 15 ++-- .../DocWriteResponseProtoUtilsTests.java | 9 ++- .../common/ShardInfoProtoUtilsTests.java | 7 +- .../OpenSearchExceptionProtoUtilsTests.java | 73 +++++++++++++++++-- ...erationFailedExceptionProtoUtilsTests.java | 11 +-- ...erationFailedExceptionProtoUtilsTests.java | 11 +-- .../search/SearchResponseProtoUtilsTests.java | 15 ++-- .../grpc/services/SearchServiceImplTests.java | 5 +- .../document/DocumentServiceImplTests.java | 16 ++-- .../grpc/util/GrpcErrorHandlerTests.java | 38 +++++----- 17 files changed, 145 insertions(+), 86 deletions(-) diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListener.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListener.java index a299ae11d3411..048062c2bd3db 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListener.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListener.java @@ -33,7 +33,7 @@ public class BulkRequestActionListener implements ActionListener { * Creates a new BulkRequestActionListener. * * @param responseObserver The gRPC stream observer to send the response back to the client - * @param params + * @param params parameters that are going to change how responses and errors are handled */ public BulkRequestActionListener( StreamObserver responseObserver, diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/listeners/SearchRequestActionListener.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/listeners/SearchRequestActionListener.java index 914699afd3926..dcf4da4672d40 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/listeners/SearchRequestActionListener.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/listeners/SearchRequestActionListener.java @@ -34,6 +34,7 @@ public class SearchRequestActionListener implements ActionListener responseObserver, diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/ResponseHandlingParams.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/ResponseHandlingParams.java index 5f5b81e2879d5..bec5bbabe79cc 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/ResponseHandlingParams.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/ResponseHandlingParams.java @@ -14,6 +14,10 @@ public class ResponseHandlingParams { private final TracingLevel errorTracingLevel; + public ResponseHandlingParams() { + this.errorTracingLevel = TracingLevel.SUMMARY; + } + public ResponseHandlingParams(boolean detailedErrorsEnabled, GlobalParams errorTracesRequested) { this.errorTracingLevel = getTracingLevel(detailedErrorsEnabled, errorTracesRequested); } diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/GrpcPluginTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/GrpcPluginTests.java index 31148fe6337d7..368e9c84554b7 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/GrpcPluginTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/GrpcPluginTests.java @@ -140,7 +140,7 @@ public void testGetSettings() { assertTrue("SETTING_GRPC_KEEPALIVE_TIMEOUT should be included", settings.contains(SETTING_GRPC_KEEPALIVE_TIMEOUT)); // Verify the number of settings - assertEquals("Should return 13 settings", 13, settings.size()); + assertEquals("Should return 14 settings", 14, settings.size()); } private static class LoadableMockServiceFactory implements GrpcServiceFactory { diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListenerTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListenerTests.java index 5f1b6e1839a04..b235ac92c9283 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListenerTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListenerTests.java @@ -22,6 +22,7 @@ import io.grpc.stub.StreamObserver; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; @@ -37,7 +38,7 @@ public class BulkRequestActionListenerTests extends OpenSearchTestCase { public void setUp() throws Exception { super.setUp(); MockitoAnnotations.openMocks(this); - listener = new BulkRequestActionListener(responseObserver); + listener = new BulkRequestActionListener(responseObserver, new ResponseHandlingParams()); } public void testOnResponseWithSuccessfulResponse() { diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/listeners/SearchRequestActionListenerTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/listeners/SearchRequestActionListenerTests.java index 2b3986586a85d..6d216248e18dc 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/listeners/SearchRequestActionListenerTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/listeners/SearchRequestActionListenerTests.java @@ -17,6 +17,7 @@ import io.grpc.stub.StreamObserver; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; @@ -34,7 +35,7 @@ public class SearchRequestActionListenerTests extends OpenSearchTestCase { public void setUp() throws Exception { super.setUp(); MockitoAnnotations.openMocks(this); - listener = new SearchRequestActionListener(responseObserver); + listener = new SearchRequestActionListener(responseObserver, new ResponseHandlingParams()); } public void testOnResponse() { @@ -60,13 +61,6 @@ public void testOnResponse() { } public void testOnFailure() { - // Create a mock StreamObserver - @SuppressWarnings("unchecked") - StreamObserver mockResponseObserver = mock(StreamObserver.class); - - // Create a SearchRequestActionListener - SearchRequestActionListener listener = new SearchRequestActionListener(mockResponseObserver); - // Create an exception Exception exception = new Exception("Test exception"); @@ -74,6 +68,6 @@ public void testOnFailure() { listener.onFailure(exception); // Verify that onError was called with a StatusRuntimeException - verify(mockResponseObserver, times(1)).onError(any(StatusRuntimeException.class)); + verify(responseObserver, times(1)).onError(any(StatusRuntimeException.class)); } } diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/BulkResponseProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/BulkResponseProtoUtilsTests.java index 9a630d0ae914d..fcae5e01098d2 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/BulkResponseProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/BulkResponseProtoUtilsTests.java @@ -17,6 +17,7 @@ import org.opensearch.core.index.shard.ShardId; import org.opensearch.test.OpenSearchTestCase; import org.opensearch.transport.grpc.proto.response.document.bulk.BulkResponseProtoUtils; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import java.io.IOException; @@ -37,7 +38,7 @@ public void testToProtoWithSuccessfulResponse() throws IOException { BulkResponse bulkResponse = new BulkResponse(responses, 100); // Convert to Protocol Buffer - org.opensearch.protobufs.BulkResponse protoResponse = BulkResponseProtoUtils.toProto(bulkResponse); + org.opensearch.protobufs.BulkResponse protoResponse = BulkResponseProtoUtils.toProto(bulkResponse, new ResponseHandlingParams()); // Verify the conversion assertEquals("Should have the correct took time", 100, protoResponse.getTook()); @@ -65,7 +66,7 @@ public void testToProtoWithFailedResponse() throws IOException { BulkResponse bulkResponse = new BulkResponse(responses, 100); // Convert to Protocol Buffer - org.opensearch.protobufs.BulkResponse protoResponse = BulkResponseProtoUtils.toProto(bulkResponse); + org.opensearch.protobufs.BulkResponse protoResponse = BulkResponseProtoUtils.toProto(bulkResponse, new ResponseHandlingParams()); // Verify the conversion assertEquals("Should have the correct took time", 100, protoResponse.getTook()); @@ -94,7 +95,7 @@ public void testToProtoWithIngestTook() throws IOException { BulkResponse bulkResponse = new BulkResponse(responses, 100, 50); // Convert to Protocol Buffer - org.opensearch.protobufs.BulkResponse protoResponse = BulkResponseProtoUtils.toProto(bulkResponse); + org.opensearch.protobufs.BulkResponse protoResponse = BulkResponseProtoUtils.toProto(bulkResponse, new ResponseHandlingParams()); // Verify the conversion assertEquals("Should have the correct took time", 100, protoResponse.getTook()); diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtilsTests.java index 0b43c0e17f6ac..d1686b971aa5f 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtilsTests.java @@ -21,6 +21,7 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.index.get.GetResult; import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -47,7 +48,7 @@ public void testToProtoWithIndexResponse() throws IOException { BulkItemResponse bulkItemResponse = new BulkItemResponse(0, DocWriteRequest.OpType.INDEX, indexResponse); // Convert to protobuf ResponseItem - org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto(bulkItemResponse); + org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto(bulkItemResponse, new ResponseHandlingParams()); // Verify the result assertNotNull("ResponseItem should not be null", responseItem); @@ -72,7 +73,7 @@ public void testToProtoWithCreateResponse() throws IOException { BulkItemResponse bulkItemResponse = new BulkItemResponse(0, DocWriteRequest.OpType.CREATE, indexResponse); // Convert to protobuf ResponseItem - org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto(bulkItemResponse); + org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto(bulkItemResponse, new ResponseHandlingParams()); // Verify the result assertNotNull("ResponseItem should not be null", responseItem); @@ -97,7 +98,7 @@ public void testToProtoWithDeleteResponse() throws IOException { BulkItemResponse bulkItemResponse = new BulkItemResponse(0, DocWriteRequest.OpType.DELETE, deleteResponse); // Convert to protobuf ResponseItem - org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto(bulkItemResponse); + org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto(bulkItemResponse, new ResponseHandlingParams()); // Verify the result assertNotNull("ResponseItem should not be null", responseItem); @@ -122,7 +123,7 @@ public void testToProtoWithUpdateResponse() throws IOException { BulkItemResponse bulkItemResponse = new BulkItemResponse(0, DocWriteRequest.OpType.UPDATE, updateResponse); // Convert to protobuf Item - org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto(bulkItemResponse); + org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto(bulkItemResponse, new ResponseHandlingParams()); // Verify the result assertNotNull("ResponseItem should not be null", responseItem); @@ -165,7 +166,7 @@ public void testToProtoWithUpdateResponseAndGetResult() throws IOException { BulkItemResponse bulkItemResponse = new BulkItemResponse(0, DocWriteRequest.OpType.UPDATE, updateResponse); // Convert to protobuf Item - org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto(bulkItemResponse); + org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto(bulkItemResponse, new ResponseHandlingParams()); // Verify the result assertNotNull("ResponseItem should not be null", responseItem); @@ -195,7 +196,7 @@ public void testToProtoWithFailure() throws IOException { BulkItemResponse bulkItemResponse = new BulkItemResponse(0, DocWriteRequest.OpType.INDEX, failure); // Convert to protobuf Item - org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto(bulkItemResponse); + org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto(bulkItemResponse, new ResponseHandlingParams()); // Verify the result assertNotNull("ResponseItem should not be null", responseItem); @@ -210,6 +211,6 @@ public void testToProtoWithFailure() throws IOException { public void testToProtoWithNullResponse() throws IOException { // Call toProto with null, should throw NullPointerException - expectThrows(NullPointerException.class, () -> BulkItemResponseProtoUtils.toProto(null)); + expectThrows(NullPointerException.class, () -> BulkItemResponseProtoUtils.toProto(null, new ResponseHandlingParams())); } } diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtilsTests.java index b1768c990b218..ebe17640b5015 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtilsTests.java @@ -14,6 +14,7 @@ import org.opensearch.core.index.shard.ShardId; import org.opensearch.protobufs.ResponseItem; import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import java.io.IOException; @@ -32,7 +33,7 @@ public void testToProtoWithIndexResponse() throws IOException { indexResponse.setForcedRefresh(true); // Convert to protobuf ResponseItem.Builder - ResponseItem.Builder responseItemBuilder = DocWriteResponseProtoUtils.toProto(indexResponse); + ResponseItem.Builder responseItemBuilder = DocWriteResponseProtoUtils.toProto(indexResponse, new ResponseHandlingParams()); // Verify the result assertNotNull("ResponseItem.Builder should not be null", responseItemBuilder); @@ -70,7 +71,7 @@ public void testToProtoWithEmptyId() throws IOException { indexResponse.setShardInfo(shardInfo); // Convert to protobuf ResponseItem.Builder - ResponseItem.Builder responseItemBuilder = DocWriteResponseProtoUtils.toProto(indexResponse); + ResponseItem.Builder responseItemBuilder = DocWriteResponseProtoUtils.toProto(indexResponse, new ResponseHandlingParams()); // Verify the result assertNotNull("ResponseItem.Builder should not be null", responseItemBuilder); @@ -94,7 +95,7 @@ public void testToProtoWithNoSeqNo() throws IOException { indexResponse.setShardInfo(shardInfo); // Convert to protobuf ResponseItem.Builder - ResponseItem.Builder responseItemBuilder = DocWriteResponseProtoUtils.toProto(indexResponse); + ResponseItem.Builder responseItemBuilder = DocWriteResponseProtoUtils.toProto(indexResponse, new ResponseHandlingParams()); // Verify the result assertNotNull("ResponseItem.Builder should not be null", responseItemBuilder); @@ -109,6 +110,6 @@ public void testToProtoWithNoSeqNo() throws IOException { public void testToProtoWithNullResponse() throws IOException { // Call toProto with null, should throw NullPointerException - expectThrows(NullPointerException.class, () -> DocWriteResponseProtoUtils.toProto(null)); + expectThrows(NullPointerException.class, () -> DocWriteResponseProtoUtils.toProto(null, new ResponseHandlingParams())); } } diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtilsTests.java index d4c873e39ff53..88679d76726d7 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtilsTests.java @@ -14,6 +14,7 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.protobufs.ShardInfo; import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import java.io.IOException; import java.util.ArrayList; @@ -26,7 +27,7 @@ public void testToProtoWithNoFailures() throws IOException { ReplicationResponse.ShardInfo shardInfo = new ReplicationResponse.ShardInfo(5, 3, new ReplicationResponse.ShardInfo.Failure[0]); // Convert to protobuf ShardInfo - ShardInfo protoShardInfo = ShardInfoProtoUtils.toProto(shardInfo); + ShardInfo protoShardInfo = ShardInfoProtoUtils.toProto(shardInfo, new ResponseHandlingParams()); // Verify the result assertNotNull("ShardInfo should not be null", protoShardInfo); @@ -55,7 +56,7 @@ public void testToProtoWithFailures() throws IOException { ReplicationResponse.ShardInfo shardInfo = new ReplicationResponse.ShardInfo(5, 3, failures); // Convert to protobuf ShardInfo - ShardInfo protoShardInfo = ShardInfoProtoUtils.toProto(shardInfo); + ShardInfo protoShardInfo = ShardInfoProtoUtils.toProto(shardInfo, new ResponseHandlingParams()); // Verify the result assertNotNull("ShardInfo should not be null", protoShardInfo); @@ -87,6 +88,6 @@ public void testToProtoWithFailures() throws IOException { public void testToProtoWithNullShardInfo() throws IOException { // Call toProto with null, should throw NullPointerException - expectThrows(NullPointerException.class, () -> ShardInfoProtoUtils.toProto(null)); + expectThrows(NullPointerException.class, () -> ShardInfoProtoUtils.toProto(null, new ResponseHandlingParams())); } } diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/OpenSearchExceptionProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/OpenSearchExceptionProtoUtilsTests.java index 421c0677d1bfc..f1997dccedcc5 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/OpenSearchExceptionProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/OpenSearchExceptionProtoUtilsTests.java @@ -17,12 +17,14 @@ import org.opensearch.core.common.ParsingException; import org.opensearch.core.common.breaker.CircuitBreakingException; import org.opensearch.protobufs.ErrorCause; +import org.opensearch.protobufs.GlobalParams; import org.opensearch.protobufs.ObjectMap; import org.opensearch.protobufs.StringOrStringArray; import org.opensearch.script.ScriptException; import org.opensearch.search.SearchParseException; import org.opensearch.search.aggregations.MultiBucketConsumerService; import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import org.opensearch.transport.grpc.proto.response.exceptions.opensearchexception.OpenSearchExceptionProtoUtils; import java.io.IOException; @@ -37,12 +39,15 @@ public class OpenSearchExceptionProtoUtilsTests extends OpenSearchTestCase { private static final String TEST_NODE_ID = "test_node_id"; + private final ResponseHandlingParams detailedErrorsEnabled = new ResponseHandlingParams(true, GlobalParams.newBuilder().setErrorTrace(true).build()); + private final ResponseHandlingParams errorsSummaryEnabled = new ResponseHandlingParams(); + public void testToProtoWithOpenSearchException() throws IOException { // Create an OpenSearchException OpenSearchException exception = new OpenSearchException("Test exception"); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.toProto(exception); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.toProto(exception, detailedErrorsEnabled); // Verify the conversion // The actual type format uses underscores instead of dots @@ -53,13 +58,27 @@ public void testToProtoWithOpenSearchException() throws IOException { assertFalse("Should not have a cause", errorCause.hasCausedBy()); } + public void testToProtoWithOpenSearchExceptionSummary() throws IOException { + // Create an OpenSearchException + OpenSearchException exception = new OpenSearchException("Test exception"); + + // Convert to Protocol Buffer + ErrorCause errorCause = OpenSearchExceptionProtoUtils.toProto(exception, errorsSummaryEnabled); + + // Verify the conversion + // The actual type format uses underscores instead of dots + assertFalse("Should not have a stack trace", errorCause.hasStackTrace()); + assertFalse("Should not have suppressed exceptions", errorCause.getSuppressedList().iterator().hasNext()); + assertFalse("Should not have a cause", errorCause.hasCausedBy()); + } + public void testToProtoWithNestedOpenSearchException() throws IOException { // Create a nested OpenSearchException IOException cause = new IOException("Cause exception"); OpenSearchException exception = new OpenSearchException("Test exception", cause); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.toProto(exception); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.toProto(exception, detailedErrorsEnabled); // Verify the conversion // The actual type format uses underscores instead of dots @@ -71,6 +90,30 @@ public void testToProtoWithNestedOpenSearchException() throws IOException { assertTrue("Should have a cause", errorCause.hasCausedBy()); ErrorCause causedBy = errorCause.getCausedBy(); // The actual type format uses underscores instead of dots + assertTrue("Should have a stack trace for cause", causedBy.getStackTrace().length() > 0); + assertEquals("Cause should have the correct type", "i_o_exception", causedBy.getType()); + assertEquals("Cause should have the correct reason", "Cause exception", causedBy.getReason()); + } + + public void testToProtoWithNestedOpenSearchExceptionSummary() throws IOException { + // Create a nested OpenSearchException + IOException cause = new IOException("Cause exception"); + OpenSearchException exception = new OpenSearchException("Test exception", cause); + + // Convert to Protocol Buffer + ErrorCause errorCause = OpenSearchExceptionProtoUtils.toProto(exception, errorsSummaryEnabled); + + // Verify the conversion + // The actual type format uses underscores instead of dots + assertEquals("Should have the correct type", "exception", errorCause.getType()); + assertEquals("Should have the correct reason", "Test exception", errorCause.getReason()); + assertFalse("Should not have a stack trace", errorCause.hasStackTrace()); + + // Verify the cause + assertTrue("Should have a cause", errorCause.hasCausedBy()); + ErrorCause causedBy = errorCause.getCausedBy(); + // The actual type format uses underscores instead of dots + assertFalse("Should not have a stack trace on the cause", causedBy.hasStackTrace()); assertEquals("Cause should have the correct type", "i_o_exception", causedBy.getType()); assertEquals("Cause should have the correct reason", "Cause exception", causedBy.getReason()); } @@ -80,7 +123,7 @@ public void testGenerateThrowableProtoWithOpenSearchException() throws IOExcepti OpenSearchException exception = new OpenSearchException("Test exception"); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, new ResponseHandlingParams()); // Verify the conversion // The actual type format uses underscores instead of dots @@ -93,7 +136,7 @@ public void testGenerateThrowableProtoWithIOException() throws IOException { IOException exception = new IOException("Test IO exception"); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, new ResponseHandlingParams()); // Verify the conversion // The actual type format uses underscores instead of dots @@ -106,7 +149,7 @@ public void testGenerateThrowableProtoWithRuntimeException() throws IOException RuntimeException exception = new RuntimeException("Test runtime exception"); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, new ResponseHandlingParams()); // Verify the conversion // The actual type format uses underscores instead of dots @@ -119,7 +162,7 @@ public void testGenerateThrowableProtoWithNullMessage() throws IOException { RuntimeException exception = new RuntimeException((String) null); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, new ResponseHandlingParams()); // Verify the conversion // The actual type format uses underscores instead of dots @@ -133,7 +176,7 @@ public void testGenerateThrowableProtoWithSuppressedExceptions() throws IOExcept exception.addSuppressed(new IllegalArgumentException("Suppressed exception")); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, errorsSummaryEnabled); // Verify the conversion // The actual type format uses underscores instead of dots @@ -153,7 +196,7 @@ public void testInnerToProtoWithBasicException() throws IOException { RuntimeException exception = new RuntimeException("Test exception"); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, detailedErrorsEnabled); // Verify the conversion // The actual type format uses underscores instead of dots @@ -162,6 +205,20 @@ public void testInnerToProtoWithBasicException() throws IOException { assertTrue("Should have a stack trace", errorCause.getStackTrace().length() > 0); } + public void testInnerToProtoReturnsOnlyBasicExceptionSummary() throws IOException { + // Create a basic exception + RuntimeException exception = new RuntimeException("Test exception"); + + // Convert to Protocol Buffer + ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, errorsSummaryEnabled); + + // Verify the conversion + // The actual type format uses underscores instead of dots + assertEquals("Should have the correct type", "runtime_exception", errorCause.getType()); + assertEquals("Should have the correct reason", "Test exception", errorCause.getReason()); + assertFalse("Should not have a stack trace", errorCause.hasStackTrace()); + } + public void testHeaderToProtoWithSingleValue() throws IOException { // Create a header with a single value String key = "test-header"; diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtilsTests.java index 7aadbed045dca..0a477e0b3209e 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtilsTests.java @@ -15,6 +15,7 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.protobufs.ShardFailure; import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import java.io.IOException; @@ -29,7 +30,7 @@ public void testToProtoWithDefaultShardOperationFailedException() throws IOExcep ); // Call the method under test - ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception); + ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception, new ResponseHandlingParams()); // Verify the result assertNotNull("ShardFailure should not be null", shardFailure); @@ -49,7 +50,7 @@ public void testToProtoWithAddIndexBlockResponseFailure() throws IOException { ); // Call the method under test - ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception); + ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception, new ResponseHandlingParams()); // Verify the result assertNotNull("ShardFailure should not be null", shardFailure); @@ -70,7 +71,7 @@ public void testToProtoWithIndicesShardStoresResponseFailure() throws IOExceptio ); // Call the method under test - ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception); + ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception, new ResponseHandlingParams()); // Verify the result assertNotNull("ShardFailure should not be null", shardFailure); @@ -91,7 +92,7 @@ public void testToProtoWithCloseIndexResponseFailure() throws IOException { ); // Call the method under test - ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception); + ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception, new ResponseHandlingParams()); // Verify the result assertNotNull("ShardFailure should not be null", shardFailure); @@ -112,7 +113,7 @@ public void testToProtoWithNullNodeId() throws IOException { ); // Call the method under test - ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception); + ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception, new ResponseHandlingParams()); // Verify the result assertNotNull("ShardFailure should not be null", shardFailure); diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtilsTests.java index 4c9e018bcef4a..0c7e2256574ac 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtilsTests.java @@ -18,6 +18,7 @@ import org.opensearch.search.SearchShardTarget; import org.opensearch.snapshots.SnapshotShardFailure; import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import java.io.IOException; @@ -35,7 +36,7 @@ public void testToProtoWithShardSearchFailure() throws IOException { ShardSearchFailure shardSearchFailure = new ShardSearchFailure(new Exception("fake exception"), searchShardTarget); // Call the method under test - ShardFailure protoFailure = ShardOperationFailedExceptionProtoUtils.toProto(shardSearchFailure); + ShardFailure protoFailure = ShardOperationFailedExceptionProtoUtils.toProto(shardSearchFailure, new ResponseHandlingParams()); // Verify the result assertNotNull("Proto failure should not be null", protoFailure); @@ -53,7 +54,7 @@ public void testToProtoWithSnapshotShardFailure() throws IOException { SnapshotShardFailure shardSearchFailure = new SnapshotShardFailure("test_node", shardId, "Snapshot failed"); // Call the method under test - ShardFailure protoFailure = ShardOperationFailedExceptionProtoUtils.toProto(shardSearchFailure); + ShardFailure protoFailure = ShardOperationFailedExceptionProtoUtils.toProto(shardSearchFailure, new ResponseHandlingParams()); // Verify the result assertNotNull("Proto failure should not be null", protoFailure); @@ -72,7 +73,7 @@ public void testToProtoWithDefaultShardOperationFailedException() throws IOExcep ); // Call the method under test - ShardFailure protoFailure = ShardOperationFailedExceptionProtoUtils.toProto(defaultShardOperationFailedException); + ShardFailure protoFailure = ShardOperationFailedExceptionProtoUtils.toProto(defaultShardOperationFailedException, new ResponseHandlingParams()); // Verify the result assertNotNull("Proto failure should not be null", protoFailure); @@ -93,7 +94,7 @@ public void testToProtoWithReplicationResponseShardInfoFailure() throws IOExcept ); // Call the method under test - ShardFailure protoFailure = ShardOperationFailedExceptionProtoUtils.toProto(replicationResponseFailure); + ShardFailure protoFailure = ShardOperationFailedExceptionProtoUtils.toProto(replicationResponseFailure, new ResponseHandlingParams()); // Verify the result assertNotNull("Proto failure should not be null", protoFailure); @@ -111,7 +112,7 @@ public void testToProtoWithUnsupportedShardOperationFailedException() { // Call the method under test, should throw UnsupportedOperationException UnsupportedOperationException exception = expectThrows( UnsupportedOperationException.class, - () -> ShardOperationFailedExceptionProtoUtils.toProto(mockFailure) + () -> ShardOperationFailedExceptionProtoUtils.toProto(mockFailure, new ResponseHandlingParams()) ); assertTrue( diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtilsTests.java index 2408a6d8dc6ae..fe29810fdb445 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtilsTests.java @@ -16,6 +16,7 @@ import org.opensearch.protobufs.PhaseTook; import org.opensearch.search.SearchHits; import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import java.io.IOException; import java.util.HashMap; @@ -41,7 +42,7 @@ public void testToProtoWithBasicResponse() throws IOException { when(mockResponse.getInternalResponse()).thenReturn(mock(SearchResponseSections.class)); // Call the method under test - org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse); + org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, new ResponseHandlingParams()); // Verify the result assertNotNull("Proto response should not be null", protoResponse); @@ -69,7 +70,7 @@ public void testToProtoWithScrollId() throws IOException { when(mockResponse.getInternalResponse()).thenReturn(mock(SearchResponseSections.class)); // Call the method under test - org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse); + org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, new ResponseHandlingParams()); // Verify the result assertNotNull("Proto response should not be null", protoResponse); @@ -92,7 +93,7 @@ public void testToProtoWithPointInTimeId() throws IOException { when(mockResponse.getInternalResponse()).thenReturn(mock(SearchResponseSections.class)); // Call the method under test - org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse); + org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, new ResponseHandlingParams()); // Verify the result assertNotNull("Proto response should not be null", protoResponse); @@ -126,7 +127,7 @@ public void testToProtoWithPhaseTook() throws IOException { when(mockResponse.getInternalResponse()).thenReturn(mock(SearchResponseSections.class)); // Call the method under test - org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse); + org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, new ResponseHandlingParams()); // Verify the result assertNotNull("Proto response should not be null", protoResponse); @@ -155,7 +156,7 @@ public void testToProtoWithTerminatedEarly() throws IOException { when(mockResponse.getInternalResponse()).thenReturn(mock(SearchResponseSections.class)); // Call the method under test - org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse); + org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, new ResponseHandlingParams()); // Verify the result assertNotNull("Proto response should not be null", protoResponse); @@ -178,7 +179,7 @@ public void testToProtoWithNumReducePhases() throws IOException { when(mockResponse.getInternalResponse()).thenReturn(mock(SearchResponseSections.class)); // Call the method under test - org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse); + org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, new ResponseHandlingParams()); // Verify the result assertNotNull("Proto response should not be null", protoResponse); @@ -200,7 +201,7 @@ public void testToProtoWithClusters() throws IOException { when(mockResponse.getInternalResponse()).thenReturn(mock(SearchResponseSections.class)); // Call the method under test - org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse); + org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, new ResponseHandlingParams()); // Verify the result assertNotNull("Proto response should not be null", protoResponse); diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/SearchServiceImplTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/SearchServiceImplTests.java index f10e683a36efe..b79f2d9c6d3bc 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/SearchServiceImplTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/SearchServiceImplTests.java @@ -101,10 +101,7 @@ public void testErrorTracingConfigValidationFailsWhenServerSettingIsDisabledAndR SearchServiceImpl serviceWithDisabledErrorsTracing = new SearchServiceImpl(client, queryUtils, false); // Call search method - serviceWithDisabledErrorsTracing.search(request, responseObserver); - - // Verify that responseObserver.onError reports request parameter must be disabled - verify(responseObserver).onError(any(StatusRuntimeException.class)); + expectThrows(IllegalArgumentException.class, () -> serviceWithDisabledErrorsTracing.search(request, responseObserver)); } public void testErrorTracingConfigValidationPassesWhenServerSettingIsDisabledAndRequestSkipsTracing() { diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java index 744d56d200013..a9258f2d364aa 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java @@ -75,10 +75,7 @@ public void testErrorTracingConfigValidationFailsWhenServerSettingIsDisabledAndR DocumentServiceImpl serviceWithDisabledErrorsTracing = new DocumentServiceImpl(client, false); // Call bulk method - serviceWithDisabledErrorsTracing.bulk(request, responseObserver); - - // Verify that an error was sent - verify(responseObserver).onError(any(StatusRuntimeException.class)); + expectThrows(IllegalArgumentException.class, () -> serviceWithDisabledErrorsTracing.bulk(request, responseObserver)); } public void testErrorTracingConfigValidationPassesWhenServerSettingIsDisabledAndRequestSkipsTracing() { @@ -103,12 +100,9 @@ private BulkRequest createTestBulkRequest() { .setObject(ByteString.copyFromUtf8("{\"field\":\"value\"}")) .build(); - BulkRequestBody requestBody = BulkRequestBody.newBuilder() - .setOperationContainer(org.opensearch.protobufs.OperationContainer.newBuilder().setIndex(indexOp).build()) - .setGlobalParams(org.opensearch.protobufs.GlobalParams.newBuilder().setErrorTrace(true)) - .setObject(ByteString.copyFromUtf8("{\"field\":\"value\"}")) - .build(); - - return BulkRequest.newBuilder().addBulkRequestBody(requestBody).build(); + return BulkRequest.newBuilder() + .addBulkRequestBody(requestBody) + .setGlobalParams(org.opensearch.protobufs.GlobalParams.newBuilder().setErrorTrace(true)) + .build(); } } diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcErrorHandlerTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcErrorHandlerTests.java index ff4627015112c..449d2202a2820 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcErrorHandlerTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcErrorHandlerTests.java @@ -16,7 +16,9 @@ import org.opensearch.core.common.breaker.CircuitBreakingException; import org.opensearch.core.concurrency.OpenSearchRejectedExecutionException; import org.opensearch.core.rest.RestStatus; +import org.opensearch.protobufs.GlobalParams; import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import java.io.IOException; import java.util.concurrent.TimeoutException; @@ -31,6 +33,8 @@ */ public class GrpcErrorHandlerTests extends OpenSearchTestCase { + private final ResponseHandlingParams detailedErrorsInResponse = new ResponseHandlingParams(true, GlobalParams.newBuilder().setErrorTrace(true).build()); + public void testOpenSearchExceptionConversion() { OpenSearchException exception = new OpenSearchException("Test exception") { @Override @@ -39,7 +43,7 @@ public RestStatus status() { } }; - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); // BAD_REQUEST -> INVALID_ARGUMENT via RestToGrpcStatusConverter assertEquals(Status.INVALID_ARGUMENT.getCode(), result.getStatus().getCode()); @@ -54,7 +58,7 @@ public RestStatus status() { public void testIllegalArgumentExceptionConversion() { IllegalArgumentException exception = new IllegalArgumentException("Invalid parameter"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); // IllegalArgumentException -> INVALID_ARGUMENT via direct gRPC mapping assertEquals(Status.INVALID_ARGUMENT.getCode(), result.getStatus().getCode()); @@ -65,7 +69,7 @@ public void testIllegalArgumentExceptionConversion() { public void testInputCoercionExceptionConversion() { InputCoercionException exception = new InputCoercionException(null, "Cannot coerce string to number", null, String.class); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); // InputCoercionException -> INVALID_ARGUMENT via direct gRPC mapping assertEquals(Status.INVALID_ARGUMENT.getCode(), result.getStatus().getCode()); @@ -77,7 +81,7 @@ public void testInputCoercionExceptionConversion() { public void testJsonParseExceptionConversion() { JsonParseException exception = new JsonParseException(null, "Unexpected character"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); // JsonParseException -> INVALID_ARGUMENT via direct gRPC mapping assertEquals(Status.INVALID_ARGUMENT.getCode(), result.getStatus().getCode()); @@ -89,7 +93,7 @@ public void testJsonParseExceptionConversion() { public void testOpenSearchRejectedExecutionExceptionConversion() { OpenSearchRejectedExecutionException exception = new OpenSearchRejectedExecutionException("Thread pool full"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); // OpenSearchRejectedExecutionException -> RESOURCE_EXHAUSTED via direct gRPC mapping assertEquals(Status.RESOURCE_EXHAUSTED.getCode(), result.getStatus().getCode()); @@ -101,7 +105,7 @@ public void testOpenSearchRejectedExecutionExceptionConversion() { public void testIllegalStateExceptionConversion() { IllegalStateException exception = new IllegalStateException("Invalid state"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); // IllegalStateException -> FAILED_PRECONDITION via direct gRPC mapping assertEquals(Status.FAILED_PRECONDITION.getCode(), result.getStatus().getCode()); @@ -112,7 +116,7 @@ public void testIllegalStateExceptionConversion() { public void testSecurityExceptionConversion() { SecurityException exception = new SecurityException("Access denied"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); // SecurityException -> PERMISSION_DENIED via direct gRPC mapping assertEquals(Status.PERMISSION_DENIED.getCode(), result.getStatus().getCode()); @@ -123,7 +127,7 @@ public void testSecurityExceptionConversion() { public void testTimeoutExceptionConversion() { TimeoutException exception = new TimeoutException("Operation timed out"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); // TimeoutException -> DEADLINE_EXCEEDED via direct gRPC mapping assertEquals(Status.DEADLINE_EXCEEDED.getCode(), result.getStatus().getCode()); @@ -134,7 +138,7 @@ public void testTimeoutExceptionConversion() { public void testInterruptedExceptionConversion() { InterruptedException exception = new InterruptedException(); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); // InterruptedException -> CANCELLED via direct gRPC mapping assertEquals(Status.CANCELLED.getCode(), result.getStatus().getCode()); @@ -145,7 +149,7 @@ public void testInterruptedExceptionConversion() { public void testIOExceptionConversion() { IOException exception = new IOException("I/O error"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); // IOException -> INTERNAL via direct gRPC mapping assertEquals(Status.INTERNAL.getCode(), result.getStatus().getCode()); @@ -156,7 +160,7 @@ public void testIOExceptionConversion() { public void testUnknownExceptionConversion() { RuntimeException exception = new RuntimeException("Unknown error"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); // RuntimeException -> INTERNAL via fallback (unknown exception type) assertEquals(Status.INTERNAL.getCode(), result.getStatus().getCode()); @@ -172,7 +176,7 @@ public RestStatus status() { } }; - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); // NOT_FOUND -> NOT_FOUND via RestToGrpcStatusConverter assertEquals(Status.NOT_FOUND.getCode(), result.getStatus().getCode()); @@ -184,7 +188,7 @@ public RestStatus status() { public void testCircuitBreakingExceptionInCleanMessage() { CircuitBreakingException exception = new CircuitBreakingException("Memory circuit breaker", 100, 90, null); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); // CircuitBreakingException extends OpenSearchException with TOO_MANY_REQUESTS -> RESOURCE_EXHAUSTED assertEquals(Status.RESOURCE_EXHAUSTED.getCode(), result.getStatus().getCode()); @@ -200,7 +204,7 @@ public void testSearchPhaseExecutionExceptionInCleanMessage() { new org.opensearch.action.search.ShardSearchFailure[0] ); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); // SearchPhaseExecutionException extends OpenSearchException with SERVICE_UNAVAILABLE -> UNAVAILABLE assertEquals(Status.UNAVAILABLE.getCode(), result.getStatus().getCode()); @@ -221,7 +225,7 @@ public RestStatus status() { }; exception.addMetadata("opensearch.test_key", "test_value"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); // Should include metadata in JSON details assertTrue(result.getMessage().contains("details=")); @@ -247,7 +251,7 @@ public void metadataToXContent( } }; - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); // Should fall back to base description when XContent extraction fails assertEquals(Status.INVALID_ARGUMENT.getCode(), result.getStatus().getCode()); @@ -272,7 +276,7 @@ public RestStatus status() { } }; - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(wrappedException); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(wrappedException, detailedErrorsInResponse); // Should include root_cause array like HTTP responses assertTrue(result.getMessage().contains("root_cause")); From 6f06a3ee205a35506571f16b4ba2b7626e333706 Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Wed, 5 Nov 2025 14:57:04 +0100 Subject: [PATCH 09/28] Encapsulate handling of global request parameters in an initializable utility class with corresponding refactoring Signed-off-by: Sergei Ustimenko --- .../opensearch/transport/grpc/GrpcPlugin.java | 15 ++--- .../listeners/BulkRequestActionListener.java | 9 +-- .../SearchRequestActionListener.java | 9 +-- .../bulk/BulkItemResponseProtoUtils.java | 4 +- .../document/bulk/BulkResponseProtoUtils.java | 4 +- .../common/DocWriteResponseProtoUtils.java | 4 +- .../document/common/ShardInfoProtoUtils.java | 6 +- .../exceptions/ResponseHandlingParams.java | 52 ---------------- .../OpenSearchExceptionProtoUtils.java | 11 ++-- ...ardOperationFailedExceptionProtoUtils.java | 12 ++-- ...ionResponseShardInfoFailureProtoUtils.java | 4 +- ...ardOperationFailedExceptionProtoUtils.java | 4 +- .../ShardSearchFailureProtoUtils.java | 4 +- .../SnapshotShardFailureProtoUtils.java | 4 +- .../search/ProtoActionsProtoUtils.java | 4 +- .../search/SearchResponseProtoUtils.java | 7 +-- .../search/ShardStatisticsProtoUtils.java | 4 +- .../grpc/services/DocumentServiceImpl.java | 13 ++-- .../grpc/services/SearchServiceImpl.java | 13 ++-- .../transport/grpc/util/GrpcErrorHandler.java | 51 ++++++++-------- .../grpc/util/GrpcParamsHandler.java | 59 +++++++++++++++++++ .../BulkRequestActionListenerTests.java | 4 +- .../SearchRequestActionListenerTests.java | 5 +- .../response/BulkResponseProtoUtilsTests.java | 9 +-- .../grpc/proto/response/TestFixtures.java | 19 ++++++ .../bulk/BulkItemResponseProtoUtilsTests.java | 35 ++++++++--- .../DocWriteResponseProtoUtilsTests.java | 11 ++-- .../common/ShardInfoProtoUtilsTests.java | 9 +-- .../OpenSearchExceptionProtoUtilsTests.java | 29 ++++----- ...erationFailedExceptionProtoUtilsTests.java | 13 ++-- ...erationFailedExceptionProtoUtilsTests.java | 15 +++-- .../search/SearchResponseProtoUtilsTests.java | 16 ++--- .../grpc/services/SearchServiceImplTests.java | 38 ++++++++---- .../document/DocumentServiceImplTests.java | 35 ++++++++--- .../grpc/util/GrpcErrorHandlerTests.java | 3 +- .../grpc/util/GrpcParamsHandlerTest.java | 55 +++++++++++++++++ 36 files changed, 354 insertions(+), 235 deletions(-) delete mode 100644 modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/ResponseHandlingParams.java create mode 100644 modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcParamsHandler.java create mode 100644 modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/TestFixtures.java create mode 100644 modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcParamsHandlerTest.java diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/GrpcPlugin.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/GrpcPlugin.java index c8bc55a95870f..9fb842ccd51d3 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/GrpcPlugin.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/GrpcPlugin.java @@ -42,6 +42,7 @@ import org.opensearch.transport.grpc.spi.GrpcServiceFactory; import org.opensearch.transport.grpc.spi.QueryBuilderProtoConverter; import org.opensearch.transport.grpc.ssl.SecureNetty4GrpcServerTransport; +import org.opensearch.transport.grpc.util.GrpcParamsHandler; import org.opensearch.watcher.ResourceWatcherService; import java.util.ArrayList; @@ -212,12 +213,9 @@ public Map> getAuxTransports( } return Collections.singletonMap(GRPC_TRANSPORT_SETTING_KEY, () -> { - boolean detailedErrorsEnabled = SETTING_GRPC_DETAILED_ERRORS_ENABLED.get(settings); + GrpcParamsHandler.initialize(settings); List grpcServices = new ArrayList<>( - List.of( - new DocumentServiceImpl(client, detailedErrorsEnabled), - new SearchServiceImpl(client, queryUtils, detailedErrorsEnabled) - ) + List.of(new DocumentServiceImpl(client), new SearchServiceImpl(client, queryUtils)) ); for (GrpcServiceFactory serviceFac : servicesFactory) { List pluginServices = serviceFac.initClient(client) @@ -268,12 +266,9 @@ public Map> getSecureAuxTransports( } return Collections.singletonMap(GRPC_SECURE_TRANSPORT_SETTING_KEY, () -> { - boolean detailedErrorsEnabled = SETTING_GRPC_DETAILED_ERRORS_ENABLED.get(settings); + GrpcParamsHandler.initialize(settings); List grpcServices = new ArrayList<>( - List.of( - new DocumentServiceImpl(client, detailedErrorsEnabled), - new SearchServiceImpl(client, queryUtils, detailedErrorsEnabled) - ) + List.of(new DocumentServiceImpl(client), new SearchServiceImpl(client, queryUtils)) ); for (GrpcServiceFactory serviceFac : servicesFactory) { List pluginServices = serviceFac.initClient(client) diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListener.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListener.java index 048062c2bd3db..020d24b9cd65e 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListener.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListener.java @@ -12,8 +12,8 @@ import org.apache.logging.log4j.Logger; import org.opensearch.action.bulk.BulkResponse; import org.opensearch.core.action.ActionListener; +import org.opensearch.protobufs.GlobalParams; import org.opensearch.transport.grpc.proto.response.document.bulk.BulkResponseProtoUtils; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import org.opensearch.transport.grpc.util.GrpcErrorHandler; import java.io.IOException; @@ -27,7 +27,7 @@ public class BulkRequestActionListener implements ActionListener { private static final Logger logger = LogManager.getLogger(BulkRequestActionListener.class); private final StreamObserver responseObserver; - private final ResponseHandlingParams params; + private final GlobalParams params; /** * Creates a new BulkRequestActionListener. @@ -35,10 +35,7 @@ public class BulkRequestActionListener implements ActionListener { * @param responseObserver The gRPC stream observer to send the response back to the client * @param params parameters that are going to change how responses and errors are handled */ - public BulkRequestActionListener( - StreamObserver responseObserver, - ResponseHandlingParams params - ) { + public BulkRequestActionListener(StreamObserver responseObserver, GlobalParams params) { super(); this.responseObserver = responseObserver; this.params = params; diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/listeners/SearchRequestActionListener.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/listeners/SearchRequestActionListener.java index dcf4da4672d40..4d25ef7b3ec71 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/listeners/SearchRequestActionListener.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/listeners/SearchRequestActionListener.java @@ -12,7 +12,7 @@ import org.apache.logging.log4j.Logger; import org.opensearch.action.search.SearchResponse; import org.opensearch.core.action.ActionListener; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; +import org.opensearch.protobufs.GlobalParams; import org.opensearch.transport.grpc.proto.response.search.SearchResponseProtoUtils; import org.opensearch.transport.grpc.util.GrpcErrorHandler; @@ -28,7 +28,7 @@ public class SearchRequestActionListener implements ActionListener responseObserver; - private final ResponseHandlingParams params; + private final GlobalParams params; /** * Constructs a new SearchRequestActionListener. @@ -36,10 +36,7 @@ public class SearchRequestActionListener implements ActionListener responseObserver, - ResponseHandlingParams params - ) { + public SearchRequestActionListener(StreamObserver responseObserver, GlobalParams params) { super(); this.responseObserver = responseObserver; this.params = params; diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtils.java index eab4349eb57f3..4873d99a120a7 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtils.java @@ -14,12 +14,12 @@ import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.index.get.GetResult; import org.opensearch.protobufs.ErrorCause; +import org.opensearch.protobufs.GlobalParams; import org.opensearch.protobufs.Id; import org.opensearch.protobufs.NullValue; import org.opensearch.protobufs.ResponseItem; import org.opensearch.transport.grpc.proto.response.document.common.DocWriteResponseProtoUtils; import org.opensearch.transport.grpc.proto.response.document.get.GetResultProtoUtils; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import org.opensearch.transport.grpc.proto.response.exceptions.opensearchexception.OpenSearchExceptionProtoUtils; import org.opensearch.transport.grpc.util.RestToGrpcStatusConverter; @@ -46,7 +46,7 @@ private BulkItemResponseProtoUtils() { * @throws IOException if there's an error during conversion * */ - public static ResponseItem toProto(BulkItemResponse response, ResponseHandlingParams params) throws IOException { + public static ResponseItem toProto(BulkItemResponse response, GlobalParams params) throws IOException { ResponseItem.Builder responseItemBuilder; if (response.isFailed() == false) { diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkResponseProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkResponseProtoUtils.java index beca944e7feda..daed66f567364 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkResponseProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkResponseProtoUtils.java @@ -11,7 +11,7 @@ import org.opensearch.action.bulk.BulkResponse; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; +import org.opensearch.protobufs.GlobalParams; import java.io.IOException; @@ -34,7 +34,7 @@ private BulkResponseProtoUtils() { * @return A Protocol Buffer BulkResponse representation * @throws IOException if there's an error during conversion */ - public static org.opensearch.protobufs.BulkResponse toProto(BulkResponse response, ResponseHandlingParams params) throws IOException { + public static org.opensearch.protobufs.BulkResponse toProto(BulkResponse response, GlobalParams params) throws IOException { // System.out.println("=== grpc bulk response=" + response.toString()); org.opensearch.protobufs.BulkResponse.Builder bulkResponse = org.opensearch.protobufs.BulkResponse.newBuilder(); diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtils.java index efb7ec7eed89f..7e970344216df 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtils.java @@ -10,11 +10,11 @@ import org.opensearch.action.DocWriteResponse; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.protobufs.GlobalParams; import org.opensearch.protobufs.Id; import org.opensearch.protobufs.NullValue; import org.opensearch.protobufs.ResponseItem; import org.opensearch.protobufs.ShardInfo; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import java.io.IOException; @@ -37,7 +37,7 @@ private DocWriteResponseProtoUtils() { * @return A ResponseItem.Builder with the DocWriteResponse data * */ - public static ResponseItem.Builder toProto(DocWriteResponse response, ResponseHandlingParams params) throws IOException { + public static ResponseItem.Builder toProto(DocWriteResponse response, GlobalParams params) throws IOException { ResponseItem.Builder responseItem = ResponseItem.newBuilder(); // Set the index name diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtils.java index 7f1f2a7ff7303..d8419381f3b3c 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtils.java @@ -10,9 +10,9 @@ import org.opensearch.action.support.replication.ReplicationResponse; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.protobufs.GlobalParams; import org.opensearch.protobufs.ShardFailure; import org.opensearch.protobufs.ShardInfo; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import org.opensearch.transport.grpc.proto.response.exceptions.opensearchexception.OpenSearchExceptionProtoUtils; import java.io.IOException; @@ -34,7 +34,7 @@ private ShardInfoProtoUtils() { * @return The protobuf representation of the shard information * @throws IOException If there's an error during conversion */ - public static ShardInfo toProto(ReplicationResponse.ShardInfo shardInfo, ResponseHandlingParams params) throws IOException { + public static ShardInfo toProto(ReplicationResponse.ShardInfo shardInfo, GlobalParams params) throws IOException { ShardInfo.Builder shardInfoBuilder = ShardInfo.newBuilder(); shardInfoBuilder.setTotal(shardInfo.getTotal()); shardInfoBuilder.setSuccessful(shardInfo.getSuccessful()); @@ -56,7 +56,7 @@ public static ShardInfo toProto(ReplicationResponse.ShardInfo shardInfo, Respons * @return The protobuf representation of the shard failure * @throws IOException If there's an error during conversion */ - private static ShardFailure toProto(ReplicationResponse.ShardInfo.Failure failure, ResponseHandlingParams params) throws IOException { + private static ShardFailure toProto(ReplicationResponse.ShardInfo.Failure failure, GlobalParams params) throws IOException { ShardFailure.Builder shardFailure = ShardFailure.newBuilder(); shardFailure.setIndex(failure.index()); shardFailure.setShard(failure.shardId()); diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/ResponseHandlingParams.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/ResponseHandlingParams.java deleted file mode 100644 index bec5bbabe79cc..0000000000000 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/ResponseHandlingParams.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - */ - -package org.opensearch.transport.grpc.proto.response.exceptions; - -import org.opensearch.protobufs.GlobalParams; - -public class ResponseHandlingParams { - - private final TracingLevel errorTracingLevel; - - public ResponseHandlingParams() { - this.errorTracingLevel = TracingLevel.SUMMARY; - } - - public ResponseHandlingParams(boolean detailedErrorsEnabled, GlobalParams errorTracesRequested) { - this.errorTracingLevel = getTracingLevel(detailedErrorsEnabled, errorTracesRequested); - } - - public TracingLevel getErrorTracingLevel() { - return errorTracingLevel; - } - - private static TracingLevel getTracingLevel(boolean detailedErrorsEnabled, GlobalParams globalParams) { - validateErrorTracingConfiguration(detailedErrorsEnabled, globalParams); - return globalParams.getErrorTrace() ? TracingLevel.DETAILED_TRACE : TracingLevel.SUMMARY; - } - - public enum TracingLevel { - SUMMARY, - DETAILED_TRACE - } - - /** - * Validates if error tracing is allowed based on server configuration and request parameters. - * - * @param detailedErrorsEnabled Whether detailed errors are enabled on the server - * @param globalRequestParams The global parameters from the gRPC request - * @throws IllegalArgumentException if error tracing is requested but disabled by the server side - */ - public static void validateErrorTracingConfiguration(boolean detailedErrorsEnabled, GlobalParams globalRequestParams) { - if (detailedErrorsEnabled == false && globalRequestParams.getErrorTrace()) { - throw new IllegalArgumentException("error traces in responses are disabled."); - } - } - -} diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/opensearchexception/OpenSearchExceptionProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/opensearchexception/OpenSearchExceptionProtoUtils.java index d0fc4ba833722..4bc3a56987117 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/opensearchexception/OpenSearchExceptionProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/opensearchexception/OpenSearchExceptionProtoUtils.java @@ -17,6 +17,7 @@ import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.protobufs.ErrorCause; +import org.opensearch.protobufs.GlobalParams; import org.opensearch.protobufs.ObjectMap; import org.opensearch.protobufs.StringArray; import org.opensearch.protobufs.StringOrStringArray; @@ -26,12 +27,12 @@ import org.opensearch.transport.grpc.proto.response.exceptions.CircuitBreakingExceptionProtoUtils; import org.opensearch.transport.grpc.proto.response.exceptions.FailedNodeExceptionProtoUtils; import org.opensearch.transport.grpc.proto.response.exceptions.ParsingExceptionProtoUtils; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import org.opensearch.transport.grpc.proto.response.exceptions.ResponseLimitBreachedExceptionProtoUtils; import org.opensearch.transport.grpc.proto.response.exceptions.ScriptExceptionProtoUtils; import org.opensearch.transport.grpc.proto.response.exceptions.SearchParseExceptionProtoUtils; import org.opensearch.transport.grpc.proto.response.exceptions.SearchPhaseExecutionExceptionProtoUtils; import org.opensearch.transport.grpc.proto.response.exceptions.TooManyBucketsExceptionProtoUtils; +import org.opensearch.transport.grpc.util.GrpcParamsHandler; import java.io.IOException; import java.util.AbstractMap; @@ -60,7 +61,7 @@ private OpenSearchExceptionProtoUtils() { * @return A Protocol Buffer ErrorCause representation * @throws IOException if there's an error during conversion */ - public static ErrorCause toProto(OpenSearchException exception, ResponseHandlingParams params) throws IOException { + public static ErrorCause toProto(OpenSearchException exception, GlobalParams params) throws IOException { Throwable ex = ExceptionsHelper.unwrapCause(exception); if (ex != exception) { return generateThrowableProto(ex, params); @@ -88,7 +89,7 @@ public static ErrorCause toProto(OpenSearchException exception, ResponseHandling * @return A Protocol Buffer ErrorCause representation * @throws IOException if there's an error during conversion */ - public static ErrorCause generateThrowableProto(Throwable t, ResponseHandlingParams params) throws IOException { + public static ErrorCause generateThrowableProto(Throwable t, GlobalParams params) throws IOException { t = ExceptionsHelper.unwrapCause(t); if (t instanceof OpenSearchException) { @@ -118,7 +119,7 @@ public static ErrorCause innerToProto( Map> headers, Map> metadata, Throwable cause, - ResponseHandlingParams params + GlobalParams params ) throws IOException { ErrorCause.Builder errorCauseBuilder = ErrorCause.newBuilder(); @@ -160,7 +161,7 @@ public static ErrorCause innerToProto( } // Add stack trace - if (params.getErrorTracingLevel() == ResponseHandlingParams.TracingLevel.DETAILED_TRACE) { + if (GrpcParamsHandler.isDetailedStackTraceRequested(params)) { errorCauseBuilder.setStackTrace(ExceptionsHelper.stackTrace(throwable)); } diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtils.java index db6b7926de4a6..9cd3c2799d529 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtils.java @@ -13,8 +13,8 @@ import org.opensearch.core.action.support.DefaultShardOperationFailedException; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.protobufs.GlobalParams; import org.opensearch.protobufs.ShardFailure; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import org.opensearch.transport.grpc.proto.response.exceptions.opensearchexception.OpenSearchExceptionProtoUtils; import java.io.IOException; @@ -36,7 +36,7 @@ private DefaultShardOperationFailedExceptionProtoUtils() { * @param exception The DefaultShardOperationFailedException to convert * @return A Protocol Buffer Struct containing the exception metadata */ - public static ShardFailure toProto(DefaultShardOperationFailedException exception, ResponseHandlingParams params) throws IOException { + public static ShardFailure toProto(DefaultShardOperationFailedException exception, GlobalParams params) throws IOException { ShardFailure.Builder shardFailureBuilder = ShardFailure.newBuilder(); if (exception instanceof AddIndexBlockResponse.AddBlockShardResult.Failure) { @@ -62,7 +62,7 @@ public static ShardFailure toProto(DefaultShardOperationFailedException exceptio public static void innerToProto( ShardFailure.Builder shardFailureBuilder, AddIndexBlockResponse.AddBlockShardResult.Failure exception, - ResponseHandlingParams params + GlobalParams params ) throws IOException { if (exception.getNodeId() != null) { shardFailureBuilder.setNode(exception.getNodeId()); @@ -81,7 +81,7 @@ public static void innerToProto( public static void innerToProto( ShardFailure.Builder shardFailureBuilder, IndicesShardStoresResponse.Failure exception, - ResponseHandlingParams params + GlobalParams params ) throws IOException { shardFailureBuilder.setNode(exception.nodeId()); parentInnerToProto(shardFailureBuilder, exception, params); @@ -98,7 +98,7 @@ public static void innerToProto( public static void innerToProto( ShardFailure.Builder shardFailureBuilder, CloseIndexResponse.ShardResult.Failure exception, - ResponseHandlingParams params + GlobalParams params ) throws IOException { if (exception.getNodeId() != null) { shardFailureBuilder.setNode(exception.getNodeId()); @@ -117,7 +117,7 @@ public static void innerToProto( public static void parentInnerToProto( ShardFailure.Builder shardFailureBuilder, DefaultShardOperationFailedException exception, - ResponseHandlingParams params + GlobalParams params ) throws IOException { shardFailureBuilder.setShard(exception.shardId()); if (exception.index() != null) { diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ReplicationResponseShardInfoFailureProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ReplicationResponseShardInfoFailureProtoUtils.java index baa295552e2ed..6976984141ce6 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ReplicationResponseShardInfoFailureProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ReplicationResponseShardInfoFailureProtoUtils.java @@ -10,8 +10,8 @@ import org.opensearch.action.support.replication.ReplicationResponse; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.protobufs.GlobalParams; import org.opensearch.protobufs.ShardFailure; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import org.opensearch.transport.grpc.proto.response.exceptions.opensearchexception.OpenSearchExceptionProtoUtils; import java.io.IOException; @@ -32,7 +32,7 @@ private ReplicationResponseShardInfoFailureProtoUtils() { * @param exception The ReplicationResponse.ShardInfo.Failure to convert metadata from * @return A map containing the exception's metadata as ObjectMap.Value objects */ - public static ShardFailure toProto(ReplicationResponse.ShardInfo.Failure exception, ResponseHandlingParams params) throws IOException { + public static ShardFailure toProto(ReplicationResponse.ShardInfo.Failure exception, GlobalParams params) throws IOException { ShardFailure.Builder shardFailure = ShardFailure.newBuilder(); if (exception.index() != null) { shardFailure.setIndex(exception.index()); diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtils.java index f55aeb5b45fbc..db4ca3202ef82 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtils.java @@ -13,9 +13,9 @@ import org.opensearch.core.action.support.DefaultShardOperationFailedException; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.protobufs.GlobalParams; import org.opensearch.protobufs.ShardFailure; import org.opensearch.snapshots.SnapshotShardFailure; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import java.io.IOException; @@ -35,7 +35,7 @@ private ShardOperationFailedExceptionProtoUtils() { * @param exception The ShardOperationFailedException to convert metadata from * @return ShardFailure */ - public static ShardFailure toProto(ShardOperationFailedException exception, ResponseHandlingParams params) throws IOException { + public static ShardFailure toProto(ShardOperationFailedException exception, GlobalParams params) throws IOException { if (exception instanceof ShardSearchFailure) { return ShardSearchFailureProtoUtils.toProto((ShardSearchFailure) exception, params); } else if (exception instanceof SnapshotShardFailure) { diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardSearchFailureProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardSearchFailureProtoUtils.java index 65c76ba6b9b40..d6bf6c8fb2dfa 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardSearchFailureProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardSearchFailureProtoUtils.java @@ -10,8 +10,8 @@ import org.opensearch.action.search.ShardSearchFailure; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.protobufs.GlobalParams; import org.opensearch.protobufs.ShardFailure; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import org.opensearch.transport.grpc.proto.response.exceptions.opensearchexception.OpenSearchExceptionProtoUtils; import java.io.IOException; @@ -32,7 +32,7 @@ private ShardSearchFailureProtoUtils() { * @param exception The ShardSearchFailure to convert * @return A Protocol Buffer Struct containing the exception metadata */ - public static ShardFailure toProto(ShardSearchFailure exception, ResponseHandlingParams params) throws IOException { + public static ShardFailure toProto(ShardSearchFailure exception, GlobalParams params) throws IOException { ShardFailure.Builder shardFailure = ShardFailure.newBuilder(); shardFailure.setShard(exception.shardId()); shardFailure.setIndex(exception.index()); diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/SnapshotShardFailureProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/SnapshotShardFailureProtoUtils.java index de4c252dc0db7..b185c0b7f57c5 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/SnapshotShardFailureProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/SnapshotShardFailureProtoUtils.java @@ -9,9 +9,9 @@ import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.protobufs.GlobalParams; import org.opensearch.protobufs.ShardFailure; import org.opensearch.snapshots.SnapshotShardFailure; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import org.opensearch.transport.grpc.proto.response.exceptions.opensearchexception.OpenSearchExceptionProtoUtils; import java.io.IOException; @@ -32,7 +32,7 @@ private SnapshotShardFailureProtoUtils() { * @param exception The SnapshotShardFailure to convert * @return A Protocol Buffer Struct containing the exception metadata */ - public static ShardFailure toProto(SnapshotShardFailure exception, ResponseHandlingParams params) throws IOException { + public static ShardFailure toProto(SnapshotShardFailure exception, GlobalParams params) throws IOException { ShardFailure.Builder shardFailure = ShardFailure.newBuilder(); if (exception.index() != null) { shardFailure.setIndex(exception.index()); diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/ProtoActionsProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/ProtoActionsProtoUtils.java index 88410c0650554..76fbe79a685cf 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/ProtoActionsProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/ProtoActionsProtoUtils.java @@ -11,9 +11,9 @@ import org.opensearch.core.action.ShardOperationFailedException; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.protobufs.GlobalParams; import org.opensearch.protobufs.SearchResponse; import org.opensearch.rest.action.RestActions; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import java.io.IOException; @@ -46,7 +46,7 @@ protected static void buildBroadcastShardsHeader( int skipped, int failed, ShardOperationFailedException[] shardFailures, - ResponseHandlingParams params + GlobalParams params ) throws IOException { searchResponseProtoBuilder.setXShards( ShardStatisticsProtoUtils.getShardStats(total, successful, skipped, failed, shardFailures, params) diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtils.java index 4d7adafadf882..670a1b8c8445a 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtils.java @@ -12,7 +12,7 @@ import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; import org.opensearch.protobufs.ClusterStatistics; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; +import org.opensearch.protobufs.GlobalParams; import java.io.IOException; import java.util.Map; @@ -36,8 +36,7 @@ private SearchResponseProtoUtils() { * @return A Protocol Buffer SearchResponse representation * @throws IOException if there's an error during conversion */ - public static org.opensearch.protobufs.SearchResponse toProto(SearchResponse response, ResponseHandlingParams params) - throws IOException { + public static org.opensearch.protobufs.SearchResponse toProto(SearchResponse response, GlobalParams params) throws IOException { org.opensearch.protobufs.SearchResponse.Builder searchResponseProtoBuilder = org.opensearch.protobufs.SearchResponse.newBuilder(); toProto(response, searchResponseProtoBuilder, params); return searchResponseProtoBuilder.build(); @@ -55,7 +54,7 @@ public static org.opensearch.protobufs.SearchResponse toProto(SearchResponse res public static void toProto( SearchResponse response, org.opensearch.protobufs.SearchResponse.Builder searchResponseProtoBuilder, - ResponseHandlingParams params + GlobalParams params ) throws IOException { // Set optional fields only if they exist diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/ShardStatisticsProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/ShardStatisticsProtoUtils.java index 18f64015b89f8..f295870aff4bc 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/ShardStatisticsProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/ShardStatisticsProtoUtils.java @@ -13,8 +13,8 @@ import org.opensearch.core.common.util.CollectionUtils; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; +import org.opensearch.protobufs.GlobalParams; import org.opensearch.protobufs.ShardStatistics; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import org.opensearch.transport.grpc.proto.response.exceptions.shardoperationfailedexception.ShardOperationFailedExceptionProtoUtils; import java.io.IOException; @@ -48,7 +48,7 @@ protected static ShardStatistics getShardStats( int skipped, int failed, ShardOperationFailedException[] shardFailures, - ResponseHandlingParams params + GlobalParams params ) throws IOException { ShardStatistics.Builder shardStats = ShardStatistics.newBuilder(); shardStats.setTotal(total); diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/services/DocumentServiceImpl.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/services/DocumentServiceImpl.java index c60542daacd96..952797febfba1 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/services/DocumentServiceImpl.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/services/DocumentServiceImpl.java @@ -14,8 +14,8 @@ import org.opensearch.transport.client.Client; import org.opensearch.transport.grpc.listeners.BulkRequestActionListener; import org.opensearch.transport.grpc.proto.request.document.bulk.BulkRequestProtoUtils; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import org.opensearch.transport.grpc.util.GrpcErrorHandler; +import org.opensearch.transport.grpc.util.GrpcParamsHandler; import io.grpc.StatusRuntimeException; import io.grpc.stub.StreamObserver; @@ -26,17 +26,14 @@ public class DocumentServiceImpl extends DocumentServiceGrpc.DocumentServiceImplBase { private static final Logger logger = LogManager.getLogger(DocumentServiceImpl.class); private final Client client; - private final boolean detailedErrorsEnabled; /** * Creates a new DocumentServiceImpl. * * @param client Client for executing actions on the local node - * @param detailedErrorsEnabled Whether detailed error tracing is enabled */ - public DocumentServiceImpl(Client client, boolean detailedErrorsEnabled) { + public DocumentServiceImpl(Client client) { this.client = client; - this.detailedErrorsEnabled = detailedErrorsEnabled; } /** @@ -47,14 +44,14 @@ public DocumentServiceImpl(Client client, boolean detailedErrorsEnabled) { */ @Override public void bulk(org.opensearch.protobufs.BulkRequest request, StreamObserver responseObserver) { - ResponseHandlingParams params = new ResponseHandlingParams(detailedErrorsEnabled, request.getGlobalParams()); try { + GrpcParamsHandler.validateStackTraceDetailsConfiguration(request.getGlobalParams()); org.opensearch.action.bulk.BulkRequest bulkRequest = BulkRequestProtoUtils.prepareRequest(request); - BulkRequestActionListener listener = new BulkRequestActionListener(responseObserver, params); + BulkRequestActionListener listener = new BulkRequestActionListener(responseObserver, request.getGlobalParams()); client.bulk(bulkRequest, listener); } catch (RuntimeException e) { logger.debug("DocumentServiceImpl failed: {} - {}", e.getClass().getSimpleName(), e.getMessage()); - StatusRuntimeException grpcError = GrpcErrorHandler.convertToGrpcError(e, params); + StatusRuntimeException grpcError = GrpcErrorHandler.convertToGrpcError(e, request.getGlobalParams()); responseObserver.onError(grpcError); } } diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/services/SearchServiceImpl.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/services/SearchServiceImpl.java index 8edb81084d927..b0ab074efbe1a 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/services/SearchServiceImpl.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/services/SearchServiceImpl.java @@ -15,8 +15,8 @@ import org.opensearch.transport.grpc.listeners.SearchRequestActionListener; import org.opensearch.transport.grpc.proto.request.search.SearchRequestProtoUtils; import org.opensearch.transport.grpc.proto.request.search.query.AbstractQueryBuilderProtoUtils; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import org.opensearch.transport.grpc.util.GrpcErrorHandler; +import org.opensearch.transport.grpc.util.GrpcParamsHandler; import java.io.IOException; @@ -32,16 +32,14 @@ public class SearchServiceImpl extends SearchServiceGrpc.SearchServiceImplBase { private static final Logger logger = LogManager.getLogger(SearchServiceImpl.class); private final Client client; private final AbstractQueryBuilderProtoUtils queryUtils; - private final boolean detailedErrorsEnabled; /** * Creates a new SearchServiceImpl. * * @param client Client for executing actions on the local node * @param queryUtils Query utils instance for parsing protobuf queries - * @param detailedErrorsEnabled Whether detailed error tracing is enabled */ - public SearchServiceImpl(Client client, AbstractQueryBuilderProtoUtils queryUtils, boolean detailedErrorsEnabled) { + public SearchServiceImpl(Client client, AbstractQueryBuilderProtoUtils queryUtils) { if (client == null) { throw new IllegalArgumentException("Client cannot be null"); } @@ -51,7 +49,6 @@ public SearchServiceImpl(Client client, AbstractQueryBuilderProtoUtils queryUtil this.client = client; this.queryUtils = queryUtils; - this.detailedErrorsEnabled = detailedErrorsEnabled; } /** @@ -65,14 +62,14 @@ public void search( org.opensearch.protobufs.SearchRequest request, StreamObserver responseObserver ) { - ResponseHandlingParams params = new ResponseHandlingParams(detailedErrorsEnabled, request.getGlobalParams()); try { + GrpcParamsHandler.validateStackTraceDetailsConfiguration(request.getGlobalParams()); org.opensearch.action.search.SearchRequest searchRequest = SearchRequestProtoUtils.prepareRequest(request, client, queryUtils); - SearchRequestActionListener listener = new SearchRequestActionListener(responseObserver, params); + SearchRequestActionListener listener = new SearchRequestActionListener(responseObserver, request.getGlobalParams()); client.search(searchRequest, listener); } catch (RuntimeException | IOException e) { logger.debug("SearchServiceImpl failed to process search request, request=" + request + ", error=" + e.getMessage()); - StatusRuntimeException grpcError = GrpcErrorHandler.convertToGrpcError(e, params); + StatusRuntimeException grpcError = GrpcErrorHandler.convertToGrpcError(e, request.getGlobalParams()); responseObserver.onError(grpcError); } } diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java index 6e5da953b48ac..79a950d94ddf3 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java @@ -21,7 +21,7 @@ import org.opensearch.core.concurrency.OpenSearchRejectedExecutionException; import org.opensearch.core.xcontent.ToXContent; import org.opensearch.core.xcontent.XContentBuilder; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; +import org.opensearch.protobufs.GlobalParams; import java.io.IOException; import java.util.concurrent.TimeoutException; @@ -48,63 +48,66 @@ private GrpcErrorHandler() { * @param params * @return StatusRuntimeException with appropriate gRPC status and enhanced error details */ - public static StatusRuntimeException convertToGrpcError(Exception e, ResponseHandlingParams params) { - ResponseHandlingParams.TracingLevel errorTracingLevel = params.getErrorTracingLevel(); + public static StatusRuntimeException convertToGrpcError(Exception e, GlobalParams params) { + boolean shouldIncludeDetailedStackTrace = GrpcParamsHandler.isDetailedStackTraceRequested(params); // ========== OpenSearch Business Logic Exceptions ========== // Custom OpenSearch exceptions which extend {@link OpenSearchException}. // Uses {@link RestToGrpcStatusConverter} for REST -> gRPC status mapping and // follows {@link OpenSearchException#generateFailureXContent} unwrapping logic if (e instanceof OpenSearchException) { - return handleOpenSearchException((OpenSearchException) e, errorTracingLevel); + return handleOpenSearchException((OpenSearchException) e, shouldIncludeDetailedStackTrace); } // ========== OpenSearch Core System Exceptions ========== // Low-level OpenSearch exceptions that don't extend OpenSearchException - include full details else if (e instanceof OpenSearchRejectedExecutionException) { - return Status.RESOURCE_EXHAUSTED.withDescription(getErrorDescriptionRespectingTracingLevel(e, errorTracingLevel)) + return Status.RESOURCE_EXHAUSTED.withDescription(getErrorDescriptionRespectingTracingLevel(e, shouldIncludeDetailedStackTrace)) .asRuntimeException(); } else if (e instanceof NotXContentException) { - return Status.INVALID_ARGUMENT.withDescription(getErrorDescriptionRespectingTracingLevel(e, errorTracingLevel)) + return Status.INVALID_ARGUMENT.withDescription(getErrorDescriptionRespectingTracingLevel(e, shouldIncludeDetailedStackTrace)) .asRuntimeException(); } else if (e instanceof NotCompressedException) { - return Status.INVALID_ARGUMENT.withDescription(getErrorDescriptionRespectingTracingLevel(e, errorTracingLevel)) + return Status.INVALID_ARGUMENT.withDescription(getErrorDescriptionRespectingTracingLevel(e, shouldIncludeDetailedStackTrace)) .asRuntimeException(); } // ========== 3. Third-party Library Exceptions ========== // External library exceptions (Jackson JSON parsing) - include full details else if (e instanceof InputCoercionException) { - return Status.INVALID_ARGUMENT.withDescription(getErrorDescriptionRespectingTracingLevel(e, errorTracingLevel)) + return Status.INVALID_ARGUMENT.withDescription(getErrorDescriptionRespectingTracingLevel(e, shouldIncludeDetailedStackTrace)) .asRuntimeException(); } else if (e instanceof JsonParseException) { - return Status.INVALID_ARGUMENT.withDescription(getErrorDescriptionRespectingTracingLevel(e, errorTracingLevel)) + return Status.INVALID_ARGUMENT.withDescription(getErrorDescriptionRespectingTracingLevel(e, shouldIncludeDetailedStackTrace)) .asRuntimeException(); } // ========== 4. Standard Java Exceptions ========== // Generic Java runtime exceptions - include full exception details for debugging else if (e instanceof IllegalArgumentException) { - return Status.INVALID_ARGUMENT.withDescription(getErrorDescriptionRespectingTracingLevel(e, errorTracingLevel)) + return Status.INVALID_ARGUMENT.withDescription(getErrorDescriptionRespectingTracingLevel(e, shouldIncludeDetailedStackTrace)) .asRuntimeException(); } else if (e instanceof IllegalStateException) { - return Status.FAILED_PRECONDITION.withDescription(getErrorDescriptionRespectingTracingLevel(e, errorTracingLevel)) + return Status.FAILED_PRECONDITION.withDescription(getErrorDescriptionRespectingTracingLevel(e, shouldIncludeDetailedStackTrace)) .asRuntimeException(); } else if (e instanceof SecurityException) { - return Status.PERMISSION_DENIED.withDescription(getErrorDescriptionRespectingTracingLevel(e, errorTracingLevel)) + return Status.PERMISSION_DENIED.withDescription(getErrorDescriptionRespectingTracingLevel(e, shouldIncludeDetailedStackTrace)) .asRuntimeException(); } else if (e instanceof TimeoutException) { - return Status.DEADLINE_EXCEEDED.withDescription(getErrorDescriptionRespectingTracingLevel(e, errorTracingLevel)) + return Status.DEADLINE_EXCEEDED.withDescription(getErrorDescriptionRespectingTracingLevel(e, shouldIncludeDetailedStackTrace)) .asRuntimeException(); } else if (e instanceof InterruptedException) { - return Status.CANCELLED.withDescription(getErrorDescriptionRespectingTracingLevel(e, errorTracingLevel)).asRuntimeException(); + return Status.CANCELLED.withDescription(getErrorDescriptionRespectingTracingLevel(e, shouldIncludeDetailedStackTrace)) + .asRuntimeException(); } else if (e instanceof IOException) { - return Status.INTERNAL.withDescription(getErrorDescriptionRespectingTracingLevel(e, errorTracingLevel)).asRuntimeException(); + return Status.INTERNAL.withDescription(getErrorDescriptionRespectingTracingLevel(e, shouldIncludeDetailedStackTrace)) + .asRuntimeException(); } // ========== 5. Unknown/Unmapped Exceptions ========== // Safety fallback for any unexpected exception to {@code Status.INTERNAL} with full debugging info else { logger.warn("Unmapped exception type: {}, treating as INTERNAL error", e.getClass().getSimpleName()); - return Status.INTERNAL.withDescription(getErrorDescriptionRespectingTracingLevel(e, errorTracingLevel)).asRuntimeException(); + return Status.INTERNAL.withDescription(getErrorDescriptionRespectingTracingLevel(e, shouldIncludeDetailedStackTrace)) + .asRuntimeException(); } } @@ -117,7 +120,7 @@ else if (e instanceof IllegalArgumentException) { * @param ose The OpenSearchException to convert * @return StatusRuntimeException with mapped gRPC status and HTTP-identical error message */ - private static StatusRuntimeException handleOpenSearchException(OpenSearchException ose, ResponseHandlingParams.TracingLevel params) { + private static StatusRuntimeException handleOpenSearchException(OpenSearchException ose, boolean shouldIncludeDetailedStackTrace) { Status grpcStatus = RestToGrpcStatusConverter.convertRestToGrpcStatus(ose.status()); // Use existing HTTP logic but enhance description with metadata from XContent @@ -125,7 +128,7 @@ private static StatusRuntimeException handleOpenSearchException(OpenSearchExcept String baseDescription = ExceptionsHelper.summaryMessage(unwrapped); // Extract metadata using the same XContent infrastructure as HTTP - String enhancedDescription = enhanceDescriptionWithXContentMetadata(unwrapped, baseDescription, params); + String enhancedDescription = enhanceDescriptionWithXContentMetadata(unwrapped, baseDescription, shouldIncludeDetailedStackTrace); return grpcStatus.withDescription(enhancedDescription).asRuntimeException(); } @@ -143,7 +146,7 @@ private static StatusRuntimeException handleOpenSearchException(OpenSearchExcept private static String enhanceDescriptionWithXContentMetadata( Throwable exception, String baseDescription, - ResponseHandlingParams.TracingLevel tracingLevel + boolean shouldIncludeDetailedStackTrace ) { try { // Use the exact same method as HTTP error responses @@ -153,12 +156,11 @@ private static String enhanceDescriptionWithXContentMetadata( // Use the same method as HTTP REST responses (BytesRestResponse.build) // This includes root_cause analysis, just like HTTP - boolean shouldExposeDetailedStackTrace = tracingLevel == ResponseHandlingParams.TracingLevel.DETAILED_TRACE; OpenSearchException.generateFailureXContent( builder, ToXContent.EMPTY_PARAMS, (Exception) exception, - shouldExposeDetailedStackTrace + shouldIncludeDetailedStackTrace ); // Add status field like HTTP does @@ -184,11 +186,8 @@ private static String enhanceDescriptionWithXContentMetadata( } } - private static String getErrorDescriptionRespectingTracingLevel(Throwable exception, ResponseHandlingParams.TracingLevel tracingLevel) { - if (tracingLevel == ResponseHandlingParams.TracingLevel.DETAILED_TRACE) { - return ExceptionsHelper.stackTrace(exception); - } - return exception.getMessage(); + private static String getErrorDescriptionRespectingTracingLevel(Throwable exception, boolean shouldIncludeDetailedStackTrace) { + return shouldIncludeDetailedStackTrace ? ExceptionsHelper.stackTrace(exception) : exception.getMessage(); } } diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcParamsHandler.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcParamsHandler.java new file mode 100644 index 0000000000000..8c4649d7bd0e9 --- /dev/null +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcParamsHandler.java @@ -0,0 +1,59 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.transport.grpc.util; + +import org.opensearch.common.settings.Settings; +import org.opensearch.protobufs.GlobalParams; + +import java.util.concurrent.atomic.AtomicBoolean; + +import static org.opensearch.transport.grpc.Netty4GrpcServerTransport.SETTING_GRPC_DETAILED_ERRORS_ENABLED; + +/** + * Central utility class to handle how global gRPC request parameters are handled. + */ +public class GrpcParamsHandler { + + /** + * Indicates whether detailed error traces are enabled on the gRPC server. + */ + private static final AtomicBoolean detailedErrorsEnabled = new AtomicBoolean(true); + + private GrpcParamsHandler() {} + + public static void initialize(Settings settings) { + detailedErrorsEnabled.set(SETTING_GRPC_DETAILED_ERRORS_ENABLED.get(settings)); + } + + /** + * Checks whether detailed stack trace was requested in the gRPC request parameters. + * This method can be further extended to encapsulate more complex behaviour like + * skipping stack traces as per server configuration, etc. + * + * @param globalParams the global gRPC request parameters + * @return if, in case of an exception, a detailed stack trace should be included in the response + */ + public static boolean isDetailedStackTraceRequested(GlobalParams globalParams) { + return globalParams.getErrorTrace(); + } + + /** + * Validates if error details are allowed to be shared in the response + * based on the grpc server configuration and request parameters. + * + * @param globalRequestParams The global parameters from the gRPC request + * @throws IllegalArgumentException if error tracing is requested but disabled by the server side + */ + public static void validateStackTraceDetailsConfiguration(GlobalParams globalRequestParams) { + if (detailedErrorsEnabled.get() == false && globalRequestParams.getErrorTrace()) { + throw new IllegalArgumentException("error traces in responses are disabled."); + } + } + +} diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListenerTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListenerTests.java index b235ac92c9283..6bb4667c6ed05 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListenerTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListenerTests.java @@ -22,8 +22,8 @@ import io.grpc.stub.StreamObserver; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; +import static org.opensearch.transport.grpc.proto.response.TestFixtures.FULL_STACK_TRACE_REQUESTED; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; @@ -38,7 +38,7 @@ public class BulkRequestActionListenerTests extends OpenSearchTestCase { public void setUp() throws Exception { super.setUp(); MockitoAnnotations.openMocks(this); - listener = new BulkRequestActionListener(responseObserver, new ResponseHandlingParams()); + listener = new BulkRequestActionListener(responseObserver, FULL_STACK_TRACE_REQUESTED); } public void testOnResponseWithSuccessfulResponse() { diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/listeners/SearchRequestActionListenerTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/listeners/SearchRequestActionListenerTests.java index 6d216248e18dc..fcad8461bd654 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/listeners/SearchRequestActionListenerTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/listeners/SearchRequestActionListenerTests.java @@ -10,6 +10,7 @@ import org.opensearch.action.search.SearchResponse; import org.opensearch.action.search.SearchResponseSections; import org.opensearch.action.search.ShardSearchFailure; +import org.opensearch.protobufs.GlobalParams; import org.opensearch.search.SearchHits; import org.opensearch.test.OpenSearchTestCase; @@ -17,10 +18,8 @@ import io.grpc.stub.StreamObserver; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -35,7 +34,7 @@ public class SearchRequestActionListenerTests extends OpenSearchTestCase { public void setUp() throws Exception { super.setUp(); MockitoAnnotations.openMocks(this); - listener = new SearchRequestActionListener(responseObserver, new ResponseHandlingParams()); + listener = new SearchRequestActionListener(responseObserver, GlobalParams.newBuilder().build()); } public void testOnResponse() { diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/BulkResponseProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/BulkResponseProtoUtilsTests.java index fcae5e01098d2..5d733537e1a8f 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/BulkResponseProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/BulkResponseProtoUtilsTests.java @@ -17,12 +17,13 @@ import org.opensearch.core.index.shard.ShardId; import org.opensearch.test.OpenSearchTestCase; import org.opensearch.transport.grpc.proto.response.document.bulk.BulkResponseProtoUtils; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import java.io.IOException; import io.grpc.Status; +import static org.opensearch.transport.grpc.proto.response.TestFixtures.FULL_STACK_TRACE_REQUESTED; + public class BulkResponseProtoUtilsTests extends OpenSearchTestCase { public void testToProtoWithSuccessfulResponse() throws IOException { @@ -38,7 +39,7 @@ public void testToProtoWithSuccessfulResponse() throws IOException { BulkResponse bulkResponse = new BulkResponse(responses, 100); // Convert to Protocol Buffer - org.opensearch.protobufs.BulkResponse protoResponse = BulkResponseProtoUtils.toProto(bulkResponse, new ResponseHandlingParams()); + org.opensearch.protobufs.BulkResponse protoResponse = BulkResponseProtoUtils.toProto(bulkResponse, FULL_STACK_TRACE_REQUESTED); // Verify the conversion assertEquals("Should have the correct took time", 100, protoResponse.getTook()); @@ -66,7 +67,7 @@ public void testToProtoWithFailedResponse() throws IOException { BulkResponse bulkResponse = new BulkResponse(responses, 100); // Convert to Protocol Buffer - org.opensearch.protobufs.BulkResponse protoResponse = BulkResponseProtoUtils.toProto(bulkResponse, new ResponseHandlingParams()); + org.opensearch.protobufs.BulkResponse protoResponse = BulkResponseProtoUtils.toProto(bulkResponse, FULL_STACK_TRACE_REQUESTED); // Verify the conversion assertEquals("Should have the correct took time", 100, protoResponse.getTook()); @@ -95,7 +96,7 @@ public void testToProtoWithIngestTook() throws IOException { BulkResponse bulkResponse = new BulkResponse(responses, 100, 50); // Convert to Protocol Buffer - org.opensearch.protobufs.BulkResponse protoResponse = BulkResponseProtoUtils.toProto(bulkResponse, new ResponseHandlingParams()); + org.opensearch.protobufs.BulkResponse protoResponse = BulkResponseProtoUtils.toProto(bulkResponse, FULL_STACK_TRACE_REQUESTED); // Verify the conversion assertEquals("Should have the correct took time", 100, protoResponse.getTook()); diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/TestFixtures.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/TestFixtures.java new file mode 100644 index 0000000000000..a8ca4cfd72bf4 --- /dev/null +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/TestFixtures.java @@ -0,0 +1,19 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.transport.grpc.proto.response; + +import org.opensearch.protobufs.GlobalParams; + +public final class TestFixtures { + + public static final GlobalParams FULL_STACK_TRACE_REQUESTED = GlobalParams.newBuilder().setErrorTrace(true).build(); + + public static final GlobalParams ERROR_SUMMARY_REQUESTED = GlobalParams.newBuilder().setErrorTrace(false).build(); + +} diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtilsTests.java index d1686b971aa5f..2699e0617ecc8 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtilsTests.java @@ -21,7 +21,6 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.index.get.GetResult; import org.opensearch.test.OpenSearchTestCase; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -31,6 +30,8 @@ import io.grpc.Status; +import static org.opensearch.transport.grpc.proto.response.TestFixtures.FULL_STACK_TRACE_REQUESTED; + public class BulkItemResponseProtoUtilsTests extends OpenSearchTestCase { public void testToProtoWithIndexResponse() throws IOException { @@ -48,7 +49,10 @@ public void testToProtoWithIndexResponse() throws IOException { BulkItemResponse bulkItemResponse = new BulkItemResponse(0, DocWriteRequest.OpType.INDEX, indexResponse); // Convert to protobuf ResponseItem - org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto(bulkItemResponse, new ResponseHandlingParams()); + org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto( + bulkItemResponse, + FULL_STACK_TRACE_REQUESTED + ); // Verify the result assertNotNull("ResponseItem should not be null", responseItem); @@ -73,7 +77,10 @@ public void testToProtoWithCreateResponse() throws IOException { BulkItemResponse bulkItemResponse = new BulkItemResponse(0, DocWriteRequest.OpType.CREATE, indexResponse); // Convert to protobuf ResponseItem - org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto(bulkItemResponse, new ResponseHandlingParams()); + org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto( + bulkItemResponse, + FULL_STACK_TRACE_REQUESTED + ); // Verify the result assertNotNull("ResponseItem should not be null", responseItem); @@ -98,7 +105,10 @@ public void testToProtoWithDeleteResponse() throws IOException { BulkItemResponse bulkItemResponse = new BulkItemResponse(0, DocWriteRequest.OpType.DELETE, deleteResponse); // Convert to protobuf ResponseItem - org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto(bulkItemResponse, new ResponseHandlingParams()); + org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto( + bulkItemResponse, + FULL_STACK_TRACE_REQUESTED + ); // Verify the result assertNotNull("ResponseItem should not be null", responseItem); @@ -123,7 +133,10 @@ public void testToProtoWithUpdateResponse() throws IOException { BulkItemResponse bulkItemResponse = new BulkItemResponse(0, DocWriteRequest.OpType.UPDATE, updateResponse); // Convert to protobuf Item - org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto(bulkItemResponse, new ResponseHandlingParams()); + org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto( + bulkItemResponse, + FULL_STACK_TRACE_REQUESTED + ); // Verify the result assertNotNull("ResponseItem should not be null", responseItem); @@ -166,7 +179,10 @@ public void testToProtoWithUpdateResponseAndGetResult() throws IOException { BulkItemResponse bulkItemResponse = new BulkItemResponse(0, DocWriteRequest.OpType.UPDATE, updateResponse); // Convert to protobuf Item - org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto(bulkItemResponse, new ResponseHandlingParams()); + org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto( + bulkItemResponse, + FULL_STACK_TRACE_REQUESTED + ); // Verify the result assertNotNull("ResponseItem should not be null", responseItem); @@ -196,7 +212,10 @@ public void testToProtoWithFailure() throws IOException { BulkItemResponse bulkItemResponse = new BulkItemResponse(0, DocWriteRequest.OpType.INDEX, failure); // Convert to protobuf Item - org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto(bulkItemResponse, new ResponseHandlingParams()); + org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto( + bulkItemResponse, + FULL_STACK_TRACE_REQUESTED + ); // Verify the result assertNotNull("ResponseItem should not be null", responseItem); @@ -211,6 +230,6 @@ public void testToProtoWithFailure() throws IOException { public void testToProtoWithNullResponse() throws IOException { // Call toProto with null, should throw NullPointerException - expectThrows(NullPointerException.class, () -> BulkItemResponseProtoUtils.toProto(null, new ResponseHandlingParams())); + expectThrows(NullPointerException.class, () -> BulkItemResponseProtoUtils.toProto(null, FULL_STACK_TRACE_REQUESTED)); } } diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtilsTests.java index ebe17640b5015..e852a9c85d77f 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtilsTests.java @@ -14,10 +14,11 @@ import org.opensearch.core.index.shard.ShardId; import org.opensearch.protobufs.ResponseItem; import org.opensearch.test.OpenSearchTestCase; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import java.io.IOException; +import static org.opensearch.transport.grpc.proto.response.TestFixtures.FULL_STACK_TRACE_REQUESTED; + public class DocWriteResponseProtoUtilsTests extends OpenSearchTestCase { public void testToProtoWithIndexResponse() throws IOException { @@ -33,7 +34,7 @@ public void testToProtoWithIndexResponse() throws IOException { indexResponse.setForcedRefresh(true); // Convert to protobuf ResponseItem.Builder - ResponseItem.Builder responseItemBuilder = DocWriteResponseProtoUtils.toProto(indexResponse, new ResponseHandlingParams()); + ResponseItem.Builder responseItemBuilder = DocWriteResponseProtoUtils.toProto(indexResponse, FULL_STACK_TRACE_REQUESTED); // Verify the result assertNotNull("ResponseItem.Builder should not be null", responseItemBuilder); @@ -71,7 +72,7 @@ public void testToProtoWithEmptyId() throws IOException { indexResponse.setShardInfo(shardInfo); // Convert to protobuf ResponseItem.Builder - ResponseItem.Builder responseItemBuilder = DocWriteResponseProtoUtils.toProto(indexResponse, new ResponseHandlingParams()); + ResponseItem.Builder responseItemBuilder = DocWriteResponseProtoUtils.toProto(indexResponse, FULL_STACK_TRACE_REQUESTED); // Verify the result assertNotNull("ResponseItem.Builder should not be null", responseItemBuilder); @@ -95,7 +96,7 @@ public void testToProtoWithNoSeqNo() throws IOException { indexResponse.setShardInfo(shardInfo); // Convert to protobuf ResponseItem.Builder - ResponseItem.Builder responseItemBuilder = DocWriteResponseProtoUtils.toProto(indexResponse, new ResponseHandlingParams()); + ResponseItem.Builder responseItemBuilder = DocWriteResponseProtoUtils.toProto(indexResponse, FULL_STACK_TRACE_REQUESTED); // Verify the result assertNotNull("ResponseItem.Builder should not be null", responseItemBuilder); @@ -110,6 +111,6 @@ public void testToProtoWithNoSeqNo() throws IOException { public void testToProtoWithNullResponse() throws IOException { // Call toProto with null, should throw NullPointerException - expectThrows(NullPointerException.class, () -> DocWriteResponseProtoUtils.toProto(null, new ResponseHandlingParams())); + expectThrows(NullPointerException.class, () -> DocWriteResponseProtoUtils.toProto(null, FULL_STACK_TRACE_REQUESTED)); } } diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtilsTests.java index 88679d76726d7..619a83c48acec 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtilsTests.java @@ -14,12 +14,13 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.protobufs.ShardInfo; import org.opensearch.test.OpenSearchTestCase; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import static org.opensearch.transport.grpc.proto.response.TestFixtures.FULL_STACK_TRACE_REQUESTED; + public class ShardInfoProtoUtilsTests extends OpenSearchTestCase { public void testToProtoWithNoFailures() throws IOException { @@ -27,7 +28,7 @@ public void testToProtoWithNoFailures() throws IOException { ReplicationResponse.ShardInfo shardInfo = new ReplicationResponse.ShardInfo(5, 3, new ReplicationResponse.ShardInfo.Failure[0]); // Convert to protobuf ShardInfo - ShardInfo protoShardInfo = ShardInfoProtoUtils.toProto(shardInfo, new ResponseHandlingParams()); + ShardInfo protoShardInfo = ShardInfoProtoUtils.toProto(shardInfo, FULL_STACK_TRACE_REQUESTED); // Verify the result assertNotNull("ShardInfo should not be null", protoShardInfo); @@ -56,7 +57,7 @@ public void testToProtoWithFailures() throws IOException { ReplicationResponse.ShardInfo shardInfo = new ReplicationResponse.ShardInfo(5, 3, failures); // Convert to protobuf ShardInfo - ShardInfo protoShardInfo = ShardInfoProtoUtils.toProto(shardInfo, new ResponseHandlingParams()); + ShardInfo protoShardInfo = ShardInfoProtoUtils.toProto(shardInfo, FULL_STACK_TRACE_REQUESTED); // Verify the result assertNotNull("ShardInfo should not be null", protoShardInfo); @@ -88,6 +89,6 @@ public void testToProtoWithFailures() throws IOException { public void testToProtoWithNullShardInfo() throws IOException { // Call toProto with null, should throw NullPointerException - expectThrows(NullPointerException.class, () -> ShardInfoProtoUtils.toProto(null, new ResponseHandlingParams())); + expectThrows(NullPointerException.class, () -> ShardInfoProtoUtils.toProto(null, FULL_STACK_TRACE_REQUESTED)); } } diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/OpenSearchExceptionProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/OpenSearchExceptionProtoUtilsTests.java index f1997dccedcc5..64ac6372c88cb 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/OpenSearchExceptionProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/OpenSearchExceptionProtoUtilsTests.java @@ -17,14 +17,12 @@ import org.opensearch.core.common.ParsingException; import org.opensearch.core.common.breaker.CircuitBreakingException; import org.opensearch.protobufs.ErrorCause; -import org.opensearch.protobufs.GlobalParams; import org.opensearch.protobufs.ObjectMap; import org.opensearch.protobufs.StringOrStringArray; import org.opensearch.script.ScriptException; import org.opensearch.search.SearchParseException; import org.opensearch.search.aggregations.MultiBucketConsumerService; import org.opensearch.test.OpenSearchTestCase; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import org.opensearch.transport.grpc.proto.response.exceptions.opensearchexception.OpenSearchExceptionProtoUtils; import java.io.IOException; @@ -33,21 +31,20 @@ import java.util.List; import java.util.Map; +import static org.opensearch.transport.grpc.proto.response.TestFixtures.ERROR_SUMMARY_REQUESTED; +import static org.opensearch.transport.grpc.proto.response.TestFixtures.FULL_STACK_TRACE_REQUESTED; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class OpenSearchExceptionProtoUtilsTests extends OpenSearchTestCase { private static final String TEST_NODE_ID = "test_node_id"; - private final ResponseHandlingParams detailedErrorsEnabled = new ResponseHandlingParams(true, GlobalParams.newBuilder().setErrorTrace(true).build()); - private final ResponseHandlingParams errorsSummaryEnabled = new ResponseHandlingParams(); - public void testToProtoWithOpenSearchException() throws IOException { // Create an OpenSearchException OpenSearchException exception = new OpenSearchException("Test exception"); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.toProto(exception, detailedErrorsEnabled); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.toProto(exception, FULL_STACK_TRACE_REQUESTED); // Verify the conversion // The actual type format uses underscores instead of dots @@ -63,7 +60,7 @@ public void testToProtoWithOpenSearchExceptionSummary() throws IOException { OpenSearchException exception = new OpenSearchException("Test exception"); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.toProto(exception, errorsSummaryEnabled); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.toProto(exception, ERROR_SUMMARY_REQUESTED); // Verify the conversion // The actual type format uses underscores instead of dots @@ -78,7 +75,7 @@ public void testToProtoWithNestedOpenSearchException() throws IOException { OpenSearchException exception = new OpenSearchException("Test exception", cause); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.toProto(exception, detailedErrorsEnabled); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.toProto(exception, FULL_STACK_TRACE_REQUESTED); // Verify the conversion // The actual type format uses underscores instead of dots @@ -101,7 +98,7 @@ public void testToProtoWithNestedOpenSearchExceptionSummary() throws IOException OpenSearchException exception = new OpenSearchException("Test exception", cause); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.toProto(exception, errorsSummaryEnabled); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.toProto(exception, ERROR_SUMMARY_REQUESTED); // Verify the conversion // The actual type format uses underscores instead of dots @@ -123,7 +120,7 @@ public void testGenerateThrowableProtoWithOpenSearchException() throws IOExcepti OpenSearchException exception = new OpenSearchException("Test exception"); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, new ResponseHandlingParams()); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, FULL_STACK_TRACE_REQUESTED); // Verify the conversion // The actual type format uses underscores instead of dots @@ -136,7 +133,7 @@ public void testGenerateThrowableProtoWithIOException() throws IOException { IOException exception = new IOException("Test IO exception"); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, new ResponseHandlingParams()); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, FULL_STACK_TRACE_REQUESTED); // Verify the conversion // The actual type format uses underscores instead of dots @@ -149,7 +146,7 @@ public void testGenerateThrowableProtoWithRuntimeException() throws IOException RuntimeException exception = new RuntimeException("Test runtime exception"); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, new ResponseHandlingParams()); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, FULL_STACK_TRACE_REQUESTED); // Verify the conversion // The actual type format uses underscores instead of dots @@ -162,7 +159,7 @@ public void testGenerateThrowableProtoWithNullMessage() throws IOException { RuntimeException exception = new RuntimeException((String) null); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, new ResponseHandlingParams()); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, FULL_STACK_TRACE_REQUESTED); // Verify the conversion // The actual type format uses underscores instead of dots @@ -176,7 +173,7 @@ public void testGenerateThrowableProtoWithSuppressedExceptions() throws IOExcept exception.addSuppressed(new IllegalArgumentException("Suppressed exception")); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, errorsSummaryEnabled); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, ERROR_SUMMARY_REQUESTED); // Verify the conversion // The actual type format uses underscores instead of dots @@ -196,7 +193,7 @@ public void testInnerToProtoWithBasicException() throws IOException { RuntimeException exception = new RuntimeException("Test exception"); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, detailedErrorsEnabled); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, FULL_STACK_TRACE_REQUESTED); // Verify the conversion // The actual type format uses underscores instead of dots @@ -210,7 +207,7 @@ public void testInnerToProtoReturnsOnlyBasicExceptionSummary() throws IOExceptio RuntimeException exception = new RuntimeException("Test exception"); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, errorsSummaryEnabled); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, ERROR_SUMMARY_REQUESTED); // Verify the conversion // The actual type format uses underscores instead of dots diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtilsTests.java index 0a477e0b3209e..1ecb90e26b6a8 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtilsTests.java @@ -15,10 +15,11 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.protobufs.ShardFailure; import org.opensearch.test.OpenSearchTestCase; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import java.io.IOException; +import static org.opensearch.transport.grpc.proto.response.TestFixtures.FULL_STACK_TRACE_REQUESTED; + public class DefaultShardOperationFailedExceptionProtoUtilsTests extends OpenSearchTestCase { public void testToProtoWithDefaultShardOperationFailedException() throws IOException { @@ -30,7 +31,7 @@ public void testToProtoWithDefaultShardOperationFailedException() throws IOExcep ); // Call the method under test - ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception, new ResponseHandlingParams()); + ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception, FULL_STACK_TRACE_REQUESTED); // Verify the result assertNotNull("ShardFailure should not be null", shardFailure); @@ -50,7 +51,7 @@ public void testToProtoWithAddIndexBlockResponseFailure() throws IOException { ); // Call the method under test - ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception, new ResponseHandlingParams()); + ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception, FULL_STACK_TRACE_REQUESTED); // Verify the result assertNotNull("ShardFailure should not be null", shardFailure); @@ -71,7 +72,7 @@ public void testToProtoWithIndicesShardStoresResponseFailure() throws IOExceptio ); // Call the method under test - ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception, new ResponseHandlingParams()); + ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception, FULL_STACK_TRACE_REQUESTED); // Verify the result assertNotNull("ShardFailure should not be null", shardFailure); @@ -92,7 +93,7 @@ public void testToProtoWithCloseIndexResponseFailure() throws IOException { ); // Call the method under test - ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception, new ResponseHandlingParams()); + ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception, FULL_STACK_TRACE_REQUESTED); // Verify the result assertNotNull("ShardFailure should not be null", shardFailure); @@ -113,7 +114,7 @@ public void testToProtoWithNullNodeId() throws IOException { ); // Call the method under test - ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception, new ResponseHandlingParams()); + ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception, FULL_STACK_TRACE_REQUESTED); // Verify the result assertNotNull("ShardFailure should not be null", shardFailure); diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtilsTests.java index 0c7e2256574ac..31b766fb2a767 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtilsTests.java @@ -18,10 +18,10 @@ import org.opensearch.search.SearchShardTarget; import org.opensearch.snapshots.SnapshotShardFailure; import org.opensearch.test.OpenSearchTestCase; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import java.io.IOException; +import static org.opensearch.transport.grpc.proto.response.TestFixtures.FULL_STACK_TRACE_REQUESTED; import static org.mockito.Mockito.mock; public class ShardOperationFailedExceptionProtoUtilsTests extends OpenSearchTestCase { @@ -36,7 +36,7 @@ public void testToProtoWithShardSearchFailure() throws IOException { ShardSearchFailure shardSearchFailure = new ShardSearchFailure(new Exception("fake exception"), searchShardTarget); // Call the method under test - ShardFailure protoFailure = ShardOperationFailedExceptionProtoUtils.toProto(shardSearchFailure, new ResponseHandlingParams()); + ShardFailure protoFailure = ShardOperationFailedExceptionProtoUtils.toProto(shardSearchFailure, FULL_STACK_TRACE_REQUESTED); // Verify the result assertNotNull("Proto failure should not be null", protoFailure); @@ -54,7 +54,7 @@ public void testToProtoWithSnapshotShardFailure() throws IOException { SnapshotShardFailure shardSearchFailure = new SnapshotShardFailure("test_node", shardId, "Snapshot failed"); // Call the method under test - ShardFailure protoFailure = ShardOperationFailedExceptionProtoUtils.toProto(shardSearchFailure, new ResponseHandlingParams()); + ShardFailure protoFailure = ShardOperationFailedExceptionProtoUtils.toProto(shardSearchFailure, FULL_STACK_TRACE_REQUESTED); // Verify the result assertNotNull("Proto failure should not be null", protoFailure); @@ -73,7 +73,10 @@ public void testToProtoWithDefaultShardOperationFailedException() throws IOExcep ); // Call the method under test - ShardFailure protoFailure = ShardOperationFailedExceptionProtoUtils.toProto(defaultShardOperationFailedException, new ResponseHandlingParams()); + ShardFailure protoFailure = ShardOperationFailedExceptionProtoUtils.toProto( + defaultShardOperationFailedException, + FULL_STACK_TRACE_REQUESTED + ); // Verify the result assertNotNull("Proto failure should not be null", protoFailure); @@ -94,7 +97,7 @@ public void testToProtoWithReplicationResponseShardInfoFailure() throws IOExcept ); // Call the method under test - ShardFailure protoFailure = ShardOperationFailedExceptionProtoUtils.toProto(replicationResponseFailure, new ResponseHandlingParams()); + ShardFailure protoFailure = ShardOperationFailedExceptionProtoUtils.toProto(replicationResponseFailure, FULL_STACK_TRACE_REQUESTED); // Verify the result assertNotNull("Proto failure should not be null", protoFailure); @@ -112,7 +115,7 @@ public void testToProtoWithUnsupportedShardOperationFailedException() { // Call the method under test, should throw UnsupportedOperationException UnsupportedOperationException exception = expectThrows( UnsupportedOperationException.class, - () -> ShardOperationFailedExceptionProtoUtils.toProto(mockFailure, new ResponseHandlingParams()) + () -> ShardOperationFailedExceptionProtoUtils.toProto(mockFailure, FULL_STACK_TRACE_REQUESTED) ); assertTrue( diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtilsTests.java index fe29810fdb445..cf2f951407780 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtilsTests.java @@ -16,12 +16,12 @@ import org.opensearch.protobufs.PhaseTook; import org.opensearch.search.SearchHits; import org.opensearch.test.OpenSearchTestCase; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import java.io.IOException; import java.util.HashMap; import java.util.Map; +import static org.opensearch.transport.grpc.proto.response.TestFixtures.FULL_STACK_TRACE_REQUESTED; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -42,7 +42,7 @@ public void testToProtoWithBasicResponse() throws IOException { when(mockResponse.getInternalResponse()).thenReturn(mock(SearchResponseSections.class)); // Call the method under test - org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, new ResponseHandlingParams()); + org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, FULL_STACK_TRACE_REQUESTED); // Verify the result assertNotNull("Proto response should not be null", protoResponse); @@ -70,7 +70,7 @@ public void testToProtoWithScrollId() throws IOException { when(mockResponse.getInternalResponse()).thenReturn(mock(SearchResponseSections.class)); // Call the method under test - org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, new ResponseHandlingParams()); + org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, FULL_STACK_TRACE_REQUESTED); // Verify the result assertNotNull("Proto response should not be null", protoResponse); @@ -93,7 +93,7 @@ public void testToProtoWithPointInTimeId() throws IOException { when(mockResponse.getInternalResponse()).thenReturn(mock(SearchResponseSections.class)); // Call the method under test - org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, new ResponseHandlingParams()); + org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, FULL_STACK_TRACE_REQUESTED); // Verify the result assertNotNull("Proto response should not be null", protoResponse); @@ -127,7 +127,7 @@ public void testToProtoWithPhaseTook() throws IOException { when(mockResponse.getInternalResponse()).thenReturn(mock(SearchResponseSections.class)); // Call the method under test - org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, new ResponseHandlingParams()); + org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, FULL_STACK_TRACE_REQUESTED); // Verify the result assertNotNull("Proto response should not be null", protoResponse); @@ -156,7 +156,7 @@ public void testToProtoWithTerminatedEarly() throws IOException { when(mockResponse.getInternalResponse()).thenReturn(mock(SearchResponseSections.class)); // Call the method under test - org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, new ResponseHandlingParams()); + org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, FULL_STACK_TRACE_REQUESTED); // Verify the result assertNotNull("Proto response should not be null", protoResponse); @@ -179,7 +179,7 @@ public void testToProtoWithNumReducePhases() throws IOException { when(mockResponse.getInternalResponse()).thenReturn(mock(SearchResponseSections.class)); // Call the method under test - org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, new ResponseHandlingParams()); + org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, FULL_STACK_TRACE_REQUESTED); // Verify the result assertNotNull("Proto response should not be null", protoResponse); @@ -201,7 +201,7 @@ public void testToProtoWithClusters() throws IOException { when(mockResponse.getInternalResponse()).thenReturn(mock(SearchResponseSections.class)); // Call the method under test - org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, new ResponseHandlingParams()); + org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, FULL_STACK_TRACE_REQUESTED); // Verify the result assertNotNull("Proto response should not be null", protoResponse); diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/SearchServiceImplTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/SearchServiceImplTests.java index b79f2d9c6d3bc..f9fa5f966b065 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/SearchServiceImplTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/SearchServiceImplTests.java @@ -8,12 +8,16 @@ package org.opensearch.transport.grpc.services; +import org.opensearch.common.settings.Settings; import org.opensearch.protobufs.SearchRequest; import org.opensearch.protobufs.SearchRequestBody; import org.opensearch.test.OpenSearchTestCase; import org.opensearch.transport.client.node.NodeClient; +import org.opensearch.transport.grpc.Netty4GrpcServerTransport; import org.opensearch.transport.grpc.proto.request.search.query.AbstractQueryBuilderProtoUtils; import org.opensearch.transport.grpc.proto.request.search.query.QueryBuilderProtoTestUtils; +import org.opensearch.transport.grpc.util.GrpcParamsHandler; +import org.junit.After; import org.junit.Before; import java.io.IOException; @@ -42,22 +46,25 @@ public class SearchServiceImplTests extends OpenSearchTestCase { public void setup() throws IOException { MockitoAnnotations.openMocks(this); queryUtils = QueryBuilderProtoTestUtils.createQueryUtils(); - service = new SearchServiceImpl(client, queryUtils, true); + service = new SearchServiceImpl(client, queryUtils); + GrpcParamsHandler.initialize(settingsWithGivenStackTraceConfig(true)); + } + + @After + public void resetStackTraceSettings() { + GrpcParamsHandler.initialize(settingsWithGivenStackTraceConfig(true)); } public void testConstructorWithNullClient() { // Test that constructor throws IllegalArgumentException when client is null - IllegalArgumentException exception = expectThrows( - IllegalArgumentException.class, - () -> new SearchServiceImpl(null, queryUtils, true) - ); + IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () -> new SearchServiceImpl(null, queryUtils)); assertEquals("Client cannot be null", exception.getMessage()); } public void testConstructorWithNullQueryUtils() { // Test that constructor throws IllegalArgumentException when queryUtils is null - IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () -> new SearchServiceImpl(client, null, true)); + IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () -> new SearchServiceImpl(client, null)); assertEquals("Query utils cannot be null", exception.getMessage()); } @@ -65,7 +72,7 @@ public void testConstructorWithNullQueryUtils() { public void testConstructorWithBothNull() { // Test that constructor throws IllegalArgumentException when both parameters are null // Should fail on the first null check (client) - IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () -> new SearchServiceImpl(null, null, true)); + IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () -> new SearchServiceImpl(null, null)); assertEquals("Client cannot be null", exception.getMessage()); } @@ -98,10 +105,14 @@ public void testSearchWithException() { public void testErrorTracingConfigValidationFailsWhenServerSettingIsDisabledAndRequestRequiresTracing() { // Setup request and the service, server setting is off and request requires tracing SearchRequest request = createTestSearchRequest(); - SearchServiceImpl serviceWithDisabledErrorsTracing = new SearchServiceImpl(client, queryUtils, false); + GrpcParamsHandler.initialize(settingsWithGivenStackTraceConfig(false)); + SearchServiceImpl serviceThatFailsToProvideErrorInfo = new SearchServiceImpl(client, queryUtils); // Call search method - expectThrows(IllegalArgumentException.class, () -> serviceWithDisabledErrorsTracing.search(request, responseObserver)); + serviceThatFailsToProvideErrorInfo.search(request, responseObserver); + + // Verify that responseObserver.onError reports request parameter must be disabled + verify(responseObserver).onError(any(StatusRuntimeException.class)); } public void testErrorTracingConfigValidationPassesWhenServerSettingIsDisabledAndRequestSkipsTracing() { @@ -109,10 +120,11 @@ public void testErrorTracingConfigValidationPassesWhenServerSettingIsDisabledAnd SearchRequest request = createTestSearchRequest().toBuilder() .setGlobalParams(org.opensearch.protobufs.GlobalParams.newBuilder().setErrorTrace(false)) .build(); - SearchServiceImpl serviceWithDisabledErrorsTracing = new SearchServiceImpl(client, queryUtils, false); + GrpcParamsHandler.initialize(settingsWithGivenStackTraceConfig(false)); + SearchServiceImpl serviceThatFailsToProvideErrorInfo = new SearchServiceImpl(client, queryUtils); // Call search method - serviceWithDisabledErrorsTracing.search(request, responseObserver); + serviceThatFailsToProvideErrorInfo.search(request, responseObserver); // Verify that client.search was called verify(client).search(any(org.opensearch.action.search.SearchRequest.class), any()); @@ -125,4 +137,8 @@ private SearchRequest createTestSearchRequest() { .setGlobalParams(org.opensearch.protobufs.GlobalParams.newBuilder().setErrorTrace(true).build()) .build(); } + + private Settings settingsWithGivenStackTraceConfig(boolean stackTracesEnabled) { + return Settings.builder().put(Netty4GrpcServerTransport.SETTING_GRPC_DETAILED_ERRORS_ENABLED.getKey(), stackTracesEnabled).build(); + } } diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java index a9258f2d364aa..0f05cac92dfc5 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java @@ -9,12 +9,16 @@ package org.opensearch.transport.grpc.services.document; import com.google.protobuf.ByteString; +import org.opensearch.common.settings.Settings; import org.opensearch.protobufs.BulkRequest; import org.opensearch.protobufs.BulkRequestBody; import org.opensearch.protobufs.IndexOperation; import org.opensearch.test.OpenSearchTestCase; import org.opensearch.transport.client.node.NodeClient; +import org.opensearch.transport.grpc.Netty4GrpcServerTransport; import org.opensearch.transport.grpc.services.DocumentServiceImpl; +import org.opensearch.transport.grpc.util.GrpcParamsHandler; +import org.junit.After; import org.junit.Before; import java.io.IOException; @@ -41,7 +45,13 @@ public class DocumentServiceImplTests extends OpenSearchTestCase { @Before public void setup() throws IOException { MockitoAnnotations.openMocks(this); - service = new DocumentServiceImpl(client, true); + service = new DocumentServiceImpl(client); + GrpcParamsHandler.initialize(settingsWithGivenStackTraceConfig(true)); + } + + @After + public void resetStackTraceSettings() { + GrpcParamsHandler.initialize(settingsWithGivenStackTraceConfig(true)); } public void testBulkSuccess() { @@ -72,10 +82,14 @@ public void testBulkError() { public void testErrorTracingConfigValidationFailsWhenServerSettingIsDisabledAndRequestRequiresTracing() { // Setup request and the service, server setting is off and request requires tracing BulkRequest request = createTestBulkRequest(); - DocumentServiceImpl serviceWithDisabledErrorsTracing = new DocumentServiceImpl(client, false); + GrpcParamsHandler.initialize(settingsWithGivenStackTraceConfig(false)); + DocumentServiceImpl serviceThatFailsToProvideErrorInfo = new DocumentServiceImpl(client); // Call bulk method - expectThrows(IllegalArgumentException.class, () -> serviceWithDisabledErrorsTracing.bulk(request, responseObserver)); + serviceThatFailsToProvideErrorInfo.bulk(request, responseObserver); + + // Verify that an error was sent + verify(responseObserver).onError(any(StatusRuntimeException.class)); } public void testErrorTracingConfigValidationPassesWhenServerSettingIsDisabledAndRequestSkipsTracing() { @@ -83,10 +97,11 @@ public void testErrorTracingConfigValidationPassesWhenServerSettingIsDisabledAnd BulkRequest request = createTestBulkRequest().toBuilder() .setGlobalParams(org.opensearch.protobufs.GlobalParams.newBuilder().setErrorTrace(false)) .build(); - DocumentServiceImpl serviceWithDisabledErrorsTracing = new DocumentServiceImpl(client, false); + GrpcParamsHandler.initialize(settingsWithGivenStackTraceConfig(false)); + DocumentServiceImpl serviceThatFailsToProvideErrorInfo = new DocumentServiceImpl(client); // Call bulk method - serviceWithDisabledErrorsTracing.bulk(request, responseObserver); + serviceThatFailsToProvideErrorInfo.bulk(request, responseObserver); // Verify that client.bulk was called verify(client).bulk(any(org.opensearch.action.bulk.BulkRequest.class), any()); @@ -101,8 +116,12 @@ private BulkRequest createTestBulkRequest() { .build(); return BulkRequest.newBuilder() - .addBulkRequestBody(requestBody) - .setGlobalParams(org.opensearch.protobufs.GlobalParams.newBuilder().setErrorTrace(true)) - .build(); + .addBulkRequestBody(requestBody) + .setGlobalParams(org.opensearch.protobufs.GlobalParams.newBuilder().setErrorTrace(true)) + .build(); + } + + private Settings settingsWithGivenStackTraceConfig(boolean stackTracesEnabled) { + return Settings.builder().put(Netty4GrpcServerTransport.SETTING_GRPC_DETAILED_ERRORS_ENABLED.getKey(), stackTracesEnabled).build(); } } diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcErrorHandlerTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcErrorHandlerTests.java index 449d2202a2820..09b0c47bfd09f 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcErrorHandlerTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcErrorHandlerTests.java @@ -18,7 +18,6 @@ import org.opensearch.core.rest.RestStatus; import org.opensearch.protobufs.GlobalParams; import org.opensearch.test.OpenSearchTestCase; -import org.opensearch.transport.grpc.proto.response.exceptions.ResponseHandlingParams; import java.io.IOException; import java.util.concurrent.TimeoutException; @@ -33,7 +32,7 @@ */ public class GrpcErrorHandlerTests extends OpenSearchTestCase { - private final ResponseHandlingParams detailedErrorsInResponse = new ResponseHandlingParams(true, GlobalParams.newBuilder().setErrorTrace(true).build()); + private final GlobalParams detailedErrorsInResponse = GlobalParams.newBuilder().setErrorTrace(true).build(); public void testOpenSearchExceptionConversion() { OpenSearchException exception = new OpenSearchException("Test exception") { diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcParamsHandlerTest.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcParamsHandlerTest.java new file mode 100644 index 0000000000000..502bbd45b7b76 --- /dev/null +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcParamsHandlerTest.java @@ -0,0 +1,55 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + */ + +package org.opensearch.transport.grpc.util; + +import static org.opensearch.transport.grpc.proto.response.TestFixtures.ERROR_SUMMARY_REQUESTED; +import static org.opensearch.transport.grpc.proto.response.TestFixtures.FULL_STACK_TRACE_REQUESTED; + +import org.junit.After; +import org.opensearch.common.settings.Settings; +import org.opensearch.test.OpenSearchTestCase; +import org.opensearch.transport.grpc.Netty4GrpcServerTransport; + +public class GrpcParamsHandlerTest extends OpenSearchTestCase { + + @After + public void resetStackTraceSettings() { + GrpcParamsHandler.initialize(settingsWithGivenStackTraceConfig(true)); + } + + public void testValidationFailsWhenDetailedErrorsDisabledAndClientRequestedStackTrace() { + GrpcParamsHandler.initialize(settingsWithGivenStackTraceConfig(false)); + + IllegalArgumentException exception = expectThrows( + IllegalArgumentException.class, + () -> GrpcParamsHandler.validateStackTraceDetailsConfiguration(FULL_STACK_TRACE_REQUESTED) + ); + assertEquals("error traces in responses are disabled.", exception.getMessage()); + } + + public void testValidationPassesWhenDetailedErrorsDisabledAndClientDoesNotRequestStackTrace() { + GrpcParamsHandler.initialize(settingsWithGivenStackTraceConfig(false)); + + try { + GrpcParamsHandler.validateStackTraceDetailsConfiguration(ERROR_SUMMARY_REQUESTED); + } catch (Exception e) { + fail("Validation should pass without exceptions when stack traces are not requested."); + } + } + + public void testGrpcParamsHandlerPicksErrorTraceRequestParameter() { + assertTrue("Params handler must directly pick error_trace=true", GrpcParamsHandler.isDetailedStackTraceRequested(FULL_STACK_TRACE_REQUESTED)); + assertFalse("Params handler must directly pick error_trace=false", GrpcParamsHandler.isDetailedStackTraceRequested(ERROR_SUMMARY_REQUESTED)); + } + + private Settings settingsWithGivenStackTraceConfig(boolean stackTracesEnabled) { + return Settings.builder().put(Netty4GrpcServerTransport.SETTING_GRPC_DETAILED_ERRORS_ENABLED.getKey(), stackTracesEnabled).build(); + } + +} From c4f605b5be349f7d7a9454670532dad9c487b1c7 Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Wed, 5 Nov 2025 15:14:23 +0100 Subject: [PATCH 10/28] Polishing Signed-off-by: Sergei Ustimenko --- .../transport/grpc/util/GrpcErrorHandler.java | 32 +++++++++++-------- .../grpc/services/SearchServiceImplTests.java | 8 ++--- .../document/DocumentServiceImplTests.java | 8 ++--- .../grpc/util/GrpcParamsHandlerTest.java | 18 +++++++---- 4 files changed, 39 insertions(+), 27 deletions(-) diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java index 79a950d94ddf3..822bb691b34c5 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java @@ -60,45 +60,45 @@ public static StatusRuntimeException convertToGrpcError(Exception e, GlobalParam // ========== OpenSearch Core System Exceptions ========== // Low-level OpenSearch exceptions that don't extend OpenSearchException - include full details else if (e instanceof OpenSearchRejectedExecutionException) { - return Status.RESOURCE_EXHAUSTED.withDescription(getErrorDescriptionRespectingTracingLevel(e, shouldIncludeDetailedStackTrace)) + return Status.RESOURCE_EXHAUSTED.withDescription(getErrorDetailsForConfig(e, shouldIncludeDetailedStackTrace)) .asRuntimeException(); } else if (e instanceof NotXContentException) { - return Status.INVALID_ARGUMENT.withDescription(getErrorDescriptionRespectingTracingLevel(e, shouldIncludeDetailedStackTrace)) + return Status.INVALID_ARGUMENT.withDescription(getErrorDetailsForConfig(e, shouldIncludeDetailedStackTrace)) .asRuntimeException(); } else if (e instanceof NotCompressedException) { - return Status.INVALID_ARGUMENT.withDescription(getErrorDescriptionRespectingTracingLevel(e, shouldIncludeDetailedStackTrace)) + return Status.INVALID_ARGUMENT.withDescription(getErrorDetailsForConfig(e, shouldIncludeDetailedStackTrace)) .asRuntimeException(); } // ========== 3. Third-party Library Exceptions ========== // External library exceptions (Jackson JSON parsing) - include full details else if (e instanceof InputCoercionException) { - return Status.INVALID_ARGUMENT.withDescription(getErrorDescriptionRespectingTracingLevel(e, shouldIncludeDetailedStackTrace)) + return Status.INVALID_ARGUMENT.withDescription(getErrorDetailsForConfig(e, shouldIncludeDetailedStackTrace)) .asRuntimeException(); } else if (e instanceof JsonParseException) { - return Status.INVALID_ARGUMENT.withDescription(getErrorDescriptionRespectingTracingLevel(e, shouldIncludeDetailedStackTrace)) + return Status.INVALID_ARGUMENT.withDescription(getErrorDetailsForConfig(e, shouldIncludeDetailedStackTrace)) .asRuntimeException(); } // ========== 4. Standard Java Exceptions ========== // Generic Java runtime exceptions - include full exception details for debugging else if (e instanceof IllegalArgumentException) { - return Status.INVALID_ARGUMENT.withDescription(getErrorDescriptionRespectingTracingLevel(e, shouldIncludeDetailedStackTrace)) + return Status.INVALID_ARGUMENT.withDescription(getErrorDetailsForConfig(e, shouldIncludeDetailedStackTrace)) .asRuntimeException(); } else if (e instanceof IllegalStateException) { - return Status.FAILED_PRECONDITION.withDescription(getErrorDescriptionRespectingTracingLevel(e, shouldIncludeDetailedStackTrace)) + return Status.FAILED_PRECONDITION.withDescription(getErrorDetailsForConfig(e, shouldIncludeDetailedStackTrace)) .asRuntimeException(); } else if (e instanceof SecurityException) { - return Status.PERMISSION_DENIED.withDescription(getErrorDescriptionRespectingTracingLevel(e, shouldIncludeDetailedStackTrace)) + return Status.PERMISSION_DENIED.withDescription(getErrorDetailsForConfig(e, shouldIncludeDetailedStackTrace)) .asRuntimeException(); } else if (e instanceof TimeoutException) { - return Status.DEADLINE_EXCEEDED.withDescription(getErrorDescriptionRespectingTracingLevel(e, shouldIncludeDetailedStackTrace)) + return Status.DEADLINE_EXCEEDED.withDescription(getErrorDetailsForConfig(e, shouldIncludeDetailedStackTrace)) .asRuntimeException(); } else if (e instanceof InterruptedException) { - return Status.CANCELLED.withDescription(getErrorDescriptionRespectingTracingLevel(e, shouldIncludeDetailedStackTrace)) + return Status.CANCELLED.withDescription(getErrorDetailsForConfig(e, shouldIncludeDetailedStackTrace)) .asRuntimeException(); } else if (e instanceof IOException) { - return Status.INTERNAL.withDescription(getErrorDescriptionRespectingTracingLevel(e, shouldIncludeDetailedStackTrace)) + return Status.INTERNAL.withDescription(getErrorDetailsForConfig(e, shouldIncludeDetailedStackTrace)) .asRuntimeException(); } @@ -106,7 +106,7 @@ else if (e instanceof IllegalArgumentException) { // Safety fallback for any unexpected exception to {@code Status.INTERNAL} with full debugging info else { logger.warn("Unmapped exception type: {}, treating as INTERNAL error", e.getClass().getSimpleName()); - return Status.INTERNAL.withDescription(getErrorDescriptionRespectingTracingLevel(e, shouldIncludeDetailedStackTrace)) + return Status.INTERNAL.withDescription(getErrorDetailsForConfig(e, shouldIncludeDetailedStackTrace)) .asRuntimeException(); } } @@ -186,7 +186,13 @@ private static String enhanceDescriptionWithXContentMetadata( } } - private static String getErrorDescriptionRespectingTracingLevel(Throwable exception, boolean shouldIncludeDetailedStackTrace) { + /** + * Gets either a full stack trace of an error or just a message based on the flag that comes from the gRPC request Global Params. + * @param exception The exception to get details from + * @param shouldIncludeDetailedStackTrace Flag indicating whether to include full stack trace + * @return String with either full stack trace or just the error message + */ + private static String getErrorDetailsForConfig(Throwable exception, boolean shouldIncludeDetailedStackTrace) { return shouldIncludeDetailedStackTrace ? ExceptionsHelper.stackTrace(exception) : exception.getMessage(); } diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/SearchServiceImplTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/SearchServiceImplTests.java index f9fa5f966b065..1afd61a2b84d2 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/SearchServiceImplTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/SearchServiceImplTests.java @@ -102,8 +102,8 @@ public void testSearchWithException() { verify(responseObserver).onError(any()); } - public void testErrorTracingConfigValidationFailsWhenServerSettingIsDisabledAndRequestRequiresTracing() { - // Setup request and the service, server setting is off and request requires tracing + public void testErrorTraceConfigValidationFailsWhenServerSettingIsDisabledAndRequestRequiresStackTrace() { + // Setup request and the service, server setting is off and request requires a stack trace SearchRequest request = createTestSearchRequest(); GrpcParamsHandler.initialize(settingsWithGivenStackTraceConfig(false)); SearchServiceImpl serviceThatFailsToProvideErrorInfo = new SearchServiceImpl(client, queryUtils); @@ -115,8 +115,8 @@ public void testErrorTracingConfigValidationFailsWhenServerSettingIsDisabledAndR verify(responseObserver).onError(any(StatusRuntimeException.class)); } - public void testErrorTracingConfigValidationPassesWhenServerSettingIsDisabledAndRequestSkipsTracing() { - // Setup request and the service, server setting is off and request skips tracing + public void testErrorTraceConfigValidationPassesWhenServerSettingIsDisabledAndRequestSkipsStackTrace() { + // Setup request and the service, server setting is off and request skips a stack trace SearchRequest request = createTestSearchRequest().toBuilder() .setGlobalParams(org.opensearch.protobufs.GlobalParams.newBuilder().setErrorTrace(false)) .build(); diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java index 0f05cac92dfc5..aa92786d364bb 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java @@ -79,8 +79,8 @@ public void testBulkError() { verify(responseObserver).onError(any(RuntimeException.class)); } - public void testErrorTracingConfigValidationFailsWhenServerSettingIsDisabledAndRequestRequiresTracing() { - // Setup request and the service, server setting is off and request requires tracing + public void testErrorTraceConfigValidationFailsWhenServerSettingIsDisabledAndRequestRequiresStackTrace() { + // Setup request and the service, server setting is off and request requires a stack trace BulkRequest request = createTestBulkRequest(); GrpcParamsHandler.initialize(settingsWithGivenStackTraceConfig(false)); DocumentServiceImpl serviceThatFailsToProvideErrorInfo = new DocumentServiceImpl(client); @@ -92,8 +92,8 @@ public void testErrorTracingConfigValidationFailsWhenServerSettingIsDisabledAndR verify(responseObserver).onError(any(StatusRuntimeException.class)); } - public void testErrorTracingConfigValidationPassesWhenServerSettingIsDisabledAndRequestSkipsTracing() { - // Setup request and the service, server setting is off and request does not require tracing + public void testErrorTraceConfigValidationPassesWhenServerSettingIsDisabledAndRequestSkipsStackTrace() { + // Setup request and the service, server setting is off and request does not require a stack trace BulkRequest request = createTestBulkRequest().toBuilder() .setGlobalParams(org.opensearch.protobufs.GlobalParams.newBuilder().setErrorTrace(false)) .build(); diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcParamsHandlerTest.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcParamsHandlerTest.java index 502bbd45b7b76..314c54266c97f 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcParamsHandlerTest.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcParamsHandlerTest.java @@ -8,13 +8,13 @@ package org.opensearch.transport.grpc.util; -import static org.opensearch.transport.grpc.proto.response.TestFixtures.ERROR_SUMMARY_REQUESTED; -import static org.opensearch.transport.grpc.proto.response.TestFixtures.FULL_STACK_TRACE_REQUESTED; - -import org.junit.After; import org.opensearch.common.settings.Settings; import org.opensearch.test.OpenSearchTestCase; import org.opensearch.transport.grpc.Netty4GrpcServerTransport; +import org.junit.After; + +import static org.opensearch.transport.grpc.proto.response.TestFixtures.ERROR_SUMMARY_REQUESTED; +import static org.opensearch.transport.grpc.proto.response.TestFixtures.FULL_STACK_TRACE_REQUESTED; public class GrpcParamsHandlerTest extends OpenSearchTestCase { @@ -44,8 +44,14 @@ public void testValidationPassesWhenDetailedErrorsDisabledAndClientDoesNotReques } public void testGrpcParamsHandlerPicksErrorTraceRequestParameter() { - assertTrue("Params handler must directly pick error_trace=true", GrpcParamsHandler.isDetailedStackTraceRequested(FULL_STACK_TRACE_REQUESTED)); - assertFalse("Params handler must directly pick error_trace=false", GrpcParamsHandler.isDetailedStackTraceRequested(ERROR_SUMMARY_REQUESTED)); + assertTrue( + "Params handler must directly pick error_trace=true", + GrpcParamsHandler.isDetailedStackTraceRequested(FULL_STACK_TRACE_REQUESTED) + ); + assertFalse( + "Params handler must directly pick error_trace=false", + GrpcParamsHandler.isDetailedStackTraceRequested(ERROR_SUMMARY_REQUESTED) + ); } private Settings settingsWithGivenStackTraceConfig(boolean stackTracesEnabled) { From 80b2bd20e5fb9be7cc9b3e20a0b31204fc08f95b Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Wed, 5 Nov 2025 17:26:14 +0100 Subject: [PATCH 11/28] Polishing Signed-off-by: Sergei Ustimenko --- .../opensearch/transport/grpc/util/GrpcErrorHandler.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java index 822bb691b34c5..13a7f5a7ff676 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java @@ -95,19 +95,16 @@ else if (e instanceof IllegalArgumentException) { return Status.DEADLINE_EXCEEDED.withDescription(getErrorDetailsForConfig(e, shouldIncludeDetailedStackTrace)) .asRuntimeException(); } else if (e instanceof InterruptedException) { - return Status.CANCELLED.withDescription(getErrorDetailsForConfig(e, shouldIncludeDetailedStackTrace)) - .asRuntimeException(); + return Status.CANCELLED.withDescription(getErrorDetailsForConfig(e, shouldIncludeDetailedStackTrace)).asRuntimeException(); } else if (e instanceof IOException) { - return Status.INTERNAL.withDescription(getErrorDetailsForConfig(e, shouldIncludeDetailedStackTrace)) - .asRuntimeException(); + return Status.INTERNAL.withDescription(getErrorDetailsForConfig(e, shouldIncludeDetailedStackTrace)).asRuntimeException(); } // ========== 5. Unknown/Unmapped Exceptions ========== // Safety fallback for any unexpected exception to {@code Status.INTERNAL} with full debugging info else { logger.warn("Unmapped exception type: {}, treating as INTERNAL error", e.getClass().getSimpleName()); - return Status.INTERNAL.withDescription(getErrorDetailsForConfig(e, shouldIncludeDetailedStackTrace)) - .asRuntimeException(); + return Status.INTERNAL.withDescription(getErrorDetailsForConfig(e, shouldIncludeDetailedStackTrace)).asRuntimeException(); } } From b4f51b035fae1de090fb43a16ccc6a31bd5a9f57 Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Wed, 5 Nov 2025 22:28:42 +0100 Subject: [PATCH 12/28] Polishing Signed-off-by: Sergei Ustimenko --- .../{GrpcParamsHandlerTest.java => GrpcParamsHandlerTests.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/{GrpcParamsHandlerTest.java => GrpcParamsHandlerTests.java} (97%) diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcParamsHandlerTest.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcParamsHandlerTests.java similarity index 97% rename from modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcParamsHandlerTest.java rename to modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcParamsHandlerTests.java index 314c54266c97f..6fe7213d94ca1 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcParamsHandlerTest.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcParamsHandlerTests.java @@ -16,7 +16,7 @@ import static org.opensearch.transport.grpc.proto.response.TestFixtures.ERROR_SUMMARY_REQUESTED; import static org.opensearch.transport.grpc.proto.response.TestFixtures.FULL_STACK_TRACE_REQUESTED; -public class GrpcParamsHandlerTest extends OpenSearchTestCase { +public class GrpcParamsHandlerTests extends OpenSearchTestCase { @After public void resetStackTraceSettings() { From 0c3696fbff304669bfad4f96df0c17236f4ca8df Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Thu, 6 Nov 2025 10:19:54 +0100 Subject: [PATCH 13/28] Polish javadocs Signed-off-by: Sergei Ustimenko --- .../document/bulk/BulkItemResponseProtoUtils.java | 1 + .../response/document/bulk/BulkResponseProtoUtils.java | 1 + .../document/common/DocWriteResponseProtoUtils.java | 1 + .../response/document/common/ShardInfoProtoUtils.java | 1 + .../OpenSearchExceptionProtoUtils.java | 8 +++++++- .../DefaultShardOperationFailedExceptionProtoUtils.java | 5 +++++ .../ReplicationResponseShardInfoFailureProtoUtils.java | 1 + .../ShardOperationFailedExceptionProtoUtils.java | 1 + .../ShardSearchFailureProtoUtils.java | 1 + .../SnapshotShardFailureProtoUtils.java | 1 + .../proto/response/search/ProtoActionsProtoUtils.java | 1 + .../proto/response/search/SearchResponseProtoUtils.java | 1 + .../proto/response/search/ShardStatisticsProtoUtils.java | 1 + .../opensearch/transport/grpc/util/GrpcParamsHandler.java | 5 +++++ 14 files changed, 28 insertions(+), 1 deletion(-) diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtils.java index 4873d99a120a7..f77ebd2a7af33 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtils.java @@ -42,6 +42,7 @@ private BulkItemResponseProtoUtils() { * * * @param response The BulkItemResponse to convert + * @param params The global gRPC request parameters * @return A Protocol Buffer ResponseItem representation * @throws IOException if there's an error during conversion * diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkResponseProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkResponseProtoUtils.java index daed66f567364..8cc788901ca99 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkResponseProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkResponseProtoUtils.java @@ -31,6 +31,7 @@ private BulkResponseProtoUtils() { * This method is equivalent to {@link BulkResponse#toXContent(XContentBuilder, ToXContent.Params)} * * @param response The BulkResponse to convert + * @param params The global gRPC request parameters * @return A Protocol Buffer BulkResponse representation * @throws IOException if there's an error during conversion */ diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtils.java index 7e970344216df..7529a8a0a4427 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtils.java @@ -34,6 +34,7 @@ private DocWriteResponseProtoUtils() { * This method is equivalent to the {@link DocWriteResponse#innerToXContent(XContentBuilder, ToXContent.Params)} * * @param response The DocWriteResponse to convert + * @param params The global gRPC request parameters * @return A ResponseItem.Builder with the DocWriteResponse data * */ diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtils.java index d8419381f3b3c..57be4f19b9fc9 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtils.java @@ -31,6 +31,7 @@ private ShardInfoProtoUtils() { * Similar to {@link ReplicationResponse.ShardInfo#toXContent(XContentBuilder, ToXContent.Params)} * * @param shardInfo The shard information to convert to protobuf format + * @param params The global gRPC request parameters * @return The protobuf representation of the shard information * @throws IOException If there's an error during conversion */ diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/opensearchexception/OpenSearchExceptionProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/opensearchexception/OpenSearchExceptionProtoUtils.java index 4bc3a56987117..c7b9a5aa33253 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/opensearchexception/OpenSearchExceptionProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/opensearchexception/OpenSearchExceptionProtoUtils.java @@ -55,9 +55,11 @@ private OpenSearchExceptionProtoUtils() { /** * Converts an OpenSearchException to its Protocol Buffer representation. - * This method is equivalent to the {@link OpenSearchException#toXContent(XContentBuilder, ToXContent.Params)} + * The corresponding global gRPC request parameters are used to control whether the full stacktrace is included or only a summary. + * This method is equivalent to the {@link OpenSearchException#toXContent(XContentBuilder, ToXContent.Params)}. * * @param exception The OpenSearchException to convert + * @param params Global gRPC params to control how much details of an error should be included * @return A Protocol Buffer ErrorCause representation * @throws IOException if there's an error during conversion */ @@ -83,9 +85,11 @@ public static ErrorCause toProto(OpenSearchException exception, GlobalParams par * as Protocol Buffers. *

* This method is usually used when the {@link Throwable} is rendered as a part of another Protocol Buffer object. + * The corresponding global gRPC request parameters are used to control whether the full stacktrace is included or only a summary. * It is equivalent to the {@link OpenSearchException#generateThrowableXContent(XContentBuilder, ToXContent.Params, Throwable)} * * @param t The throwable to convert + * @param params Global gRPC params to control how much details of an error should be included * @return A Protocol Buffer ErrorCause representation * @throws IOException if there's an error during conversion */ @@ -101,6 +105,7 @@ public static ErrorCause generateThrowableProto(Throwable t, GlobalParams params /** * Inner helper method for converting a Throwable to its Protocol Buffer representation. + * The corresponding global gRPC request parameters are used to control whether the full stacktrace is included or only a summary. * This method is equivalent to the {@link OpenSearchException#innerToXContent(XContentBuilder, ToXContent.Params, Throwable, String, String, Map, Map, Throwable)}. * * @param throwable The throwable to convert @@ -109,6 +114,7 @@ public static ErrorCause generateThrowableProto(Throwable t, GlobalParams params * @param headers The exception headers * @param metadata The exception metadata * @param cause The exception cause + * @param params Global gRPC params to control how much details of an error should be included * @return A Protocol Buffer ErrorCause representation * @throws IOException if there's an error during conversion */ diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtils.java index 9cd3c2799d529..f15ebdc27e7ef 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtils.java @@ -34,6 +34,7 @@ private DefaultShardOperationFailedExceptionProtoUtils() { * This method is overridden by various exception classes, which are hardcoded here. * * @param exception The DefaultShardOperationFailedException to convert + * @param params The global gRPC request parameters * @return A Protocol Buffer Struct containing the exception metadata */ public static ShardFailure toProto(DefaultShardOperationFailedException exception, GlobalParams params) throws IOException { @@ -57,6 +58,7 @@ public static ShardFailure toProto(DefaultShardOperationFailedException exceptio * * @param shardFailureBuilder the builder to populate with failure information * @param exception The AddIndexBlockResponse.AddBlockShardResult.Failure to convert + * @param params The global gRPC request parameters * @throws IOException if there's an error during conversion */ public static void innerToProto( @@ -76,6 +78,7 @@ public static void innerToProto( * * @param shardFailureBuilder the builder to populate with failure information * @param exception The IndicesShardStoresResponse.Failure to convert + * @param params The global gRPC request parameters * @throws IOException if there's an error during conversion */ public static void innerToProto( @@ -93,6 +96,7 @@ public static void innerToProto( * * @param shardFailureBuilder the builder to populate with failure information * @param exception The CloseIndexResponse.ShardResult.Failure to convert + * @param params The global gRPC request parameters * @throws IOException if there's an error during conversion */ public static void innerToProto( @@ -112,6 +116,7 @@ public static void innerToProto( * * @param shardFailureBuilder the builder to populate with failure information * @param exception The DefaultShardOperationFailedException to convert + * @param params The global gRPC request parameters * @throws IOException if there's an error during conversion */ public static void parentInnerToProto( diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ReplicationResponseShardInfoFailureProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ReplicationResponseShardInfoFailureProtoUtils.java index 6976984141ce6..e650d31ea2b66 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ReplicationResponseShardInfoFailureProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ReplicationResponseShardInfoFailureProtoUtils.java @@ -30,6 +30,7 @@ private ReplicationResponseShardInfoFailureProtoUtils() { * This method is overridden by various exception classes, which are hardcoded here. * * @param exception The ReplicationResponse.ShardInfo.Failure to convert metadata from + * @param params The global gRPC request parameters * @return A map containing the exception's metadata as ObjectMap.Value objects */ public static ShardFailure toProto(ReplicationResponse.ShardInfo.Failure exception, GlobalParams params) throws IOException { diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtils.java index db4ca3202ef82..8cac622da67d8 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtils.java @@ -33,6 +33,7 @@ private ShardOperationFailedExceptionProtoUtils() { * This method is overridden by various exception classes, which are hardcoded here. * * @param exception The ShardOperationFailedException to convert metadata from + * @param params The global gRPC request parameters * @return ShardFailure */ public static ShardFailure toProto(ShardOperationFailedException exception, GlobalParams params) throws IOException { diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardSearchFailureProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardSearchFailureProtoUtils.java index d6bf6c8fb2dfa..f0f15ba0704a2 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardSearchFailureProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardSearchFailureProtoUtils.java @@ -30,6 +30,7 @@ private ShardSearchFailureProtoUtils() { * Similar to {@link ShardSearchFailure#toXContent(XContentBuilder, ToXContent.Params)} * * * @param exception The ShardSearchFailure to convert + * @param params The global gRPC request parameters * @return A Protocol Buffer Struct containing the exception metadata */ public static ShardFailure toProto(ShardSearchFailure exception, GlobalParams params) throws IOException { diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/SnapshotShardFailureProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/SnapshotShardFailureProtoUtils.java index b185c0b7f57c5..de7857fd578ad 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/SnapshotShardFailureProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/SnapshotShardFailureProtoUtils.java @@ -30,6 +30,7 @@ private SnapshotShardFailureProtoUtils() { * Similar to {@link SnapshotShardFailure#toXContent(XContentBuilder, ToXContent.Params)} * * * @param exception The SnapshotShardFailure to convert + * @param params The global gRPC request parameters * @return A Protocol Buffer Struct containing the exception metadata */ public static ShardFailure toProto(SnapshotShardFailure exception, GlobalParams params) throws IOException { diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/ProtoActionsProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/ProtoActionsProtoUtils.java index 76fbe79a685cf..fe54266c85b0c 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/ProtoActionsProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/ProtoActionsProtoUtils.java @@ -37,6 +37,7 @@ private ProtoActionsProtoUtils() { * @param skipped the number of skipped shards * @param failed the number of failed shards * @param shardFailures the array of shard operation failures + * @param params The global gRPC request parameters * @throws IOException if there's an error during conversion */ protected static void buildBroadcastShardsHeader( diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtils.java index 670a1b8c8445a..9c0309a69b3e9 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtils.java @@ -33,6 +33,7 @@ private SearchResponseProtoUtils() { * This method is equivalent to {@link SearchResponse#toXContent(XContentBuilder, ToXContent.Params)} * * @param response The SearchResponse to convert + * @param params The global gRPC request parameters * @return A Protocol Buffer SearchResponse representation * @throws IOException if there's an error during conversion */ diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/ShardStatisticsProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/ShardStatisticsProtoUtils.java index f295870aff4bc..a6667b84024c5 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/ShardStatisticsProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/ShardStatisticsProtoUtils.java @@ -39,6 +39,7 @@ private ShardStatisticsProtoUtils() { * @param skipped the number of skipped shards * @param failed the number of failed shards * @param shardFailures the array of shard operation failures + * @param params The global gRPC request parameters * @return A Protocol Buffer ShardStatistics representation * @throws IOException if there's an error during conversion */ diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcParamsHandler.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcParamsHandler.java index 8c4649d7bd0e9..82633ce480d17 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcParamsHandler.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcParamsHandler.java @@ -27,6 +27,11 @@ public class GrpcParamsHandler { private GrpcParamsHandler() {} + /** + * Initializes the handler with the given settings. + * + * @param settings the node settings + */ public static void initialize(Settings settings) { detailedErrorsEnabled.set(SETTING_GRPC_DETAILED_ERRORS_ENABLED.get(settings)); } From 725d80bc44a7d48e64b30f501463a91e5c1304c4 Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Thu, 6 Nov 2025 12:58:56 +0100 Subject: [PATCH 14/28] Merge latest CHANGELOG Signed-off-by: Sergei Ustimenko --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4f4e85edc9b2..a15b968e53262 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Add pluggable gRPC interceptors with explicit ordering([#19005](https://github.com/opensearch-project/OpenSearch/pull/19005)) - Add BindableServices extension point to transport-grpc-spi ([#19304](https://github.com/opensearch-project/OpenSearch/pull/19304)) - Add metrics for the merged segment warmer feature ([#18929](https://github.com/opensearch-project/OpenSearch/pull/18929)) -- Add separate grpc.detailed_errors.enabled error handling setting for gRPC ([#19644](https://github.com/opensearch-project/OpenSearch/pull/19644)) +- Add handling for the global gRPC error_trace parameter ([#19644](https://github.com/opensearch-project/OpenSearch/pull/19644)) - Handle deleted documents for filter rewrite subaggregation optimization ([#19643](https://github.com/opensearch-project/OpenSearch/pull/19643)) - Add pointer based lag metric in pull-based ingestion ([#19635](https://github.com/opensearch-project/OpenSearch/pull/19635)) - Introduced internal API for retrieving metadata about requested indices from transport actions ([#18523](https://github.com/opensearch-project/OpenSearch/pull/18523)) From 3f5228164e36f8dba109529d8ceaaeb45c1b13c2 Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Thu, 6 Nov 2025 14:34:54 +0100 Subject: [PATCH 15/28] trigger CI Signed-off-by: Sergei Ustimenko From e2b0a5ff6cf3f82fc024d17b02d72140a5a0483a Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Fri, 7 Nov 2025 12:06:52 +0100 Subject: [PATCH 16/28] Make sure error details are included in regular errors Signed-off-by: Sergei Ustimenko --- .../transport/grpc/util/GrpcErrorHandler.java | 10 +- .../grpc/util/GrpcParamsHandler.java | 18 +++ .../{proto/response => }/TestFixtures.java | 7 +- .../BulkRequestActionListenerTests.java | 2 +- .../response/BulkResponseProtoUtilsTests.java | 2 +- .../bulk/BulkItemResponseProtoUtilsTests.java | 2 +- .../DocWriteResponseProtoUtilsTests.java | 2 +- .../common/ShardInfoProtoUtilsTests.java | 2 +- .../OpenSearchExceptionProtoUtilsTests.java | 4 +- ...erationFailedExceptionProtoUtilsTests.java | 2 +- ...erationFailedExceptionProtoUtilsTests.java | 2 +- .../search/SearchResponseProtoUtilsTests.java | 2 +- .../grpc/services/SearchServiceImplTests.java | 7 +- .../document/DocumentServiceImplTests.java | 7 +- .../grpc/util/GrpcErrorHandlerTests.java | 114 ++++++++++++++---- .../grpc/util/GrpcParamsHandlerTests.java | 11 +- 16 files changed, 135 insertions(+), 59 deletions(-) rename modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/{proto/response => }/TestFixtures.java (62%) diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java index 13a7f5a7ff676..20ec8cc415d0d 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java @@ -24,6 +24,7 @@ import org.opensearch.protobufs.GlobalParams; import java.io.IOException; +import java.util.Map; import java.util.concurrent.TimeoutException; import io.grpc.Status; @@ -35,6 +36,10 @@ public class GrpcErrorHandler { private static final Logger logger = LogManager.getLogger(GrpcErrorHandler.class); + private static final ToXContent.MapParams INCLUDE_STACK_TRACES = new ToXContent.MapParams( + Map.of(OpenSearchException.REST_EXCEPTION_SKIP_STACK_TRACE, "false") + ); + private GrpcErrorHandler() { // Utility class, no instances } @@ -153,11 +158,12 @@ private static String enhanceDescriptionWithXContentMetadata( // Use the same method as HTTP REST responses (BytesRestResponse.build) // This includes root_cause analysis, just like HTTP + ToXContent.Params params = shouldIncludeDetailedStackTrace ? INCLUDE_STACK_TRACES : ToXContent.EMPTY_PARAMS; OpenSearchException.generateFailureXContent( builder, - ToXContent.EMPTY_PARAMS, + params, (Exception) exception, - shouldIncludeDetailedStackTrace + GrpcParamsHandler.isDetailedErrorsEnabled() ); // Add status field like HTTP does diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcParamsHandler.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcParamsHandler.java index 82633ce480d17..77f16f5961889 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcParamsHandler.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcParamsHandler.java @@ -9,7 +9,12 @@ package org.opensearch.transport.grpc.util; import org.opensearch.common.settings.Settings; +import org.opensearch.common.util.concurrent.ThreadContext; import org.opensearch.protobufs.GlobalParams; +import org.opensearch.rest.AbstractRestChannel; +import org.opensearch.rest.RestChannel; +import org.opensearch.rest.RestController; +import org.opensearch.rest.RestRequest; import java.util.concurrent.atomic.AtomicBoolean; @@ -17,6 +22,10 @@ /** * Central utility class to handle how global gRPC request parameters are handled. + * Handling of the server side {@code detailedErrorsEnabled} and the fail-fast behaviour + * in case of faulty configuration is aligned with the + * {@link RestController#tryAllHandlers(RestRequest, RestChannel, ThreadContext)} and the + * {@link AbstractRestChannel}. */ public class GrpcParamsHandler { @@ -48,6 +57,15 @@ public static boolean isDetailedStackTraceRequested(GlobalParams globalParams) { return globalParams.getErrorTrace(); } + /** + * Checks if detailed errors are enabled on the gRPC server. + * + * @return true if detailed errors are enabled, false otherwise + */ + public static boolean isDetailedErrorsEnabled() { + return detailedErrorsEnabled.get(); + } + /** * Validates if error details are allowed to be shared in the response * based on the grpc server configuration and request parameters. diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/TestFixtures.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/TestFixtures.java similarity index 62% rename from modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/TestFixtures.java rename to modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/TestFixtures.java index a8ca4cfd72bf4..70dd06ba482e8 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/TestFixtures.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/TestFixtures.java @@ -6,8 +6,9 @@ * compatible open source license. */ -package org.opensearch.transport.grpc.proto.response; +package org.opensearch.transport.grpc; +import org.opensearch.common.settings.Settings; import org.opensearch.protobufs.GlobalParams; public final class TestFixtures { @@ -16,4 +17,8 @@ public final class TestFixtures { public static final GlobalParams ERROR_SUMMARY_REQUESTED = GlobalParams.newBuilder().setErrorTrace(false).build(); + public static Settings settingsWithGivenStackTraceConfig(boolean stackTracesEnabled) { + return Settings.builder().put(Netty4GrpcServerTransport.SETTING_GRPC_DETAILED_ERRORS_ENABLED.getKey(), stackTracesEnabled).build(); + } + } diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListenerTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListenerTests.java index 6bb4667c6ed05..18133143498a8 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListenerTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListenerTests.java @@ -23,7 +23,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import static org.opensearch.transport.grpc.proto.response.TestFixtures.FULL_STACK_TRACE_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.FULL_STACK_TRACE_REQUESTED; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/BulkResponseProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/BulkResponseProtoUtilsTests.java index 5d733537e1a8f..8f545a62ed898 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/BulkResponseProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/BulkResponseProtoUtilsTests.java @@ -22,7 +22,7 @@ import io.grpc.Status; -import static org.opensearch.transport.grpc.proto.response.TestFixtures.FULL_STACK_TRACE_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.FULL_STACK_TRACE_REQUESTED; public class BulkResponseProtoUtilsTests extends OpenSearchTestCase { diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtilsTests.java index 2699e0617ecc8..949bcc4166bdd 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtilsTests.java @@ -30,7 +30,7 @@ import io.grpc.Status; -import static org.opensearch.transport.grpc.proto.response.TestFixtures.FULL_STACK_TRACE_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.FULL_STACK_TRACE_REQUESTED; public class BulkItemResponseProtoUtilsTests extends OpenSearchTestCase { diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtilsTests.java index e852a9c85d77f..7a480c1527585 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtilsTests.java @@ -17,7 +17,7 @@ import java.io.IOException; -import static org.opensearch.transport.grpc.proto.response.TestFixtures.FULL_STACK_TRACE_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.FULL_STACK_TRACE_REQUESTED; public class DocWriteResponseProtoUtilsTests extends OpenSearchTestCase { diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtilsTests.java index 619a83c48acec..d0eb6d2d07c3e 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtilsTests.java @@ -19,7 +19,7 @@ import java.util.ArrayList; import java.util.List; -import static org.opensearch.transport.grpc.proto.response.TestFixtures.FULL_STACK_TRACE_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.FULL_STACK_TRACE_REQUESTED; public class ShardInfoProtoUtilsTests extends OpenSearchTestCase { diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/OpenSearchExceptionProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/OpenSearchExceptionProtoUtilsTests.java index 64ac6372c88cb..d7492bdd94946 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/OpenSearchExceptionProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/OpenSearchExceptionProtoUtilsTests.java @@ -31,8 +31,8 @@ import java.util.List; import java.util.Map; -import static org.opensearch.transport.grpc.proto.response.TestFixtures.ERROR_SUMMARY_REQUESTED; -import static org.opensearch.transport.grpc.proto.response.TestFixtures.FULL_STACK_TRACE_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.ERROR_SUMMARY_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.FULL_STACK_TRACE_REQUESTED; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtilsTests.java index 1ecb90e26b6a8..0674ef40dcaa0 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtilsTests.java @@ -18,7 +18,7 @@ import java.io.IOException; -import static org.opensearch.transport.grpc.proto.response.TestFixtures.FULL_STACK_TRACE_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.FULL_STACK_TRACE_REQUESTED; public class DefaultShardOperationFailedExceptionProtoUtilsTests extends OpenSearchTestCase { diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtilsTests.java index 31b766fb2a767..f9d6918ee52fe 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtilsTests.java @@ -21,7 +21,7 @@ import java.io.IOException; -import static org.opensearch.transport.grpc.proto.response.TestFixtures.FULL_STACK_TRACE_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.FULL_STACK_TRACE_REQUESTED; import static org.mockito.Mockito.mock; public class ShardOperationFailedExceptionProtoUtilsTests extends OpenSearchTestCase { diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtilsTests.java index cf2f951407780..43703b3dfd907 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtilsTests.java @@ -21,7 +21,7 @@ import java.util.HashMap; import java.util.Map; -import static org.opensearch.transport.grpc.proto.response.TestFixtures.FULL_STACK_TRACE_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.FULL_STACK_TRACE_REQUESTED; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/SearchServiceImplTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/SearchServiceImplTests.java index 1afd61a2b84d2..9b717aeba2206 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/SearchServiceImplTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/SearchServiceImplTests.java @@ -8,12 +8,10 @@ package org.opensearch.transport.grpc.services; -import org.opensearch.common.settings.Settings; import org.opensearch.protobufs.SearchRequest; import org.opensearch.protobufs.SearchRequestBody; import org.opensearch.test.OpenSearchTestCase; import org.opensearch.transport.client.node.NodeClient; -import org.opensearch.transport.grpc.Netty4GrpcServerTransport; import org.opensearch.transport.grpc.proto.request.search.query.AbstractQueryBuilderProtoUtils; import org.opensearch.transport.grpc.proto.request.search.query.QueryBuilderProtoTestUtils; import org.opensearch.transport.grpc.util.GrpcParamsHandler; @@ -27,6 +25,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import static org.opensearch.transport.grpc.TestFixtures.settingsWithGivenStackTraceConfig; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.verify; @@ -137,8 +136,4 @@ private SearchRequest createTestSearchRequest() { .setGlobalParams(org.opensearch.protobufs.GlobalParams.newBuilder().setErrorTrace(true).build()) .build(); } - - private Settings settingsWithGivenStackTraceConfig(boolean stackTracesEnabled) { - return Settings.builder().put(Netty4GrpcServerTransport.SETTING_GRPC_DETAILED_ERRORS_ENABLED.getKey(), stackTracesEnabled).build(); - } } diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java index aa92786d364bb..82169eb8d4d71 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/services/document/DocumentServiceImplTests.java @@ -9,13 +9,11 @@ package org.opensearch.transport.grpc.services.document; import com.google.protobuf.ByteString; -import org.opensearch.common.settings.Settings; import org.opensearch.protobufs.BulkRequest; import org.opensearch.protobufs.BulkRequestBody; import org.opensearch.protobufs.IndexOperation; import org.opensearch.test.OpenSearchTestCase; import org.opensearch.transport.client.node.NodeClient; -import org.opensearch.transport.grpc.Netty4GrpcServerTransport; import org.opensearch.transport.grpc.services.DocumentServiceImpl; import org.opensearch.transport.grpc.util.GrpcParamsHandler; import org.junit.After; @@ -28,6 +26,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import static org.opensearch.transport.grpc.TestFixtures.settingsWithGivenStackTraceConfig; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.verify; @@ -120,8 +119,4 @@ private BulkRequest createTestBulkRequest() { .setGlobalParams(org.opensearch.protobufs.GlobalParams.newBuilder().setErrorTrace(true)) .build(); } - - private Settings settingsWithGivenStackTraceConfig(boolean stackTracesEnabled) { - return Settings.builder().put(Netty4GrpcServerTransport.SETTING_GRPC_DETAILED_ERRORS_ENABLED.getKey(), stackTracesEnabled).build(); - } } diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcErrorHandlerTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcErrorHandlerTests.java index 09b0c47bfd09f..e3c3eaa4a5eb9 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcErrorHandlerTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcErrorHandlerTests.java @@ -16,8 +16,8 @@ import org.opensearch.core.common.breaker.CircuitBreakingException; import org.opensearch.core.concurrency.OpenSearchRejectedExecutionException; import org.opensearch.core.rest.RestStatus; -import org.opensearch.protobufs.GlobalParams; import org.opensearch.test.OpenSearchTestCase; +import org.junit.Before; import java.io.IOException; import java.util.concurrent.TimeoutException; @@ -25,6 +25,10 @@ import io.grpc.Status; import io.grpc.StatusRuntimeException; +import static org.opensearch.transport.grpc.TestFixtures.ERROR_SUMMARY_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.FULL_STACK_TRACE_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.settingsWithGivenStackTraceConfig; + /** * Tests for GrpcErrorHandler utility. * Validates that exceptions are properly converted to appropriate gRPC StatusRuntimeException @@ -32,9 +36,17 @@ */ public class GrpcErrorHandlerTests extends OpenSearchTestCase { - private final GlobalParams detailedErrorsInResponse = GlobalParams.newBuilder().setErrorTrace(true).build(); + @Before + public void setUpGrpcParamsHandler() { + GrpcParamsHandler.initialize(settingsWithGivenStackTraceConfig(true)); + } - public void testOpenSearchExceptionConversion() { + @Before + public void resetGrpcParamsHandlerStackTraces() { + GrpcParamsHandler.initialize(settingsWithGivenStackTraceConfig(true)); + } + + public void testOpenSearchExceptionConversionWithTheStackTrace() { OpenSearchException exception = new OpenSearchException("Test exception") { @Override public RestStatus status() { @@ -42,22 +54,72 @@ public RestStatus status() { } }; - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); // BAD_REQUEST -> INVALID_ARGUMENT via RestToGrpcStatusConverter assertEquals(Status.INVALID_ARGUMENT.getCode(), result.getStatus().getCode()); - // Uses ExceptionsHelper.summaryMessage() format + XContent details - assertTrue(result.getMessage().contains("OpenSearchException[Test exception]")); - assertTrue(result.getMessage().contains("details=")); - assertTrue(result.getMessage().contains("\"type\":\"exception\"")); - assertTrue(result.getMessage().contains("\"reason\":\"Test exception\"")); - assertTrue(result.getMessage().contains("\"status\":400")); + assertTrue( + "Error type with the cause must be present", + result.getMessage().contains("INVALID_ARGUMENT: OpenSearchException[Test exception];") + ); + assertTrue("Details must be present", result.getMessage().contains("details=")); + assertTrue("Exception type must be populated", result.getMessage().contains("\"type\":\"exception\"")); + assertTrue("Reason must be given", result.getMessage().contains("\"reason\":\"Test exception\"")); + assertTrue("Status must be populated", result.getMessage().contains("\"status\":400")); + assertTrue("Stack trace must be populated", result.getMessage().contains("\"stack_trace\":\"OpenSearchException[Test exception]")); + } + + public void testOpenSearchExceptionConversionWithoutTheStackTrace() { + OpenSearchException exception = new OpenSearchException("Test exception") { + @Override + public RestStatus status() { + return RestStatus.BAD_REQUEST; + } + }; + + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, ERROR_SUMMARY_REQUESTED); + + // BAD_REQUEST -> INVALID_ARGUMENT via RestToGrpcStatusConverter + assertEquals(Status.INVALID_ARGUMENT.getCode(), result.getStatus().getCode()); + assertTrue( + "Error type with the cause must be present", + result.getMessage().contains("INVALID_ARGUMENT: OpenSearchException[Test exception];") + ); + assertTrue("Details must be present", result.getMessage().contains("details=")); + assertTrue("Exception type must be present", result.getMessage().contains("\"type\":\"exception\"")); + assertTrue("Reason must be present", result.getMessage().contains("\"reason\":\"Test exception\"")); + assertTrue("Status must be populated", result.getMessage().contains("\"status\":400")); + assertFalse("Stack trace must be omitted", result.getMessage().contains("\"stack_trace\"")); + } + + public void testOpenSearchExceptionConversionWhenDetailedErrorsAreDisabledOnTheServerSide() { + GrpcParamsHandler.initialize(settingsWithGivenStackTraceConfig(false)); + OpenSearchException exception = new OpenSearchException("Test exception") { + @Override + public RestStatus status() { + return RestStatus.BAD_REQUEST; + } + }; + + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, ERROR_SUMMARY_REQUESTED); + + // BAD_REQUEST -> INVALID_ARGUMENT via RestToGrpcStatusConverter + assertEquals(Status.INVALID_ARGUMENT.getCode(), result.getStatus().getCode()); + assertTrue( + "Error type with the cause must be present", + result.getMessage().contains("INVALID_ARGUMENT: OpenSearchException[Test exception];") + ); + assertTrue("Details must be present", result.getMessage().contains("details=")); + assertFalse("Exception type must be omitted", result.getMessage().contains("\"type\"")); + assertFalse("Reason must be omitted", result.getMessage().contains("\"reason\"")); + assertTrue("Status must be populated", result.getMessage().contains("\"status\":400")); + assertFalse("Stack trace must be omitted", result.getMessage().contains("\"stack_trace\"")); } public void testIllegalArgumentExceptionConversion() { IllegalArgumentException exception = new IllegalArgumentException("Invalid parameter"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); // IllegalArgumentException -> INVALID_ARGUMENT via direct gRPC mapping assertEquals(Status.INVALID_ARGUMENT.getCode(), result.getStatus().getCode()); @@ -68,7 +130,7 @@ public void testIllegalArgumentExceptionConversion() { public void testInputCoercionExceptionConversion() { InputCoercionException exception = new InputCoercionException(null, "Cannot coerce string to number", null, String.class); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); // InputCoercionException -> INVALID_ARGUMENT via direct gRPC mapping assertEquals(Status.INVALID_ARGUMENT.getCode(), result.getStatus().getCode()); @@ -80,7 +142,7 @@ public void testInputCoercionExceptionConversion() { public void testJsonParseExceptionConversion() { JsonParseException exception = new JsonParseException(null, "Unexpected character"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); // JsonParseException -> INVALID_ARGUMENT via direct gRPC mapping assertEquals(Status.INVALID_ARGUMENT.getCode(), result.getStatus().getCode()); @@ -92,7 +154,7 @@ public void testJsonParseExceptionConversion() { public void testOpenSearchRejectedExecutionExceptionConversion() { OpenSearchRejectedExecutionException exception = new OpenSearchRejectedExecutionException("Thread pool full"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); // OpenSearchRejectedExecutionException -> RESOURCE_EXHAUSTED via direct gRPC mapping assertEquals(Status.RESOURCE_EXHAUSTED.getCode(), result.getStatus().getCode()); @@ -104,7 +166,7 @@ public void testOpenSearchRejectedExecutionExceptionConversion() { public void testIllegalStateExceptionConversion() { IllegalStateException exception = new IllegalStateException("Invalid state"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); // IllegalStateException -> FAILED_PRECONDITION via direct gRPC mapping assertEquals(Status.FAILED_PRECONDITION.getCode(), result.getStatus().getCode()); @@ -115,7 +177,7 @@ public void testIllegalStateExceptionConversion() { public void testSecurityExceptionConversion() { SecurityException exception = new SecurityException("Access denied"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); // SecurityException -> PERMISSION_DENIED via direct gRPC mapping assertEquals(Status.PERMISSION_DENIED.getCode(), result.getStatus().getCode()); @@ -126,7 +188,7 @@ public void testSecurityExceptionConversion() { public void testTimeoutExceptionConversion() { TimeoutException exception = new TimeoutException("Operation timed out"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); // TimeoutException -> DEADLINE_EXCEEDED via direct gRPC mapping assertEquals(Status.DEADLINE_EXCEEDED.getCode(), result.getStatus().getCode()); @@ -137,7 +199,7 @@ public void testTimeoutExceptionConversion() { public void testInterruptedExceptionConversion() { InterruptedException exception = new InterruptedException(); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); // InterruptedException -> CANCELLED via direct gRPC mapping assertEquals(Status.CANCELLED.getCode(), result.getStatus().getCode()); @@ -148,7 +210,7 @@ public void testInterruptedExceptionConversion() { public void testIOExceptionConversion() { IOException exception = new IOException("I/O error"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); // IOException -> INTERNAL via direct gRPC mapping assertEquals(Status.INTERNAL.getCode(), result.getStatus().getCode()); @@ -159,7 +221,7 @@ public void testIOExceptionConversion() { public void testUnknownExceptionConversion() { RuntimeException exception = new RuntimeException("Unknown error"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); // RuntimeException -> INTERNAL via fallback (unknown exception type) assertEquals(Status.INTERNAL.getCode(), result.getStatus().getCode()); @@ -175,7 +237,7 @@ public RestStatus status() { } }; - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); // NOT_FOUND -> NOT_FOUND via RestToGrpcStatusConverter assertEquals(Status.NOT_FOUND.getCode(), result.getStatus().getCode()); @@ -187,7 +249,7 @@ public RestStatus status() { public void testCircuitBreakingExceptionInCleanMessage() { CircuitBreakingException exception = new CircuitBreakingException("Memory circuit breaker", 100, 90, null); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); // CircuitBreakingException extends OpenSearchException with TOO_MANY_REQUESTS -> RESOURCE_EXHAUSTED assertEquals(Status.RESOURCE_EXHAUSTED.getCode(), result.getStatus().getCode()); @@ -203,7 +265,7 @@ public void testSearchPhaseExecutionExceptionInCleanMessage() { new org.opensearch.action.search.ShardSearchFailure[0] ); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); // SearchPhaseExecutionException extends OpenSearchException with SERVICE_UNAVAILABLE -> UNAVAILABLE assertEquals(Status.UNAVAILABLE.getCode(), result.getStatus().getCode()); @@ -224,7 +286,7 @@ public RestStatus status() { }; exception.addMetadata("opensearch.test_key", "test_value"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); // Should include metadata in JSON details assertTrue(result.getMessage().contains("details=")); @@ -250,7 +312,7 @@ public void metadataToXContent( } }; - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, detailedErrorsInResponse); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); // Should fall back to base description when XContent extraction fails assertEquals(Status.INVALID_ARGUMENT.getCode(), result.getStatus().getCode()); @@ -275,7 +337,7 @@ public RestStatus status() { } }; - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(wrappedException, detailedErrorsInResponse); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(wrappedException, FULL_STACK_TRACE_REQUESTED); // Should include root_cause array like HTTP responses assertTrue(result.getMessage().contains("root_cause")); diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcParamsHandlerTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcParamsHandlerTests.java index 6fe7213d94ca1..a95cf918afb92 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcParamsHandlerTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcParamsHandlerTests.java @@ -8,13 +8,12 @@ package org.opensearch.transport.grpc.util; -import org.opensearch.common.settings.Settings; import org.opensearch.test.OpenSearchTestCase; -import org.opensearch.transport.grpc.Netty4GrpcServerTransport; import org.junit.After; -import static org.opensearch.transport.grpc.proto.response.TestFixtures.ERROR_SUMMARY_REQUESTED; -import static org.opensearch.transport.grpc.proto.response.TestFixtures.FULL_STACK_TRACE_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.ERROR_SUMMARY_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.FULL_STACK_TRACE_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.settingsWithGivenStackTraceConfig; public class GrpcParamsHandlerTests extends OpenSearchTestCase { @@ -54,8 +53,4 @@ public void testGrpcParamsHandlerPicksErrorTraceRequestParameter() { ); } - private Settings settingsWithGivenStackTraceConfig(boolean stackTracesEnabled) { - return Settings.builder().put(Netty4GrpcServerTransport.SETTING_GRPC_DETAILED_ERRORS_ENABLED.getKey(), stackTracesEnabled).build(); - } - } From 402308f45af418087547659c213aa932c75c09fc Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Mon, 10 Nov 2025 17:57:38 +0100 Subject: [PATCH 17/28] Further polishing and a bit more testing Signed-off-by: Sergei Ustimenko --- .../transport/grpc/TestFixtures.java | 4 +- .../BulkRequestActionListenerTests.java | 4 +- .../response/BulkResponseProtoUtilsTests.java | 17 +- .../bulk/BulkItemResponseProtoUtilsTests.java | 16 +- .../DocWriteResponseProtoUtilsTests.java | 10 +- .../common/ShardInfoProtoUtilsTests.java | 8 +- .../OpenSearchExceptionProtoUtilsTests.java | 26 ++-- ...erationFailedExceptionProtoUtilsTests.java | 12 +- ...erationFailedExceptionProtoUtilsTests.java | 21 ++- .../search/SearchResponseProtoUtilsTests.java | 37 ++++- .../grpc/util/GrpcErrorHandlerTests.java | 145 +++++++++++++++--- .../grpc/util/GrpcParamsHandlerTests.java | 12 +- 12 files changed, 226 insertions(+), 86 deletions(-) diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/TestFixtures.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/TestFixtures.java index 70dd06ba482e8..d1e02789a4de3 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/TestFixtures.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/TestFixtures.java @@ -13,9 +13,9 @@ public final class TestFixtures { - public static final GlobalParams FULL_STACK_TRACE_REQUESTED = GlobalParams.newBuilder().setErrorTrace(true).build(); + public static final GlobalParams GLOBAL_PARAMS_WITH_ERROR_TRACE_TRUE = GlobalParams.newBuilder().setErrorTrace(true).build(); - public static final GlobalParams ERROR_SUMMARY_REQUESTED = GlobalParams.newBuilder().setErrorTrace(false).build(); + public static final GlobalParams GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE = GlobalParams.newBuilder().setErrorTrace(false).build(); public static Settings settingsWithGivenStackTraceConfig(boolean stackTracesEnabled) { return Settings.builder().put(Netty4GrpcServerTransport.SETTING_GRPC_DETAILED_ERRORS_ENABLED.getKey(), stackTracesEnabled).build(); diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListenerTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListenerTests.java index 18133143498a8..a4a57c9f07743 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListenerTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/listeners/BulkRequestActionListenerTests.java @@ -23,7 +23,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import static org.opensearch.transport.grpc.TestFixtures.FULL_STACK_TRACE_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; @@ -38,7 +38,7 @@ public class BulkRequestActionListenerTests extends OpenSearchTestCase { public void setUp() throws Exception { super.setUp(); MockitoAnnotations.openMocks(this); - listener = new BulkRequestActionListener(responseObserver, FULL_STACK_TRACE_REQUESTED); + listener = new BulkRequestActionListener(responseObserver, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); } public void testOnResponseWithSuccessfulResponse() { diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/BulkResponseProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/BulkResponseProtoUtilsTests.java index 8f545a62ed898..bc2d1af520bb6 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/BulkResponseProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/BulkResponseProtoUtilsTests.java @@ -22,7 +22,7 @@ import io.grpc.Status; -import static org.opensearch.transport.grpc.TestFixtures.FULL_STACK_TRACE_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE; public class BulkResponseProtoUtilsTests extends OpenSearchTestCase { @@ -39,7 +39,10 @@ public void testToProtoWithSuccessfulResponse() throws IOException { BulkResponse bulkResponse = new BulkResponse(responses, 100); // Convert to Protocol Buffer - org.opensearch.protobufs.BulkResponse protoResponse = BulkResponseProtoUtils.toProto(bulkResponse, FULL_STACK_TRACE_REQUESTED); + org.opensearch.protobufs.BulkResponse protoResponse = BulkResponseProtoUtils.toProto( + bulkResponse, + GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE + ); // Verify the conversion assertEquals("Should have the correct took time", 100, protoResponse.getTook()); @@ -67,7 +70,10 @@ public void testToProtoWithFailedResponse() throws IOException { BulkResponse bulkResponse = new BulkResponse(responses, 100); // Convert to Protocol Buffer - org.opensearch.protobufs.BulkResponse protoResponse = BulkResponseProtoUtils.toProto(bulkResponse, FULL_STACK_TRACE_REQUESTED); + org.opensearch.protobufs.BulkResponse protoResponse = BulkResponseProtoUtils.toProto( + bulkResponse, + GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE + ); // Verify the conversion assertEquals("Should have the correct took time", 100, protoResponse.getTook()); @@ -96,7 +102,10 @@ public void testToProtoWithIngestTook() throws IOException { BulkResponse bulkResponse = new BulkResponse(responses, 100, 50); // Convert to Protocol Buffer - org.opensearch.protobufs.BulkResponse protoResponse = BulkResponseProtoUtils.toProto(bulkResponse, FULL_STACK_TRACE_REQUESTED); + org.opensearch.protobufs.BulkResponse protoResponse = BulkResponseProtoUtils.toProto( + bulkResponse, + GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE + ); // Verify the conversion assertEquals("Should have the correct took time", 100, protoResponse.getTook()); diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtilsTests.java index 949bcc4166bdd..a48285ef84812 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/bulk/BulkItemResponseProtoUtilsTests.java @@ -30,7 +30,7 @@ import io.grpc.Status; -import static org.opensearch.transport.grpc.TestFixtures.FULL_STACK_TRACE_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE; public class BulkItemResponseProtoUtilsTests extends OpenSearchTestCase { @@ -51,7 +51,7 @@ public void testToProtoWithIndexResponse() throws IOException { // Convert to protobuf ResponseItem org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto( bulkItemResponse, - FULL_STACK_TRACE_REQUESTED + GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE ); // Verify the result @@ -79,7 +79,7 @@ public void testToProtoWithCreateResponse() throws IOException { // Convert to protobuf ResponseItem org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto( bulkItemResponse, - FULL_STACK_TRACE_REQUESTED + GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE ); // Verify the result @@ -107,7 +107,7 @@ public void testToProtoWithDeleteResponse() throws IOException { // Convert to protobuf ResponseItem org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto( bulkItemResponse, - FULL_STACK_TRACE_REQUESTED + GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE ); // Verify the result @@ -135,7 +135,7 @@ public void testToProtoWithUpdateResponse() throws IOException { // Convert to protobuf Item org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto( bulkItemResponse, - FULL_STACK_TRACE_REQUESTED + GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE ); // Verify the result @@ -181,7 +181,7 @@ public void testToProtoWithUpdateResponseAndGetResult() throws IOException { // Convert to protobuf Item org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto( bulkItemResponse, - FULL_STACK_TRACE_REQUESTED + GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE ); // Verify the result @@ -214,7 +214,7 @@ public void testToProtoWithFailure() throws IOException { // Convert to protobuf Item org.opensearch.protobufs.ResponseItem responseItem = BulkItemResponseProtoUtils.toProto( bulkItemResponse, - FULL_STACK_TRACE_REQUESTED + GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE ); // Verify the result @@ -230,6 +230,6 @@ public void testToProtoWithFailure() throws IOException { public void testToProtoWithNullResponse() throws IOException { // Call toProto with null, should throw NullPointerException - expectThrows(NullPointerException.class, () -> BulkItemResponseProtoUtils.toProto(null, FULL_STACK_TRACE_REQUESTED)); + expectThrows(NullPointerException.class, () -> BulkItemResponseProtoUtils.toProto(null, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE)); } } diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtilsTests.java index 7a480c1527585..fde5d8a7ef635 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/DocWriteResponseProtoUtilsTests.java @@ -17,7 +17,7 @@ import java.io.IOException; -import static org.opensearch.transport.grpc.TestFixtures.FULL_STACK_TRACE_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE; public class DocWriteResponseProtoUtilsTests extends OpenSearchTestCase { @@ -34,7 +34,7 @@ public void testToProtoWithIndexResponse() throws IOException { indexResponse.setForcedRefresh(true); // Convert to protobuf ResponseItem.Builder - ResponseItem.Builder responseItemBuilder = DocWriteResponseProtoUtils.toProto(indexResponse, FULL_STACK_TRACE_REQUESTED); + ResponseItem.Builder responseItemBuilder = DocWriteResponseProtoUtils.toProto(indexResponse, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // Verify the result assertNotNull("ResponseItem.Builder should not be null", responseItemBuilder); @@ -72,7 +72,7 @@ public void testToProtoWithEmptyId() throws IOException { indexResponse.setShardInfo(shardInfo); // Convert to protobuf ResponseItem.Builder - ResponseItem.Builder responseItemBuilder = DocWriteResponseProtoUtils.toProto(indexResponse, FULL_STACK_TRACE_REQUESTED); + ResponseItem.Builder responseItemBuilder = DocWriteResponseProtoUtils.toProto(indexResponse, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // Verify the result assertNotNull("ResponseItem.Builder should not be null", responseItemBuilder); @@ -96,7 +96,7 @@ public void testToProtoWithNoSeqNo() throws IOException { indexResponse.setShardInfo(shardInfo); // Convert to protobuf ResponseItem.Builder - ResponseItem.Builder responseItemBuilder = DocWriteResponseProtoUtils.toProto(indexResponse, FULL_STACK_TRACE_REQUESTED); + ResponseItem.Builder responseItemBuilder = DocWriteResponseProtoUtils.toProto(indexResponse, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // Verify the result assertNotNull("ResponseItem.Builder should not be null", responseItemBuilder); @@ -111,6 +111,6 @@ public void testToProtoWithNoSeqNo() throws IOException { public void testToProtoWithNullResponse() throws IOException { // Call toProto with null, should throw NullPointerException - expectThrows(NullPointerException.class, () -> DocWriteResponseProtoUtils.toProto(null, FULL_STACK_TRACE_REQUESTED)); + expectThrows(NullPointerException.class, () -> DocWriteResponseProtoUtils.toProto(null, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE)); } } diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtilsTests.java index d0eb6d2d07c3e..a4f4a6867d472 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/document/common/ShardInfoProtoUtilsTests.java @@ -19,7 +19,7 @@ import java.util.ArrayList; import java.util.List; -import static org.opensearch.transport.grpc.TestFixtures.FULL_STACK_TRACE_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE; public class ShardInfoProtoUtilsTests extends OpenSearchTestCase { @@ -28,7 +28,7 @@ public void testToProtoWithNoFailures() throws IOException { ReplicationResponse.ShardInfo shardInfo = new ReplicationResponse.ShardInfo(5, 3, new ReplicationResponse.ShardInfo.Failure[0]); // Convert to protobuf ShardInfo - ShardInfo protoShardInfo = ShardInfoProtoUtils.toProto(shardInfo, FULL_STACK_TRACE_REQUESTED); + ShardInfo protoShardInfo = ShardInfoProtoUtils.toProto(shardInfo, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // Verify the result assertNotNull("ShardInfo should not be null", protoShardInfo); @@ -57,7 +57,7 @@ public void testToProtoWithFailures() throws IOException { ReplicationResponse.ShardInfo shardInfo = new ReplicationResponse.ShardInfo(5, 3, failures); // Convert to protobuf ShardInfo - ShardInfo protoShardInfo = ShardInfoProtoUtils.toProto(shardInfo, FULL_STACK_TRACE_REQUESTED); + ShardInfo protoShardInfo = ShardInfoProtoUtils.toProto(shardInfo, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // Verify the result assertNotNull("ShardInfo should not be null", protoShardInfo); @@ -89,6 +89,6 @@ public void testToProtoWithFailures() throws IOException { public void testToProtoWithNullShardInfo() throws IOException { // Call toProto with null, should throw NullPointerException - expectThrows(NullPointerException.class, () -> ShardInfoProtoUtils.toProto(null, FULL_STACK_TRACE_REQUESTED)); + expectThrows(NullPointerException.class, () -> ShardInfoProtoUtils.toProto(null, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE)); } } diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/OpenSearchExceptionProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/OpenSearchExceptionProtoUtilsTests.java index d7492bdd94946..fabb29e0fa62c 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/OpenSearchExceptionProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/OpenSearchExceptionProtoUtilsTests.java @@ -31,8 +31,8 @@ import java.util.List; import java.util.Map; -import static org.opensearch.transport.grpc.TestFixtures.ERROR_SUMMARY_REQUESTED; -import static org.opensearch.transport.grpc.TestFixtures.FULL_STACK_TRACE_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE; +import static org.opensearch.transport.grpc.TestFixtures.GLOBAL_PARAMS_WITH_ERROR_TRACE_TRUE; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -44,7 +44,7 @@ public void testToProtoWithOpenSearchException() throws IOException { OpenSearchException exception = new OpenSearchException("Test exception"); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.toProto(exception, FULL_STACK_TRACE_REQUESTED); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.toProto(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_TRUE); // Verify the conversion // The actual type format uses underscores instead of dots @@ -60,7 +60,7 @@ public void testToProtoWithOpenSearchExceptionSummary() throws IOException { OpenSearchException exception = new OpenSearchException("Test exception"); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.toProto(exception, ERROR_SUMMARY_REQUESTED); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.toProto(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // Verify the conversion // The actual type format uses underscores instead of dots @@ -75,7 +75,7 @@ public void testToProtoWithNestedOpenSearchException() throws IOException { OpenSearchException exception = new OpenSearchException("Test exception", cause); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.toProto(exception, FULL_STACK_TRACE_REQUESTED); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.toProto(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_TRUE); // Verify the conversion // The actual type format uses underscores instead of dots @@ -98,7 +98,7 @@ public void testToProtoWithNestedOpenSearchExceptionSummary() throws IOException OpenSearchException exception = new OpenSearchException("Test exception", cause); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.toProto(exception, ERROR_SUMMARY_REQUESTED); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.toProto(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // Verify the conversion // The actual type format uses underscores instead of dots @@ -120,7 +120,7 @@ public void testGenerateThrowableProtoWithOpenSearchException() throws IOExcepti OpenSearchException exception = new OpenSearchException("Test exception"); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, FULL_STACK_TRACE_REQUESTED); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // Verify the conversion // The actual type format uses underscores instead of dots @@ -133,7 +133,7 @@ public void testGenerateThrowableProtoWithIOException() throws IOException { IOException exception = new IOException("Test IO exception"); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, FULL_STACK_TRACE_REQUESTED); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // Verify the conversion // The actual type format uses underscores instead of dots @@ -146,7 +146,7 @@ public void testGenerateThrowableProtoWithRuntimeException() throws IOException RuntimeException exception = new RuntimeException("Test runtime exception"); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, FULL_STACK_TRACE_REQUESTED); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // Verify the conversion // The actual type format uses underscores instead of dots @@ -159,7 +159,7 @@ public void testGenerateThrowableProtoWithNullMessage() throws IOException { RuntimeException exception = new RuntimeException((String) null); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, FULL_STACK_TRACE_REQUESTED); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // Verify the conversion // The actual type format uses underscores instead of dots @@ -173,7 +173,7 @@ public void testGenerateThrowableProtoWithSuppressedExceptions() throws IOExcept exception.addSuppressed(new IllegalArgumentException("Suppressed exception")); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, ERROR_SUMMARY_REQUESTED); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // Verify the conversion // The actual type format uses underscores instead of dots @@ -193,7 +193,7 @@ public void testInnerToProtoWithBasicException() throws IOException { RuntimeException exception = new RuntimeException("Test exception"); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, FULL_STACK_TRACE_REQUESTED); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_TRUE); // Verify the conversion // The actual type format uses underscores instead of dots @@ -207,7 +207,7 @@ public void testInnerToProtoReturnsOnlyBasicExceptionSummary() throws IOExceptio RuntimeException exception = new RuntimeException("Test exception"); // Convert to Protocol Buffer - ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, ERROR_SUMMARY_REQUESTED); + ErrorCause errorCause = OpenSearchExceptionProtoUtils.generateThrowableProto(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // Verify the conversion // The actual type format uses underscores instead of dots diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtilsTests.java index 0674ef40dcaa0..92c66549522af 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtilsTests.java @@ -18,7 +18,7 @@ import java.io.IOException; -import static org.opensearch.transport.grpc.TestFixtures.FULL_STACK_TRACE_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE; public class DefaultShardOperationFailedExceptionProtoUtilsTests extends OpenSearchTestCase { @@ -31,7 +31,7 @@ public void testToProtoWithDefaultShardOperationFailedException() throws IOExcep ); // Call the method under test - ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception, FULL_STACK_TRACE_REQUESTED); + ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // Verify the result assertNotNull("ShardFailure should not be null", shardFailure); @@ -51,7 +51,7 @@ public void testToProtoWithAddIndexBlockResponseFailure() throws IOException { ); // Call the method under test - ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception, FULL_STACK_TRACE_REQUESTED); + ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // Verify the result assertNotNull("ShardFailure should not be null", shardFailure); @@ -72,7 +72,7 @@ public void testToProtoWithIndicesShardStoresResponseFailure() throws IOExceptio ); // Call the method under test - ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception, FULL_STACK_TRACE_REQUESTED); + ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // Verify the result assertNotNull("ShardFailure should not be null", shardFailure); @@ -93,7 +93,7 @@ public void testToProtoWithCloseIndexResponseFailure() throws IOException { ); // Call the method under test - ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception, FULL_STACK_TRACE_REQUESTED); + ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // Verify the result assertNotNull("ShardFailure should not be null", shardFailure); @@ -114,7 +114,7 @@ public void testToProtoWithNullNodeId() throws IOException { ); // Call the method under test - ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception, FULL_STACK_TRACE_REQUESTED); + ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // Verify the result assertNotNull("ShardFailure should not be null", shardFailure); diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtilsTests.java index f9d6918ee52fe..45de397f521c2 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtilsTests.java @@ -21,7 +21,7 @@ import java.io.IOException; -import static org.opensearch.transport.grpc.TestFixtures.FULL_STACK_TRACE_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE; import static org.mockito.Mockito.mock; public class ShardOperationFailedExceptionProtoUtilsTests extends OpenSearchTestCase { @@ -36,7 +36,10 @@ public void testToProtoWithShardSearchFailure() throws IOException { ShardSearchFailure shardSearchFailure = new ShardSearchFailure(new Exception("fake exception"), searchShardTarget); // Call the method under test - ShardFailure protoFailure = ShardOperationFailedExceptionProtoUtils.toProto(shardSearchFailure, FULL_STACK_TRACE_REQUESTED); + ShardFailure protoFailure = ShardOperationFailedExceptionProtoUtils.toProto( + shardSearchFailure, + GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE + ); // Verify the result assertNotNull("Proto failure should not be null", protoFailure); @@ -54,7 +57,10 @@ public void testToProtoWithSnapshotShardFailure() throws IOException { SnapshotShardFailure shardSearchFailure = new SnapshotShardFailure("test_node", shardId, "Snapshot failed"); // Call the method under test - ShardFailure protoFailure = ShardOperationFailedExceptionProtoUtils.toProto(shardSearchFailure, FULL_STACK_TRACE_REQUESTED); + ShardFailure protoFailure = ShardOperationFailedExceptionProtoUtils.toProto( + shardSearchFailure, + GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE + ); // Verify the result assertNotNull("Proto failure should not be null", protoFailure); @@ -75,7 +81,7 @@ public void testToProtoWithDefaultShardOperationFailedException() throws IOExcep // Call the method under test ShardFailure protoFailure = ShardOperationFailedExceptionProtoUtils.toProto( defaultShardOperationFailedException, - FULL_STACK_TRACE_REQUESTED + GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE ); // Verify the result @@ -97,7 +103,10 @@ public void testToProtoWithReplicationResponseShardInfoFailure() throws IOExcept ); // Call the method under test - ShardFailure protoFailure = ShardOperationFailedExceptionProtoUtils.toProto(replicationResponseFailure, FULL_STACK_TRACE_REQUESTED); + ShardFailure protoFailure = ShardOperationFailedExceptionProtoUtils.toProto( + replicationResponseFailure, + GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE + ); // Verify the result assertNotNull("Proto failure should not be null", protoFailure); @@ -115,7 +124,7 @@ public void testToProtoWithUnsupportedShardOperationFailedException() { // Call the method under test, should throw UnsupportedOperationException UnsupportedOperationException exception = expectThrows( UnsupportedOperationException.class, - () -> ShardOperationFailedExceptionProtoUtils.toProto(mockFailure, FULL_STACK_TRACE_REQUESTED) + () -> ShardOperationFailedExceptionProtoUtils.toProto(mockFailure, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE) ); assertTrue( diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtilsTests.java index 43703b3dfd907..9aa23c0f25749 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtilsTests.java @@ -21,7 +21,7 @@ import java.util.HashMap; import java.util.Map; -import static org.opensearch.transport.grpc.TestFixtures.FULL_STACK_TRACE_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -42,7 +42,10 @@ public void testToProtoWithBasicResponse() throws IOException { when(mockResponse.getInternalResponse()).thenReturn(mock(SearchResponseSections.class)); // Call the method under test - org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, FULL_STACK_TRACE_REQUESTED); + org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto( + mockResponse, + GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE + ); // Verify the result assertNotNull("Proto response should not be null", protoResponse); @@ -70,7 +73,10 @@ public void testToProtoWithScrollId() throws IOException { when(mockResponse.getInternalResponse()).thenReturn(mock(SearchResponseSections.class)); // Call the method under test - org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, FULL_STACK_TRACE_REQUESTED); + org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto( + mockResponse, + GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE + ); // Verify the result assertNotNull("Proto response should not be null", protoResponse); @@ -93,7 +99,10 @@ public void testToProtoWithPointInTimeId() throws IOException { when(mockResponse.getInternalResponse()).thenReturn(mock(SearchResponseSections.class)); // Call the method under test - org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, FULL_STACK_TRACE_REQUESTED); + org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto( + mockResponse, + GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE + ); // Verify the result assertNotNull("Proto response should not be null", protoResponse); @@ -127,7 +136,10 @@ public void testToProtoWithPhaseTook() throws IOException { when(mockResponse.getInternalResponse()).thenReturn(mock(SearchResponseSections.class)); // Call the method under test - org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, FULL_STACK_TRACE_REQUESTED); + org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto( + mockResponse, + GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE + ); // Verify the result assertNotNull("Proto response should not be null", protoResponse); @@ -156,7 +168,10 @@ public void testToProtoWithTerminatedEarly() throws IOException { when(mockResponse.getInternalResponse()).thenReturn(mock(SearchResponseSections.class)); // Call the method under test - org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, FULL_STACK_TRACE_REQUESTED); + org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto( + mockResponse, + GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE + ); // Verify the result assertNotNull("Proto response should not be null", protoResponse); @@ -179,7 +194,10 @@ public void testToProtoWithNumReducePhases() throws IOException { when(mockResponse.getInternalResponse()).thenReturn(mock(SearchResponseSections.class)); // Call the method under test - org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, FULL_STACK_TRACE_REQUESTED); + org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto( + mockResponse, + GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE + ); // Verify the result assertNotNull("Proto response should not be null", protoResponse); @@ -201,7 +219,10 @@ public void testToProtoWithClusters() throws IOException { when(mockResponse.getInternalResponse()).thenReturn(mock(SearchResponseSections.class)); // Call the method under test - org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto(mockResponse, FULL_STACK_TRACE_REQUESTED); + org.opensearch.protobufs.SearchResponse protoResponse = SearchResponseProtoUtils.toProto( + mockResponse, + GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE + ); // Verify the result assertNotNull("Proto response should not be null", protoResponse); diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcErrorHandlerTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcErrorHandlerTests.java index e3c3eaa4a5eb9..70ca92398c2b1 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcErrorHandlerTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcErrorHandlerTests.java @@ -17,6 +17,7 @@ import org.opensearch.core.concurrency.OpenSearchRejectedExecutionException; import org.opensearch.core.rest.RestStatus; import org.opensearch.test.OpenSearchTestCase; +import org.junit.After; import org.junit.Before; import java.io.IOException; @@ -25,8 +26,8 @@ import io.grpc.Status; import io.grpc.StatusRuntimeException; -import static org.opensearch.transport.grpc.TestFixtures.ERROR_SUMMARY_REQUESTED; -import static org.opensearch.transport.grpc.TestFixtures.FULL_STACK_TRACE_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE; +import static org.opensearch.transport.grpc.TestFixtures.GLOBAL_PARAMS_WITH_ERROR_TRACE_TRUE; import static org.opensearch.transport.grpc.TestFixtures.settingsWithGivenStackTraceConfig; /** @@ -41,7 +42,7 @@ public void setUpGrpcParamsHandler() { GrpcParamsHandler.initialize(settingsWithGivenStackTraceConfig(true)); } - @Before + @After public void resetGrpcParamsHandlerStackTraces() { GrpcParamsHandler.initialize(settingsWithGivenStackTraceConfig(true)); } @@ -54,7 +55,7 @@ public RestStatus status() { } }; - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_TRUE); // BAD_REQUEST -> INVALID_ARGUMENT via RestToGrpcStatusConverter assertEquals(Status.INVALID_ARGUMENT.getCode(), result.getStatus().getCode()); @@ -77,7 +78,7 @@ public RestStatus status() { } }; - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, ERROR_SUMMARY_REQUESTED); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // BAD_REQUEST -> INVALID_ARGUMENT via RestToGrpcStatusConverter assertEquals(Status.INVALID_ARGUMENT.getCode(), result.getStatus().getCode()); @@ -101,7 +102,7 @@ public RestStatus status() { } }; - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, ERROR_SUMMARY_REQUESTED); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // BAD_REQUEST -> INVALID_ARGUMENT via RestToGrpcStatusConverter assertEquals(Status.INVALID_ARGUMENT.getCode(), result.getStatus().getCode()); @@ -119,7 +120,17 @@ public RestStatus status() { public void testIllegalArgumentExceptionConversion() { IllegalArgumentException exception = new IllegalArgumentException("Invalid parameter"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); + + // IllegalArgumentException -> INVALID_ARGUMENT via direct gRPC mapping + assertEquals(Status.INVALID_ARGUMENT.getCode(), result.getStatus().getCode()); + assertTrue(result.getMessage().contains("INVALID_ARGUMENT: Invalid parameter")); + } + + public void testIllegalArgumentExceptionConversionWithExceptionDetails() { + IllegalArgumentException exception = new IllegalArgumentException("Invalid parameter"); + + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_TRUE); // IllegalArgumentException -> INVALID_ARGUMENT via direct gRPC mapping assertEquals(Status.INVALID_ARGUMENT.getCode(), result.getStatus().getCode()); @@ -130,7 +141,17 @@ public void testIllegalArgumentExceptionConversion() { public void testInputCoercionExceptionConversion() { InputCoercionException exception = new InputCoercionException(null, "Cannot coerce string to number", null, String.class); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); + + // InputCoercionException -> INVALID_ARGUMENT via direct gRPC mapping + assertEquals(Status.INVALID_ARGUMENT.getCode(), result.getStatus().getCode()); + assertTrue(result.getMessage().contains("INVALID_ARGUMENT: Cannot coerce string to number")); + } + + public void testInputCoercionExceptionConversionWithExceptionDetails() { + InputCoercionException exception = new InputCoercionException(null, "Cannot coerce string to number", null, String.class); + + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_TRUE); // InputCoercionException -> INVALID_ARGUMENT via direct gRPC mapping assertEquals(Status.INVALID_ARGUMENT.getCode(), result.getStatus().getCode()); @@ -142,7 +163,17 @@ public void testInputCoercionExceptionConversion() { public void testJsonParseExceptionConversion() { JsonParseException exception = new JsonParseException(null, "Unexpected character"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); + + // JsonParseException -> INVALID_ARGUMENT via direct gRPC mapping + assertEquals(Status.INVALID_ARGUMENT.getCode(), result.getStatus().getCode()); + assertTrue(result.getMessage().contains("INVALID_ARGUMENT: Unexpected character")); + } + + public void testJsonParseExceptionConversionWithExceptionDetails() { + JsonParseException exception = new JsonParseException(null, "Unexpected character"); + + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_TRUE); // JsonParseException -> INVALID_ARGUMENT via direct gRPC mapping assertEquals(Status.INVALID_ARGUMENT.getCode(), result.getStatus().getCode()); @@ -154,7 +185,17 @@ public void testJsonParseExceptionConversion() { public void testOpenSearchRejectedExecutionExceptionConversion() { OpenSearchRejectedExecutionException exception = new OpenSearchRejectedExecutionException("Thread pool full"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); + + // OpenSearchRejectedExecutionException -> RESOURCE_EXHAUSTED via direct gRPC mapping + assertEquals(Status.RESOURCE_EXHAUSTED.getCode(), result.getStatus().getCode()); + assertTrue(result.getMessage().contains("RESOURCE_EXHAUSTED: Thread pool full")); + } + + public void testOpenSearchRejectedExecutionExceptionConversionWithExceptionDetails() { + OpenSearchRejectedExecutionException exception = new OpenSearchRejectedExecutionException("Thread pool full"); + + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_TRUE); // OpenSearchRejectedExecutionException -> RESOURCE_EXHAUSTED via direct gRPC mapping assertEquals(Status.RESOURCE_EXHAUSTED.getCode(), result.getStatus().getCode()); @@ -166,7 +207,17 @@ public void testOpenSearchRejectedExecutionExceptionConversion() { public void testIllegalStateExceptionConversion() { IllegalStateException exception = new IllegalStateException("Invalid state"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); + + // IllegalStateException -> FAILED_PRECONDITION via direct gRPC mapping + assertEquals(Status.FAILED_PRECONDITION.getCode(), result.getStatus().getCode()); + assertTrue(result.getMessage().contains("FAILED_PRECONDITION: Invalid state")); + } + + public void testIllegalStateExceptionConversionWithExceptionDetails() { + IllegalStateException exception = new IllegalStateException("Invalid state"); + + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_TRUE); // IllegalStateException -> FAILED_PRECONDITION via direct gRPC mapping assertEquals(Status.FAILED_PRECONDITION.getCode(), result.getStatus().getCode()); @@ -177,7 +228,17 @@ public void testIllegalStateExceptionConversion() { public void testSecurityExceptionConversion() { SecurityException exception = new SecurityException("Access denied"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); + + // SecurityException -> PERMISSION_DENIED via direct gRPC mapping + assertEquals(Status.PERMISSION_DENIED.getCode(), result.getStatus().getCode()); + assertTrue(result.getMessage().contains("PERMISSION_DENIED: Access denied")); + } + + public void testSecurityExceptionConversionWithExceptionDetails() { + SecurityException exception = new SecurityException("Access denied"); + + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_TRUE); // SecurityException -> PERMISSION_DENIED via direct gRPC mapping assertEquals(Status.PERMISSION_DENIED.getCode(), result.getStatus().getCode()); @@ -188,7 +249,17 @@ public void testSecurityExceptionConversion() { public void testTimeoutExceptionConversion() { TimeoutException exception = new TimeoutException("Operation timed out"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); + + // TimeoutException -> DEADLINE_EXCEEDED via direct gRPC mapping + assertEquals(Status.DEADLINE_EXCEEDED.getCode(), result.getStatus().getCode()); + assertTrue(result.getMessage().contains("DEADLINE_EXCEEDED: Operation timed out")); + } + + public void testTimeoutExceptionConversionWithExceptionDetails() { + TimeoutException exception = new TimeoutException("Operation timed out"); + + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_TRUE); // TimeoutException -> DEADLINE_EXCEEDED via direct gRPC mapping assertEquals(Status.DEADLINE_EXCEEDED.getCode(), result.getStatus().getCode()); @@ -199,7 +270,17 @@ public void testTimeoutExceptionConversion() { public void testInterruptedExceptionConversion() { InterruptedException exception = new InterruptedException(); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); + + // InterruptedException -> CANCELLED via direct gRPC mapping + assertEquals(Status.CANCELLED.getCode(), result.getStatus().getCode()); + assertTrue(result.getMessage().contains("CANCELLED")); + } + + public void testInterruptedExceptionConversionWithExceptionDetails() { + InterruptedException exception = new InterruptedException(); + + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_TRUE); // InterruptedException -> CANCELLED via direct gRPC mapping assertEquals(Status.CANCELLED.getCode(), result.getStatus().getCode()); @@ -210,7 +291,17 @@ public void testInterruptedExceptionConversion() { public void testIOExceptionConversion() { IOException exception = new IOException("I/O error"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); + + // IOException -> INTERNAL via direct gRPC mapping + assertEquals(Status.INTERNAL.getCode(), result.getStatus().getCode()); + assertTrue(result.getMessage().contains("INTERNAL: I/O error")); + } + + public void testIOExceptionConversionWithExceptionDetails() { + IOException exception = new IOException("I/O error"); + + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_TRUE); // IOException -> INTERNAL via direct gRPC mapping assertEquals(Status.INTERNAL.getCode(), result.getStatus().getCode()); @@ -221,7 +312,17 @@ public void testIOExceptionConversion() { public void testUnknownExceptionConversion() { RuntimeException exception = new RuntimeException("Unknown error"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); + + // RuntimeException -> INTERNAL via fallback (unknown exception type) + assertEquals(Status.INTERNAL.getCode(), result.getStatus().getCode()); + assertTrue(result.getMessage().contains("INTERNAL: Unknown error")); + } + + public void testUnknownExceptionConversionWithExceptionDetails() { + RuntimeException exception = new RuntimeException("Unknown error"); + + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_TRUE); // RuntimeException -> INTERNAL via fallback (unknown exception type) assertEquals(Status.INTERNAL.getCode(), result.getStatus().getCode()); @@ -237,7 +338,7 @@ public RestStatus status() { } }; - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // NOT_FOUND -> NOT_FOUND via RestToGrpcStatusConverter assertEquals(Status.NOT_FOUND.getCode(), result.getStatus().getCode()); @@ -249,7 +350,7 @@ public RestStatus status() { public void testCircuitBreakingExceptionInCleanMessage() { CircuitBreakingException exception = new CircuitBreakingException("Memory circuit breaker", 100, 90, null); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // CircuitBreakingException extends OpenSearchException with TOO_MANY_REQUESTS -> RESOURCE_EXHAUSTED assertEquals(Status.RESOURCE_EXHAUSTED.getCode(), result.getStatus().getCode()); @@ -265,7 +366,7 @@ public void testSearchPhaseExecutionExceptionInCleanMessage() { new org.opensearch.action.search.ShardSearchFailure[0] ); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // SearchPhaseExecutionException extends OpenSearchException with SERVICE_UNAVAILABLE -> UNAVAILABLE assertEquals(Status.UNAVAILABLE.getCode(), result.getStatus().getCode()); @@ -286,7 +387,7 @@ public RestStatus status() { }; exception.addMetadata("opensearch.test_key", "test_value"); - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // Should include metadata in JSON details assertTrue(result.getMessage().contains("details=")); @@ -312,7 +413,7 @@ public void metadataToXContent( } }; - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, FULL_STACK_TRACE_REQUESTED); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(exception, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // Should fall back to base description when XContent extraction fails assertEquals(Status.INVALID_ARGUMENT.getCode(), result.getStatus().getCode()); @@ -337,7 +438,7 @@ public RestStatus status() { } }; - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(wrappedException, FULL_STACK_TRACE_REQUESTED); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(wrappedException, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // Should include root_cause array like HTTP responses assertTrue(result.getMessage().contains("root_cause")); diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcParamsHandlerTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcParamsHandlerTests.java index a95cf918afb92..c44d165183369 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcParamsHandlerTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcParamsHandlerTests.java @@ -11,8 +11,8 @@ import org.opensearch.test.OpenSearchTestCase; import org.junit.After; -import static org.opensearch.transport.grpc.TestFixtures.ERROR_SUMMARY_REQUESTED; -import static org.opensearch.transport.grpc.TestFixtures.FULL_STACK_TRACE_REQUESTED; +import static org.opensearch.transport.grpc.TestFixtures.GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE; +import static org.opensearch.transport.grpc.TestFixtures.GLOBAL_PARAMS_WITH_ERROR_TRACE_TRUE; import static org.opensearch.transport.grpc.TestFixtures.settingsWithGivenStackTraceConfig; public class GrpcParamsHandlerTests extends OpenSearchTestCase { @@ -27,7 +27,7 @@ public void testValidationFailsWhenDetailedErrorsDisabledAndClientRequestedStack IllegalArgumentException exception = expectThrows( IllegalArgumentException.class, - () -> GrpcParamsHandler.validateStackTraceDetailsConfiguration(FULL_STACK_TRACE_REQUESTED) + () -> GrpcParamsHandler.validateStackTraceDetailsConfiguration(GLOBAL_PARAMS_WITH_ERROR_TRACE_TRUE) ); assertEquals("error traces in responses are disabled.", exception.getMessage()); } @@ -36,7 +36,7 @@ public void testValidationPassesWhenDetailedErrorsDisabledAndClientDoesNotReques GrpcParamsHandler.initialize(settingsWithGivenStackTraceConfig(false)); try { - GrpcParamsHandler.validateStackTraceDetailsConfiguration(ERROR_SUMMARY_REQUESTED); + GrpcParamsHandler.validateStackTraceDetailsConfiguration(GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); } catch (Exception e) { fail("Validation should pass without exceptions when stack traces are not requested."); } @@ -45,11 +45,11 @@ public void testValidationPassesWhenDetailedErrorsDisabledAndClientDoesNotReques public void testGrpcParamsHandlerPicksErrorTraceRequestParameter() { assertTrue( "Params handler must directly pick error_trace=true", - GrpcParamsHandler.isDetailedStackTraceRequested(FULL_STACK_TRACE_REQUESTED) + GrpcParamsHandler.isDetailedStackTraceRequested(GLOBAL_PARAMS_WITH_ERROR_TRACE_TRUE) ); assertFalse( "Params handler must directly pick error_trace=false", - GrpcParamsHandler.isDetailedStackTraceRequested(ERROR_SUMMARY_REQUESTED) + GrpcParamsHandler.isDetailedStackTraceRequested(GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE) ); } From 72138c16ce3df38a2418402f4803e401eeb0c874 Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Mon, 17 Nov 2025 18:04:34 +0100 Subject: [PATCH 18/28] Polishing Signed-off-by: Sergei Ustimenko --- ...ardOperationFailedExceptionProtoUtils.java | 6 ++- .../transport/grpc/util/GrpcErrorHandler.java | 40 ++++++++++++++----- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtils.java index bee4f7b22ae6e..af19f9a64b935 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtils.java @@ -41,7 +41,11 @@ public static ShardFailure toProto(DefaultShardOperationFailedException exceptio ShardFailure.Builder shardFailureBuilder = ShardFailure.newBuilder(); switch (exception) { - case AddIndexBlockResponse.AddBlockShardResult.Failure addBlockFailure -> innerToProto(shardFailureBuilder, addBlockFailure, params); + case AddIndexBlockResponse.AddBlockShardResult.Failure addBlockFailure -> innerToProto( + shardFailureBuilder, + addBlockFailure, + params + ); case IndicesShardStoresResponse.Failure indicesShardStoresFailure -> innerToProto( shardFailureBuilder, indicesShardStoresFailure, diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java index b3b42f62f03fe..8743879036e3d 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/util/GrpcErrorHandler.java @@ -67,43 +67,61 @@ public static StatusRuntimeException convertToGrpcError(Exception e, GlobalParam // ========== OpenSearch Core System Exceptions ========== // Low-level OpenSearch exceptions that don't extend OpenSearchException - include full details case OpenSearchRejectedExecutionException osree -> { - return Status.RESOURCE_EXHAUSTED.withDescription(getErrorDetailsForConfig(osree, shouldIncludeDetailedStackTrace)).asRuntimeException(); + return Status.RESOURCE_EXHAUSTED.withDescription(getErrorDetailsForConfig(osree, shouldIncludeDetailedStackTrace)) + .asRuntimeException(); } case NotXContentException notXContentException -> { - return Status.INVALID_ARGUMENT.withDescription(getErrorDetailsForConfig(notXContentException, shouldIncludeDetailedStackTrace)).asRuntimeException(); + return Status.INVALID_ARGUMENT.withDescription( + getErrorDetailsForConfig(notXContentException, shouldIncludeDetailedStackTrace) + ).asRuntimeException(); } case NotCompressedException notCompressedException -> { - return Status.INVALID_ARGUMENT.withDescription(getErrorDetailsForConfig(notCompressedException, shouldIncludeDetailedStackTrace)).asRuntimeException(); + return Status.INVALID_ARGUMENT.withDescription( + getErrorDetailsForConfig(notCompressedException, shouldIncludeDetailedStackTrace) + ).asRuntimeException(); } // ========== 3. Third-party Library Exceptions ========== // External library exceptions (Jackson JSON parsing) - include full details case InputCoercionException inputCoercionException -> { - return Status.INVALID_ARGUMENT.withDescription(getErrorDetailsForConfig(inputCoercionException, shouldIncludeDetailedStackTrace)).asRuntimeException(); + return Status.INVALID_ARGUMENT.withDescription( + getErrorDetailsForConfig(inputCoercionException, shouldIncludeDetailedStackTrace) + ).asRuntimeException(); } case JsonParseException jsonParseException -> { - return Status.INVALID_ARGUMENT.withDescription(getErrorDetailsForConfig(jsonParseException, shouldIncludeDetailedStackTrace)).asRuntimeException(); + return Status.INVALID_ARGUMENT.withDescription( + getErrorDetailsForConfig(jsonParseException, shouldIncludeDetailedStackTrace) + ).asRuntimeException(); } // ========== 4. Standard Java Exceptions ========== // Generic Java runtime exceptions - include full exception details for debugging case IllegalArgumentException illegalArgumentException -> { - return Status.INVALID_ARGUMENT.withDescription(getErrorDetailsForConfig(illegalArgumentException, shouldIncludeDetailedStackTrace)).asRuntimeException(); + return Status.INVALID_ARGUMENT.withDescription( + getErrorDetailsForConfig(illegalArgumentException, shouldIncludeDetailedStackTrace) + ).asRuntimeException(); } case IllegalStateException illegalStateException -> { - return Status.FAILED_PRECONDITION.withDescription(getErrorDetailsForConfig(illegalStateException, shouldIncludeDetailedStackTrace)).asRuntimeException(); + return Status.FAILED_PRECONDITION.withDescription( + getErrorDetailsForConfig(illegalStateException, shouldIncludeDetailedStackTrace) + ).asRuntimeException(); } case SecurityException securityException -> { - return Status.PERMISSION_DENIED.withDescription(getErrorDetailsForConfig(securityException, shouldIncludeDetailedStackTrace)).asRuntimeException(); + return Status.PERMISSION_DENIED.withDescription( + getErrorDetailsForConfig(securityException, shouldIncludeDetailedStackTrace) + ).asRuntimeException(); } case TimeoutException timeoutException -> { - return Status.DEADLINE_EXCEEDED.withDescription(getErrorDetailsForConfig(timeoutException, shouldIncludeDetailedStackTrace)).asRuntimeException(); + return Status.DEADLINE_EXCEEDED.withDescription(getErrorDetailsForConfig(timeoutException, shouldIncludeDetailedStackTrace)) + .asRuntimeException(); } case InterruptedException interruptedException -> { - return Status.CANCELLED.withDescription(getErrorDetailsForConfig(interruptedException, shouldIncludeDetailedStackTrace)).asRuntimeException(); + return Status.CANCELLED.withDescription(getErrorDetailsForConfig(interruptedException, shouldIncludeDetailedStackTrace)) + .asRuntimeException(); } case IOException ioException -> { - return Status.INTERNAL.withDescription(getErrorDetailsForConfig(ioException, shouldIncludeDetailedStackTrace)).asRuntimeException(); + return Status.INTERNAL.withDescription(getErrorDetailsForConfig(ioException, shouldIncludeDetailedStackTrace)) + .asRuntimeException(); } // ========== 5. Unknown/Unmapped Exceptions ========== From 1c05dc2306fa1559d8105fe8f81d31f4f96d83b5 Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Fri, 14 Nov 2025 14:38:27 +0100 Subject: [PATCH 19/28] Trigger CI because of flaky ChildQuerySearchIT Signed-off-by: Sergei Ustimenko From fef43c4cd5015941d03ef9304da1502a106fa9d2 Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Fri, 14 Nov 2025 16:59:39 +0100 Subject: [PATCH 20/28] Trigger CI again after flaky fail Signed-off-by: Sergei Ustimenko From 2f086023b435d12e218dc1ecdf0e05b90baa7d14 Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Fri, 14 Nov 2025 19:44:59 +0100 Subject: [PATCH 21/28] Rerun CI because of other flaky test Signed-off-by: Sergei Ustimenko From a5a64e34d9d517904716d3292c4f9bc1bfed798e Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Mon, 17 Nov 2025 20:24:49 +0100 Subject: [PATCH 22/28] Trigger CI Signed-off-by: Sergei Ustimenko From 8c8df9608df8b53c061c6b2887067fac05b17b8b Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Wed, 17 Dec 2025 14:48:32 +0100 Subject: [PATCH 23/28] Apply coderabbit suggestions Signed-off-by: Sergei Ustimenko --- CHANGELOG.md | 2 +- .../grpc/proto/response/search/SearchResponseProtoUtils.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f4463c491e00d..cf2d8a8d53f71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Add pluggable gRPC interceptors with explicit ordering([#19005](https://github.com/opensearch-project/OpenSearch/pull/19005)) - Add BindableServices extension point to transport-grpc-spi ([#19304](https://github.com/opensearch-project/OpenSearch/pull/19304)) - Add metrics for the merged segment warmer feature ([#18929](https://github.com/opensearch-project/OpenSearch/pull/18929)) -- Add handling for the global gRPC error_trace parameter ([#19644](https://github.com/opensearch-project/OpenSearch/pull/19644)) +- Add handling for the grpc.detailed_errors.enabled setting and global gRPC error_trace parameter ([#19644](https://github.com/opensearch-project/OpenSearch/pull/19644)) - Handle deleted documents for filter rewrite subaggregation optimization ([#19643](https://github.com/opensearch-project/OpenSearch/pull/19643)) - Handle deleted documents for filter rewrite sub-aggregation optimization ([#19643](https://github.com/opensearch-project/OpenSearch/pull/19643)) - Add bulk collect API for filter rewrite sub-aggregation optimization ([#19933](https://github.com/opensearch-project/OpenSearch/pull/19933)) diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtils.java index 9c0309a69b3e9..63af4dafda628 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/search/SearchResponseProtoUtils.java @@ -49,7 +49,7 @@ public static org.opensearch.protobufs.SearchResponse toProto(SearchResponse res * * @param response The SearchResponse to convert * @param searchResponseProtoBuilder The builder to populate with the SearchResponse data - * @param params + * @param params The global gRPC request parameters * @throws IOException if there's an error during conversion */ public static void toProto( From fa61c6f7b0975262179cc315b688224ed6ff4894 Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Wed, 17 Dec 2025 14:57:40 +0100 Subject: [PATCH 24/28] Rerun CI as Jenkins has a problem retrieving secrets from 1password Signed-off-by: Sergei Ustimenko From fac5c5e790c01fef513e625a7ff761a85f797450 Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Wed, 17 Dec 2025 15:02:06 +0100 Subject: [PATCH 25/28] Kill changelog entries dragged from the previous release Signed-off-by: Sergei Ustimenko --- CHANGELOG.md | 33 +-------------------------------- 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf2d8a8d53f71..8c574c1fe5cc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,40 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased 3.x] ### Added -- Allow setting index.creation_date on index creation and restore for plugin compatibility and migrations ([#19931](https://github.com/opensearch-project/OpenSearch/pull/19931)) -- Add support for a ForkJoinPool type ([#19008](https://github.com/opensearch-project/OpenSearch/pull/19008)) -- Add seperate shard limit validation for local and remote indices ([#19532](https://github.com/opensearch-project/OpenSearch/pull/19532)) -- Use Lucene `pack` method for `half_float` and `usigned_long` when using `ApproximatePointRangeQuery`. -- Add a mapper for context aware segments grouping criteria ([#19233](https://github.com/opensearch-project/OpenSearch/pull/19233)) -- Return full error for GRPC error response ([#19568](https://github.com/opensearch-project/OpenSearch/pull/19568)) -- Add support for repository with Server side encryption enabled and client side encryption as well based on a flag. ([#19630)](https://github.com/opensearch-project/OpenSearch/pull/19630)) -- Add pluggable gRPC interceptors with explicit ordering([#19005](https://github.com/opensearch-project/OpenSearch/pull/19005)) -- Add BindableServices extension point to transport-grpc-spi ([#19304](https://github.com/opensearch-project/OpenSearch/pull/19304)) -- Add metrics for the merged segment warmer feature ([#18929](https://github.com/opensearch-project/OpenSearch/pull/18929)) -- Add handling for the grpc.detailed_errors.enabled setting and global gRPC error_trace parameter ([#19644](https://github.com/opensearch-project/OpenSearch/pull/19644)) -- Handle deleted documents for filter rewrite subaggregation optimization ([#19643](https://github.com/opensearch-project/OpenSearch/pull/19643)) -- Handle deleted documents for filter rewrite sub-aggregation optimization ([#19643](https://github.com/opensearch-project/OpenSearch/pull/19643)) -- Add bulk collect API for filter rewrite sub-aggregation optimization ([#19933](https://github.com/opensearch-project/OpenSearch/pull/19933)) -- Allow collectors take advantage of preaggregated data using collectRange API ([#20009](https://github.com/opensearch-project/OpenSearch/pull/20009)) -- Bulk collection logic for metrics and cardinality aggregations ([#20067](https://github.com/opensearch-project/OpenSearch/pull/20067)) -- Add pointer based lag metric in pull-based ingestion ([#19635](https://github.com/opensearch-project/OpenSearch/pull/19635)) -- Introduced internal API for retrieving metadata about requested indices from transport actions ([#18523](https://github.com/opensearch-project/OpenSearch/pull/18523)) -- Add cluster defaults for merge autoThrottle, maxMergeThreads, and maxMergeCount; Add segment size filter to the merged segment warmer ([#19629](https://github.com/opensearch-project/OpenSearch/pull/19629)) -- Add build-tooling to run in FIPS environment ([#18921](https://github.com/opensearch-project/OpenSearch/pull/18921)) -- Add SMILE/CBOR/YAML document format support to Bulk GRPC endpoint ([#19744](https://github.com/opensearch-project/OpenSearch/pull/19744)) -- Make test-suite runnable under FIPS compliance support ([#18491](https://github.com/opensearch-project/OpenSearch/pull/18491)) -- Implement GRPC Search params `Highlight`and `Sort` ([#19868](https://github.com/opensearch-project/OpenSearch/pull/19868)) -- Implement GRPC ConstantScoreQuery, FuzzyQuery, MatchBoolPrefixQuery, MatchPhrasePrefix, PrefixQuery, MatchQuery ([#19854](https://github.com/opensearch-project/OpenSearch/pull/19854)) -- Add async periodic flush task support for pull-based ingestion ([#19878](https://github.com/opensearch-project/OpenSearch/pull/19878)) -- Add support for context aware segments ([#19098](https://github.com/opensearch-project/OpenSearch/pull/19098)) -- Implement GRPC FunctionScoreQuery ([#19888](https://github.com/opensearch-project/OpenSearch/pull/19888)) -- Implement error_trace parameter for bulk requests ([#19985](https://github.com/opensearch-project/OpenSearch/pull/19985)) -- Allow the truncate filter in normalizers ([#19778](https://github.com/opensearch-project/OpenSearch/issues/19778)) -- Support pull-based ingestion message mappers and raw payload support ([#19765](https://github.com/opensearch-project/OpenSearch/pull/19765)) -- Add search API tracker ([#18601](https://github.com/opensearch-project/OpenSearch/pull/18601)) -- Support dynamic consumer configuration update in pull-based ingestion ([#19963](https://github.com/opensearch-project/OpenSearch/pull/19963)) - Add support for forward translog reading ([#20163](https://github.com/opensearch-project/OpenSearch/pull/20163)) - Added public getter method in `SourceFieldMapper` to return excluded field ([#20205](https://github.com/opensearch-project/OpenSearch/pull/20205)) +- Add handling for the grpc.detailed_errors.enabled setting and global gRPC error_trace parameter ([#19644](https://github.com/opensearch-project/OpenSearch/pull/19644)) ### Changed - Handle custom metadata files in subdirectory-store ([#20157](https://github.com/opensearch-project/OpenSearch/pull/20157)) From dac36944c362530e8da6277f20d275636cd51076 Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Wed, 17 Dec 2025 15:21:57 +0100 Subject: [PATCH 26/28] Integrate latest changes regarding global_param validation Signed-off-by: Sergei Ustimenko --- .../proto/request/document/bulk/BulkRequestProtoUtils.java | 7 ++++--- .../grpc/proto/request/search/SearchRequestProtoUtils.java | 6 +++--- .../request/document/bulk/BulkRequestProtoUtilsTests.java | 5 +++-- .../proto/request/search/SearchRequestProtoUtilsTests.java | 4 ++-- ...efaultShardOperationFailedExceptionProtoUtilsTests.java | 2 +- .../ShardOperationFailedExceptionProtoUtilsTests.java | 2 +- .../transport/grpc/util/GrpcErrorHandlerTests.java | 2 +- 7 files changed, 15 insertions(+), 13 deletions(-) diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/request/document/bulk/BulkRequestProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/request/document/bulk/BulkRequestProtoUtils.java index 85e9ab47d873c..9420965cab05a 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/request/document/bulk/BulkRequestProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/request/document/bulk/BulkRequestProtoUtils.java @@ -10,6 +10,7 @@ import org.opensearch.action.bulk.BulkShardRequest; import org.opensearch.protobufs.BulkRequest; +import org.opensearch.protobufs.GlobalParams; import org.opensearch.rest.RestRequest; import org.opensearch.rest.action.document.RestBulkAction; import org.opensearch.search.fetch.subphase.FetchSourceContext; @@ -90,9 +91,9 @@ public static org.opensearch.action.bulk.BulkRequest prepareRequest(BulkRequest throw new UnsupportedOperationException("type param is not supported"); } - // TODO support global_params - if (request.hasGlobalParams()) { - throw new UnsupportedOperationException("global_params param is not supported yet"); + // TODO support global_params.human parameter + if (request.getGlobalParams().hasHuman()) { + throw new UnsupportedOperationException("global_params.human param is not supported yet"); } return bulkRequest; diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/request/search/SearchRequestProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/request/search/SearchRequestProtoUtils.java index 0473c46c3156e..36af780aa7729 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/request/search/SearchRequestProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/request/search/SearchRequestProtoUtils.java @@ -189,9 +189,9 @@ protected static void parseSearchRequest( throw new UnsupportedOperationException("typed_keys param is not supported yet"); } - // TODO support global_params - if (request.hasGlobalParams()) { - throw new UnsupportedOperationException("global_params param is not supported yet"); + // TODO support global_params.human parameter + if (request.getGlobalParams().hasHuman()) { + throw new UnsupportedOperationException("global_params.human param is not supported yet"); } } diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/request/document/bulk/BulkRequestProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/request/document/bulk/BulkRequestProtoUtilsTests.java index 699ab999a40c9..ab81077a674ec 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/request/document/bulk/BulkRequestProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/request/document/bulk/BulkRequestProtoUtilsTests.java @@ -142,7 +142,8 @@ public void testPrepareRequestWithTypeThrowsUnsupportedOperationException() { public void testPrepareRequestWithGlobalParamsThrowsUnsupportedOperationException() { // Create a protobuf BulkRequest with global_params - BulkRequest request = BulkRequest.newBuilder().setGlobalParams(org.opensearch.protobufs.GlobalParams.newBuilder().build()).build(); + BulkRequest request = BulkRequest.newBuilder().setGlobalParams( + org.opensearch.protobufs.GlobalParams.newBuilder().setHuman(true).build()).build(); // Call prepareRequest, should throw UnsupportedOperationException UnsupportedOperationException exception = expectThrows( @@ -150,6 +151,6 @@ public void testPrepareRequestWithGlobalParamsThrowsUnsupportedOperationExceptio () -> BulkRequestProtoUtils.prepareRequest(request) ); - assertEquals("global_params param is not supported yet", exception.getMessage()); + assertEquals("global_params.human param is not supported yet", exception.getMessage()); } } diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/request/search/SearchRequestProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/request/search/SearchRequestProtoUtilsTests.java index 2faddbdbcc4ea..4dead6f37fcac 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/request/search/SearchRequestProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/request/search/SearchRequestProtoUtilsTests.java @@ -409,7 +409,7 @@ public void testParseSearchRequestWithTypedKeysThrowsUnsupportedOperationExcepti public void testParseSearchRequestWithGlobalParamsThrowsUnsupportedOperationException() throws IOException { // Create a protobuf SearchRequest with global_params org.opensearch.protobufs.SearchRequest protoRequest = org.opensearch.protobufs.SearchRequest.newBuilder() - .setGlobalParams(org.opensearch.protobufs.GlobalParams.newBuilder().build()) + .setGlobalParams(org.opensearch.protobufs.GlobalParams.newBuilder().setHuman(true).build()) .build(); // Create a SearchRequest to populate @@ -421,7 +421,7 @@ public void testParseSearchRequestWithGlobalParamsThrowsUnsupportedOperationExce () -> SearchRequestProtoUtils.parseSearchRequest(searchRequest, protoRequest, namedWriteableRegistry, size -> {}, queryUtils) ); - assertEquals("global_params param is not supported yet", exception.getMessage()); + assertEquals("global_params.human param is not supported yet", exception.getMessage()); } } diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtilsTests.java index aa24160da0599..567ffcbb39dd5 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/DefaultShardOperationFailedExceptionProtoUtilsTests.java @@ -126,7 +126,7 @@ public void testToProtoWithNullNodeId() throws IOException { } public void testToProtoWithNull() throws IOException { - ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(null); + ShardFailure shardFailure = DefaultShardOperationFailedExceptionProtoUtils.toProto(null, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); assertNotNull("ShardFailure should not be null", shardFailure); assertFalse("Index should not be set", shardFailure.hasIndex()); assertFalse("Status should not be set", shardFailure.hasStatus()); diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtilsTests.java index 42ba1d69db331..299313231fd7b 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/ShardOperationFailedExceptionProtoUtilsTests.java @@ -137,7 +137,7 @@ public void testToProtoWithNullShardOperationFailedException() { // Call the method under test with null, should throw UnsupportedOperationException UnsupportedOperationException exception = expectThrows( UnsupportedOperationException.class, - () -> ShardOperationFailedExceptionProtoUtils.toProto(null) + () -> ShardOperationFailedExceptionProtoUtils.toProto(null, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE) ); assertEquals("Unsupported ShardOperationFailedException [null] cannot be converted to proto.", exception.getMessage()); diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcErrorHandlerTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcErrorHandlerTests.java index 3e6cda7621aba..56c02b495eb32 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcErrorHandlerTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/util/GrpcErrorHandlerTests.java @@ -447,7 +447,7 @@ public RestStatus status() { } public void testNullExceptionConversion() { - StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(null); + StatusRuntimeException result = GrpcErrorHandler.convertToGrpcError(null, GLOBAL_PARAMS_WITH_ERROR_TRACE_FALSE); // null -> INTERNAL via case null handling assertEquals(Status.INTERNAL.getCode(), result.getStatus().getCode()); From 769cdff58b40c7e01c7bc3b8b304c3ff7c1367e2 Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Wed, 17 Dec 2025 15:34:56 +0100 Subject: [PATCH 27/28] Apply spotless Signed-off-by: Sergei Ustimenko --- .../proto/request/document/bulk/BulkRequestProtoUtils.java | 1 - .../request/document/bulk/BulkRequestProtoUtilsTests.java | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/request/document/bulk/BulkRequestProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/request/document/bulk/BulkRequestProtoUtils.java index 9420965cab05a..5949b33786d13 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/request/document/bulk/BulkRequestProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/request/document/bulk/BulkRequestProtoUtils.java @@ -10,7 +10,6 @@ import org.opensearch.action.bulk.BulkShardRequest; import org.opensearch.protobufs.BulkRequest; -import org.opensearch.protobufs.GlobalParams; import org.opensearch.rest.RestRequest; import org.opensearch.rest.action.document.RestBulkAction; import org.opensearch.search.fetch.subphase.FetchSourceContext; diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/request/document/bulk/BulkRequestProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/request/document/bulk/BulkRequestProtoUtilsTests.java index ab81077a674ec..a1c1e25ea3ed9 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/request/document/bulk/BulkRequestProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/request/document/bulk/BulkRequestProtoUtilsTests.java @@ -142,8 +142,9 @@ public void testPrepareRequestWithTypeThrowsUnsupportedOperationException() { public void testPrepareRequestWithGlobalParamsThrowsUnsupportedOperationException() { // Create a protobuf BulkRequest with global_params - BulkRequest request = BulkRequest.newBuilder().setGlobalParams( - org.opensearch.protobufs.GlobalParams.newBuilder().setHuman(true).build()).build(); + BulkRequest request = BulkRequest.newBuilder() + .setGlobalParams(org.opensearch.protobufs.GlobalParams.newBuilder().setHuman(true).build()) + .build(); // Call prepareRequest, should throw UnsupportedOperationException UnsupportedOperationException exception = expectThrows( From 0722de86ddd4acb84999e4eb47e72a5a2422bbe5 Mon Sep 17 00:00:00 2001 From: Sergei Ustimenko Date: Mon, 29 Dec 2025 22:09:13 +0100 Subject: [PATCH 28/28] Review comments Signed-off-by: Sergei Ustimenko --- .../request/document/bulk/BulkRequestProtoUtils.java | 8 +++++--- .../proto/request/search/SearchRequestProtoUtils.java | 8 +++++--- .../SnapshotShardFailureProtoUtils.java | 4 +--- .../request/document/bulk/BulkRequestProtoUtilsTests.java | 2 +- .../request/search/SearchRequestProtoUtilsTests.java | 2 +- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/request/document/bulk/BulkRequestProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/request/document/bulk/BulkRequestProtoUtils.java index 5949b33786d13..248663289feb8 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/request/document/bulk/BulkRequestProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/request/document/bulk/BulkRequestProtoUtils.java @@ -10,6 +10,7 @@ import org.opensearch.action.bulk.BulkShardRequest; import org.opensearch.protobufs.BulkRequest; +import org.opensearch.protobufs.GlobalParams; import org.opensearch.rest.RestRequest; import org.opensearch.rest.action.document.RestBulkAction; import org.opensearch.search.fetch.subphase.FetchSourceContext; @@ -90,9 +91,10 @@ public static org.opensearch.action.bulk.BulkRequest prepareRequest(BulkRequest throw new UnsupportedOperationException("type param is not supported"); } - // TODO support global_params.human parameter - if (request.getGlobalParams().hasHuman()) { - throw new UnsupportedOperationException("global_params.human param is not supported yet"); + // TODO support global_params parameters + GlobalParams params = request.getGlobalParams(); + if (params.hasHuman() || params.getFilterPathCount() > 0) { + throw new UnsupportedOperationException("global_params.human or filter_path params are not supported yet"); } return bulkRequest; diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/request/search/SearchRequestProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/request/search/SearchRequestProtoUtils.java index 36af780aa7729..3ca0612b98016 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/request/search/SearchRequestProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/request/search/SearchRequestProtoUtils.java @@ -15,6 +15,7 @@ import org.opensearch.core.common.io.stream.NamedWriteableRegistry; import org.opensearch.core.xcontent.XContentParser; import org.opensearch.index.query.QueryBuilder; +import org.opensearch.protobufs.GlobalParams; import org.opensearch.protobufs.SearchRequest; import org.opensearch.protobufs.SearchRequestBody; import org.opensearch.rest.RestRequest; @@ -189,9 +190,10 @@ protected static void parseSearchRequest( throw new UnsupportedOperationException("typed_keys param is not supported yet"); } - // TODO support global_params.human parameter - if (request.getGlobalParams().hasHuman()) { - throw new UnsupportedOperationException("global_params.human param is not supported yet"); + // TODO support global_params parameters + GlobalParams params = request.getGlobalParams(); + if (params.hasHuman() || params.getFilterPathCount() > 0) { + throw new UnsupportedOperationException("global_params.human or filter_path params are not supported yet"); } } diff --git a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/SnapshotShardFailureProtoUtils.java b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/SnapshotShardFailureProtoUtils.java index de7857fd578ad..f366f3b48a860 100644 --- a/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/SnapshotShardFailureProtoUtils.java +++ b/modules/transport-grpc/src/main/java/org/opensearch/transport/grpc/proto/response/exceptions/shardoperationfailedexception/SnapshotShardFailureProtoUtils.java @@ -35,9 +35,7 @@ private SnapshotShardFailureProtoUtils() { */ public static ShardFailure toProto(SnapshotShardFailure exception, GlobalParams params) throws IOException { ShardFailure.Builder shardFailure = ShardFailure.newBuilder(); - if (exception.index() != null) { - shardFailure.setIndex(exception.index()); - } + shardFailure.setIndex(exception.index()); // shardFailure.setIndexUuid(exception.index()); // TODO no field called index_uuid in ShardFailure protos shardFailure.setShard(exception.shardId()); if (exception.nodeId() != null) { diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/request/document/bulk/BulkRequestProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/request/document/bulk/BulkRequestProtoUtilsTests.java index a1c1e25ea3ed9..a5b8128bc255b 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/request/document/bulk/BulkRequestProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/request/document/bulk/BulkRequestProtoUtilsTests.java @@ -152,6 +152,6 @@ public void testPrepareRequestWithGlobalParamsThrowsUnsupportedOperationExceptio () -> BulkRequestProtoUtils.prepareRequest(request) ); - assertEquals("global_params.human param is not supported yet", exception.getMessage()); + assertEquals("global_params.human or filter_path params are not supported yet", exception.getMessage()); } } diff --git a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/request/search/SearchRequestProtoUtilsTests.java b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/request/search/SearchRequestProtoUtilsTests.java index 4dead6f37fcac..17ae549d9e00e 100644 --- a/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/request/search/SearchRequestProtoUtilsTests.java +++ b/modules/transport-grpc/src/test/java/org/opensearch/transport/grpc/proto/request/search/SearchRequestProtoUtilsTests.java @@ -421,7 +421,7 @@ public void testParseSearchRequestWithGlobalParamsThrowsUnsupportedOperationExce () -> SearchRequestProtoUtils.parseSearchRequest(searchRequest, protoRequest, namedWriteableRegistry, size -> {}, queryUtils) ); - assertEquals("global_params.human param is not supported yet", exception.getMessage()); + assertEquals("global_params.human or filter_path params are not supported yet", exception.getMessage()); } }