From 6c930de7d35989957f5c5b18d1b3fb937d9727ff Mon Sep 17 00:00:00 2001 From: Kamil Sobol <61715331+kasobol-msft@users.noreply.github.com> Date: Mon, 7 Feb 2022 17:05:11 -0800 Subject: [PATCH] Add Traits to Search builders. (#26907) * Update Log4j to 2.17.0 * search * fix build. --- .../checkstyle/checkstyle-suppressions.xml | 2 +- .../azure-search-documents/CHANGELOG.md | 2 + .../search/documents/SearchClientBuilder.java | 131 +++++++++++++++--- .../implementation/util/Utility.java | 11 +- .../indexes/SearchIndexClientBuilder.java | 127 ++++++++++++++--- .../indexes/SearchIndexerClientBuilder.java | 130 ++++++++++++++--- .../documents/SearchClientBuilderTests.java | 14 ++ .../SearchIndexClientBuilderTests.java | 13 ++ .../SearchIndexerClientBuilderTests.java | 13 ++ 9 files changed, 380 insertions(+), 63 deletions(-) diff --git a/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml b/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml index 4d8be3b0d97b1..4e8cf129ab7f3 100755 --- a/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml +++ b/eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml @@ -421,7 +421,7 @@ the main ServiceBusClientBuilder. --> + lines="481,515,529"/> diff --git a/sdk/search/azure-search-documents/CHANGELOG.md b/sdk/search/azure-search-documents/CHANGELOG.md index 7d0ae5f12beca..0f65eb2c6684c 100644 --- a/sdk/search/azure-search-documents/CHANGELOG.md +++ b/sdk/search/azure-search-documents/CHANGELOG.md @@ -3,6 +3,8 @@ ## 11.5.0-beta.6 (Unreleased) ### Features Added +- Added interfaces from `com.azure.core.client.traits` to `SearchIndexerClientBuilder`, `SearchIndexClientBuilder` + and `SearchClientBuilder` ### Breaking Changes diff --git a/sdk/search/azure-search-documents/src/main/java/com/azure/search/documents/SearchClientBuilder.java b/sdk/search/azure-search-documents/src/main/java/com/azure/search/documents/SearchClientBuilder.java index e20d35b5c947f..d4ffeb389c4af 100644 --- a/sdk/search/azure-search-documents/src/main/java/com/azure/search/documents/SearchClientBuilder.java +++ b/sdk/search/azure-search-documents/src/main/java/com/azure/search/documents/SearchClientBuilder.java @@ -4,17 +4,25 @@ package com.azure.search.documents; import com.azure.core.annotation.ServiceClientBuilder; +import com.azure.core.client.traits.AzureKeyCredentialTrait; +import com.azure.core.client.traits.ConfigurationTrait; +import com.azure.core.client.traits.EndpointTrait; +import com.azure.core.client.traits.HttpTrait; +import com.azure.core.client.traits.TokenCredentialTrait; import com.azure.core.credential.AzureKeyCredential; import com.azure.core.credential.TokenCredential; import com.azure.core.http.HttpClient; import com.azure.core.http.HttpPipeline; import com.azure.core.http.HttpPipelinePosition; +import com.azure.core.http.policy.HttpLogDetailLevel; import com.azure.core.http.policy.HttpLogOptions; import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.core.http.policy.RetryOptions; import com.azure.core.http.policy.RetryPolicy; import com.azure.core.util.ClientOptions; import com.azure.core.util.Configuration; import com.azure.core.util.CoreUtils; +import com.azure.core.util.HttpClientOptions; import com.azure.core.util.logging.ClientLogger; import com.azure.core.util.serializer.JsonSerializer; import com.azure.core.util.serializer.TypeReference; @@ -78,7 +86,12 @@ * @see SearchAsyncClient */ @ServiceClientBuilder(serviceClients = {SearchClient.class, SearchAsyncClient.class}) -public final class SearchClientBuilder { +public final class SearchClientBuilder implements + AzureKeyCredentialTrait, + ConfigurationTrait, + EndpointTrait, + HttpTrait, + TokenCredentialTrait { private static final boolean DEFAULT_AUTO_FLUSH = true; private static final int DEFAULT_INITIAL_BATCH_ACTION_COUNT = 512; private static final Duration DEFAULT_FLUSH_INTERVAL = Duration.ofSeconds(60); @@ -111,6 +124,7 @@ public final class SearchClientBuilder { private Configuration configuration; private String indexName; private RetryPolicy retryPolicy; + private RetryOptions retryOptions; private JsonSerializer jsonSerializer; /** @@ -130,6 +144,8 @@ public SearchClientBuilder() { * * @return A SearchClient with the options set from the builder. * @throws NullPointerException If {@code indexName} or {@code endpoint} are null. + * @throws IllegalStateException If both {@link #retryOptions(RetryOptions)} + * and {@link #retryPolicy(RetryPolicy)} have been set. */ public SearchClient buildClient() { return new SearchClient(buildAsyncClient()); @@ -145,6 +161,8 @@ public SearchClient buildClient() { * * @return A SearchClient with the options set from the builder. * @throws NullPointerException If {@code indexName} or {@code endpoint} are null. + * @throws IllegalStateException If both {@link #retryOptions(RetryOptions)} + * and {@link #retryPolicy(RetryPolicy)} have been set. */ public SearchAsyncClient buildAsyncClient() { validateIndexNameAndEndpoint(); @@ -180,7 +198,7 @@ private HttpPipeline getHttpPipeline() { return httpPipeline; } - return Utility.buildHttpPipeline(clientOptions, httpLogOptions, configuration, retryPolicy, + return Utility.buildHttpPipeline(clientOptions, httpLogOptions, configuration, retryPolicy, retryOptions, azureKeyCredential, tokenCredential, perCallPolicies, perRetryPolicies, httpClient, logger); } @@ -191,6 +209,7 @@ private HttpPipeline getHttpPipeline() { * @return The updated SearchClientBuilder object. * @throws IllegalArgumentException If {@code endpoint} is null or it cannot be parsed into a valid URL. */ + @Override public SearchClientBuilder endpoint(String endpoint) { try { new URL(endpoint); @@ -207,17 +226,21 @@ public SearchClientBuilder endpoint(String endpoint) { * @param credential The {@link AzureKeyCredential} used to authenticate HTTP requests. * @return The updated SearchClientBuilder object. */ + @Override public SearchClientBuilder credential(AzureKeyCredential credential) { this.azureKeyCredential = credential; return this; } /** - * Sets the {@link TokenCredential} used to authenticate HTTP requests. + * Sets the {@link TokenCredential} used to authorize requests sent to the service. Refer to the Azure SDK for Java + * identity and authentication + * documentation for more details on proper usage of the {@link TokenCredential} type. * - * @param credential The {@link TokenCredential} used to authenticate HTTP requests. + * @param credential {@link TokenCredential} used to authorize requests sent to the service. * @return The updated SearchClientBuilder object. */ + @Override public SearchClientBuilder credential(TokenCredential credential) { this.tokenCredential = credential; return this; @@ -239,13 +262,21 @@ public SearchClientBuilder indexName(String indexName) { } /** - * Sets the logging configuration for HTTP requests and responses. - *

- * If logging configurations aren't provided HTTP requests and responses won't be logged. + * Sets the {@link HttpLogOptions logging configuration} to use when sending and receiving requests to and from + * the service. If a {@code logLevel} is not provided, default value of {@link HttpLogDetailLevel#NONE} is set. + * + *

Note: It is important to understand the precedence order of the HttpTrait APIs. In + * particular, if a {@link HttpPipeline} is specified, this takes precedence over all other APIs in the trait, and + * they will be ignored. If no {@link HttpPipeline} is specified, a HTTP pipeline will be constructed internally + * based on the settings provided to this trait. Additionally, there may be other APIs in types that implement this + * trait that are also ignored if an {@link HttpPipeline} is specified, so please be sure to refer to the + * documentation of types that implement this trait to understand the full set of implications.

* - * @param logOptions The logging configuration for HTTP requests and responses. + * @param logOptions The {@link HttpLogOptions logging configuration} to use when sending and receiving requests to + * and from the service. * @return The updated SearchClientBuilder object. */ + @Override public SearchClientBuilder httpLogOptions(HttpLogOptions logOptions) { httpLogOptions = logOptions; return this; @@ -261,26 +292,44 @@ public static HttpLogOptions getDefaultLogOptions() { } /** - * Sets the client options such as application ID and custom headers to set on a request. + * Allows for setting common properties such as application ID, headers, proxy configuration, etc. Note that it is + * recommended that this method be called with an instance of the {@link HttpClientOptions} + * class (a subclass of the {@link ClientOptions} base class). The HttpClientOptions subclass provides more + * configuration options suitable for HTTP clients, which is applicable for any class that implements this HttpTrait + * interface. + * + *

Note: It is important to understand the precedence order of the HttpTrait APIs. In + * particular, if a {@link HttpPipeline} is specified, this takes precedence over all other APIs in the trait, and + * they will be ignored. If no {@link HttpPipeline} is specified, a HTTP pipeline will be constructed internally + * based on the settings provided to this trait. Additionally, there may be other APIs in types that implement this + * trait that are also ignored if an {@link HttpPipeline} is specified, so please be sure to refer to the + * documentation of types that implement this trait to understand the full set of implications.

* - * @param clientOptions The client options. + * @param clientOptions A configured instance of {@link HttpClientOptions}. * @return The updated SearchClientBuilder object. + * @see HttpClientOptions */ + @Override public SearchClientBuilder clientOptions(ClientOptions clientOptions) { this.clientOptions = clientOptions; return this; } /** - * Adds a pipeline policy to apply to each request sent. - *

- * This method may be called multiple times, each time it is called the policy will be added to the end of added - * policy list. All policies will be added after the retry policy. + * Adds a {@link HttpPipelinePolicy pipeline policy} to apply on each request sent. + * + *

Note: It is important to understand the precedence order of the HttpTrait APIs. In + * particular, if a {@link HttpPipeline} is specified, this takes precedence over all other APIs in the trait, and + * they will be ignored. If no {@link HttpPipeline} is specified, a HTTP pipeline will be constructed internally + * based on the settings provided to this trait. Additionally, there may be other APIs in types that implement this + * trait that are also ignored if an {@link HttpPipeline} is specified, so please be sure to refer to the + * documentation of types that implement this trait to understand the full set of implications.

* - * @param policy The pipeline policies to added to the policy list. + * @param policy A {@link HttpPipelinePolicy pipeline policy}. * @return The updated SearchClientBuilder object. * @throws NullPointerException If {@code policy} is null. */ + @Override public SearchClientBuilder addPolicy(HttpPipelinePolicy policy) { Objects.requireNonNull(policy, "'policy' cannot be null."); @@ -306,11 +355,19 @@ public SearchClientBuilder serializer(JsonSerializer jsonSerializer) { } /** - * Sets the HTTP client to use for sending requests and receiving responses. + * Sets the {@link HttpClient} to use for sending and receiving requests to and from the service. * - * @param client The HTTP client that will handle sending requests and receiving responses. + *

Note: It is important to understand the precedence order of the HttpTrait APIs. In + * particular, if a {@link HttpPipeline} is specified, this takes precedence over all other APIs in the trait, and + * they will be ignored. If no {@link HttpPipeline} is specified, a HTTP pipeline will be constructed internally + * based on the settings provided to this trait. Additionally, there may be other APIs in types that implement this + * trait that are also ignored if an {@link HttpPipeline} is specified, so please be sure to refer to the + * documentation of types that implement this trait to understand the full set of implications.

+ * + * @param client The {@link HttpClient} to use for requests. * @return The updated SearchClientBuilder object. */ + @Override public SearchClientBuilder httpClient(HttpClient client) { if (this.httpClient != null && client == null) { logger.info("HttpClient is being set to 'null' when it was previously configured."); @@ -321,14 +378,22 @@ public SearchClientBuilder httpClient(HttpClient client) { } /** - * Sets the HTTP pipeline to use for the service client. + * Sets the {@link HttpPipeline} to use for the service client. + * + *

Note: It is important to understand the precedence order of the HttpTrait APIs. In + * particular, if a {@link HttpPipeline} is specified, this takes precedence over all other APIs in the trait, and + * they will be ignored. If no {@link HttpPipeline} is specified, a HTTP pipeline will be constructed internally + * based on the settings provided to this trait. Additionally, there may be other APIs in types that implement this + * trait that are also ignored if an {@link HttpPipeline} is specified, so please be sure to refer to the + * documentation of types that implement this trait to understand the full set of implications.

*

* If {@code pipeline} is set, all other settings are ignored, aside from {@link #endpoint(String) endpoint} and * {@link #indexName(String) index} when building a {@link SearchClient} or {@link SearchAsyncClient}. * - * @param httpPipeline The HTTP pipeline to use for sending service requests and receiving responses. + * @param httpPipeline {@link HttpPipeline} to use for sending service requests and receiving responses. * @return The updated SearchClientBuilder object. */ + @Override public SearchClientBuilder pipeline(HttpPipeline httpPipeline) { if (this.httpPipeline != null && httpPipeline == null) { logger.info("HttpPipeline is being set to 'null' when it was previously configured."); @@ -347,6 +412,7 @@ public SearchClientBuilder pipeline(HttpPipeline httpPipeline) { * @param configuration The configuration store that will be used. * @return The updated SearchClientBuilder object. */ + @Override public SearchClientBuilder configuration(Configuration configuration) { this.configuration = configuration; return this; @@ -356,6 +422,8 @@ public SearchClientBuilder configuration(Configuration configuration) { * Sets the {@link HttpPipelinePolicy} that will attempt to retry requests when needed. *

* A default retry policy will be supplied if one isn't provided. + *

+ * Setting this is mutually exclusive with using {@link #retryOptions(RetryOptions)}. * * @param retryPolicy The {@link RetryPolicy} that will attempt to retry requests when needed. * @return The updated SearchClientBuilder object. @@ -365,6 +433,27 @@ public SearchClientBuilder retryPolicy(RetryPolicy retryPolicy) { return this; } + /** + * Sets the {@link RetryOptions} for all the requests made through the client. + * + *

Note: It is important to understand the precedence order of the HttpTrait APIs. In + * particular, if a {@link HttpPipeline} is specified, this takes precedence over all other APIs in the trait, and + * they will be ignored. If no {@link HttpPipeline} is specified, a HTTP pipeline will be constructed internally + * based on the settings provided to this trait. Additionally, there may be other APIs in types that implement this + * trait that are also ignored if an {@link HttpPipeline} is specified, so please be sure to refer to the + * documentation of types that implement this trait to understand the full set of implications.

+ *

+ * Setting this is mutually exclusive with using {@link #retryPolicy(RetryPolicy)}. + * + * @param retryOptions The {@link RetryOptions} to use for all the requests made through the client. + * @return The updated SearchClientBuilder object. + */ + @Override + public SearchClientBuilder retryOptions(RetryOptions retryOptions) { + this.retryOptions = retryOptions; + return this; + } + /** * Sets the {@link SearchServiceVersion} that is used when making API requests. *

@@ -420,6 +509,8 @@ private SearchIndexingBufferedSenderBuilder() { * @return A SearchIndexingBufferedSender with the options set from the builder. * @throws NullPointerException If {@code indexName}, {@code endpoint}, or {@code documentKeyRetriever} are * null. + * @throws IllegalStateException If both {@link #retryOptions(RetryOptions)} + * and {@link #retryPolicy(RetryPolicy)} have been set. */ public SearchIndexingBufferedSender buildSender() { return new SearchIndexingBufferedSender<>(buildAsyncSender()); @@ -432,6 +523,8 @@ public SearchIndexingBufferedSender buildSender() { * @return A SearchIndexingBufferedAsyncSender with the options set from the builder. * @throws NullPointerException If {@code indexName}, {@code endpoint}, or {@code documentKeyRetriever} are * null. + * @throws IllegalStateException If both {@link #retryOptions(RetryOptions)} + * and {@link #retryPolicy(RetryPolicy)} have been set. */ public SearchIndexingBufferedAsyncSender buildAsyncSender() { validateIndexNameAndEndpoint(); diff --git a/sdk/search/azure-search-documents/src/main/java/com/azure/search/documents/implementation/util/Utility.java b/sdk/search/azure-search-documents/src/main/java/com/azure/search/documents/implementation/util/Utility.java index 9c305dc3aca07..1bfefc0c72ccd 100644 --- a/sdk/search/azure-search-documents/src/main/java/com/azure/search/documents/implementation/util/Utility.java +++ b/sdk/search/azure-search-documents/src/main/java/com/azure/search/documents/implementation/util/Utility.java @@ -19,6 +19,7 @@ import com.azure.core.http.policy.HttpPipelinePolicy; import com.azure.core.http.policy.HttpPolicyProviders; import com.azure.core.http.policy.RequestIdPolicy; +import com.azure.core.http.policy.RetryOptions; import com.azure.core.http.policy.RetryPolicy; import com.azure.core.http.policy.UserAgentPolicy; import com.azure.core.http.rest.Response; @@ -26,6 +27,7 @@ import com.azure.core.util.Configuration; import com.azure.core.util.Context; import com.azure.core.util.CoreUtils; +import com.azure.core.util.builder.ClientBuilderUtil; import com.azure.core.util.logging.ClientLogger; import com.azure.core.util.serializer.JacksonAdapter; import com.azure.core.util.serializer.SerializerAdapter; @@ -104,9 +106,10 @@ public static T convertValue(Object initialValue, Class newValueType) thr } public static HttpPipeline buildHttpPipeline(ClientOptions clientOptions, HttpLogOptions logOptions, - Configuration configuration, RetryPolicy retryPolicy, AzureKeyCredential azureKeyCredential, - TokenCredential tokenCredential, List perCallPolicies, - List perRetryPolicies, HttpClient httpClient, ClientLogger logger) { + Configuration configuration, RetryPolicy retryPolicy, RetryOptions retryOptions, + AzureKeyCredential azureKeyCredential, TokenCredential tokenCredential, + List perCallPolicies, List perRetryPolicies, HttpClient httpClient, + ClientLogger logger) { Configuration buildConfiguration = (configuration == null) ? Configuration.getGlobalConfiguration() : configuration; @@ -125,7 +128,7 @@ public static HttpPipeline buildHttpPipeline(ClientOptions clientOptions, HttpLo httpPipelinePolicies.addAll(perCallPolicies); HttpPolicyProviders.addBeforeRetryPolicies(httpPipelinePolicies); - httpPipelinePolicies.add(retryPolicy == null ? new RetryPolicy() : retryPolicy); + httpPipelinePolicies.add(ClientBuilderUtil.validateAndGetRetryPolicy(retryPolicy, retryOptions)); httpPipelinePolicies.add(new AddDatePolicy()); diff --git a/sdk/search/azure-search-documents/src/main/java/com/azure/search/documents/indexes/SearchIndexClientBuilder.java b/sdk/search/azure-search-documents/src/main/java/com/azure/search/documents/indexes/SearchIndexClientBuilder.java index 7aead9ab78afc..4e41fec0a3c40 100644 --- a/sdk/search/azure-search-documents/src/main/java/com/azure/search/documents/indexes/SearchIndexClientBuilder.java +++ b/sdk/search/azure-search-documents/src/main/java/com/azure/search/documents/indexes/SearchIndexClientBuilder.java @@ -3,16 +3,24 @@ package com.azure.search.documents.indexes; import com.azure.core.annotation.ServiceClientBuilder; +import com.azure.core.client.traits.AzureKeyCredentialTrait; +import com.azure.core.client.traits.ConfigurationTrait; +import com.azure.core.client.traits.EndpointTrait; +import com.azure.core.client.traits.HttpTrait; +import com.azure.core.client.traits.TokenCredentialTrait; import com.azure.core.credential.AzureKeyCredential; import com.azure.core.credential.TokenCredential; import com.azure.core.http.HttpClient; import com.azure.core.http.HttpPipeline; import com.azure.core.http.HttpPipelinePosition; +import com.azure.core.http.policy.HttpLogDetailLevel; import com.azure.core.http.policy.HttpLogOptions; import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.core.http.policy.RetryOptions; import com.azure.core.http.policy.RetryPolicy; import com.azure.core.util.ClientOptions; import com.azure.core.util.Configuration; +import com.azure.core.util.HttpClientOptions; import com.azure.core.util.logging.ClientLogger; import com.azure.core.util.serializer.JsonSerializer; import com.azure.search.documents.SearchServiceVersion; @@ -63,7 +71,12 @@ * @see SearchIndexAsyncClient */ @ServiceClientBuilder(serviceClients = {SearchIndexClient.class, SearchIndexAsyncClient.class}) -public final class SearchIndexClientBuilder { +public final class SearchIndexClientBuilder implements + AzureKeyCredentialTrait, + ConfigurationTrait, + EndpointTrait, + HttpTrait, + TokenCredentialTrait { private final ClientLogger logger = new ClientLogger(SearchIndexClientBuilder.class); private final List perCallPolicies = new ArrayList<>(); @@ -80,6 +93,7 @@ public final class SearchIndexClientBuilder { private ClientOptions clientOptions; private Configuration configuration; private RetryPolicy retryPolicy; + private RetryOptions retryOptions; private JsonSerializer jsonSerializer; /** @@ -98,6 +112,8 @@ public SearchIndexClientBuilder() { * * @return A SearchIndexClient with the options set from the builder. * @throws NullPointerException If {@code endpoint} are {@code null}. + * @throws IllegalStateException If both {@link #retryOptions(RetryOptions)} + * and {@link #retryPolicy(RetryPolicy)} have been set. */ public SearchIndexClient buildClient() { return new SearchIndexClient(buildAsyncClient()); @@ -112,6 +128,8 @@ public SearchIndexClient buildClient() { * * @return A SearchIndexAsyncClient with the options set from the builder. * @throws NullPointerException If {@code endpoint} are {@code null}. + * @throws IllegalStateException If both {@link #retryOptions(RetryOptions)} + * and {@link #retryPolicy(RetryPolicy)} have been set. */ public SearchIndexAsyncClient buildAsyncClient() { Objects.requireNonNull(endpoint, "'endpoint' cannot be null."); @@ -125,7 +143,7 @@ public SearchIndexAsyncClient buildAsyncClient() { } HttpPipeline pipeline = Utility.buildHttpPipeline(clientOptions, httpLogOptions, configuration, retryPolicy, - azureKeyCredential, tokenCredential, perCallPolicies, perRetryPolicies, httpClient, logger); + retryOptions, azureKeyCredential, tokenCredential, perCallPolicies, perRetryPolicies, httpClient, logger); return new SearchIndexAsyncClient(endpoint, buildVersion, pipeline, jsonSerializer); } @@ -137,6 +155,7 @@ public SearchIndexAsyncClient buildAsyncClient() { * @return The updated SearchIndexClientBuilder object. * @throws IllegalArgumentException If {@code endpoint} is null or it cannot be parsed into a valid URL. */ + @Override public SearchIndexClientBuilder endpoint(String endpoint) { try { new URL(endpoint); @@ -153,30 +172,42 @@ public SearchIndexClientBuilder endpoint(String endpoint) { * @param credential The {@link AzureKeyCredential} used to authenticate HTTP requests. * @return The updated SearchIndexClientBuilder object. */ + @Override public SearchIndexClientBuilder credential(AzureKeyCredential credential) { this.azureKeyCredential = credential; return this; } /** - * Sets the {@link TokenCredential} used to authenticate HTTP requests. + * Sets the {@link TokenCredential} used to authorize requests sent to the service. Refer to the Azure SDK for Java + * identity and authentication + * documentation for more details on proper usage of the {@link TokenCredential} type. * - * @param credential The {@link TokenCredential} used to authenticate HTTP requests. + * @param credential {@link TokenCredential} used to authorize requests sent to the service. * @return The updated SearchIndexClientBuilder object. */ + @Override public SearchIndexClientBuilder credential(TokenCredential credential) { this.tokenCredential = credential; return this; } /** - * Sets the logging configuration for HTTP requests and responses. - *

- * If logging configurations aren't provided HTTP requests and responses won't be logged. + * Sets the {@link HttpLogOptions logging configuration} to use when sending and receiving requests to and from + * the service. If a {@code logLevel} is not provided, default value of {@link HttpLogDetailLevel#NONE} is set. + * + *

Note: It is important to understand the precedence order of the HttpTrait APIs. In + * particular, if a {@link HttpPipeline} is specified, this takes precedence over all other APIs in the trait, and + * they will be ignored. If no {@link HttpPipeline} is specified, a HTTP pipeline will be constructed internally + * based on the settings provided to this trait. Additionally, there may be other APIs in types that implement this + * trait that are also ignored if an {@link HttpPipeline} is specified, so please be sure to refer to the + * documentation of types that implement this trait to understand the full set of implications.

* - * @param logOptions The logging configuration for HTTP requests and responses. + * @param logOptions The {@link HttpLogOptions logging configuration} to use when sending and receiving requests to + * and from the service. * @return The updated SearchIndexClientBuilder object. */ + @Override public SearchIndexClientBuilder httpLogOptions(HttpLogOptions logOptions) { httpLogOptions = logOptions; return this; @@ -192,26 +223,44 @@ public static HttpLogOptions getDefaultLogOptions() { } /** - * Sets the client options such as application ID and custom headers to set on a request. + * Allows for setting common properties such as application ID, headers, proxy configuration, etc. Note that it is + * recommended that this method be called with an instance of the {@link HttpClientOptions} + * class (a subclass of the {@link ClientOptions} base class). The HttpClientOptions subclass provides more + * configuration options suitable for HTTP clients, which is applicable for any class that implements this HttpTrait + * interface. + * + *

Note: It is important to understand the precedence order of the HttpTrait APIs. In + * particular, if a {@link HttpPipeline} is specified, this takes precedence over all other APIs in the trait, and + * they will be ignored. If no {@link HttpPipeline} is specified, a HTTP pipeline will be constructed internally + * based on the settings provided to this trait. Additionally, there may be other APIs in types that implement this + * trait that are also ignored if an {@link HttpPipeline} is specified, so please be sure to refer to the + * documentation of types that implement this trait to understand the full set of implications.

* - * @param clientOptions The client options. + * @param clientOptions A configured instance of {@link HttpClientOptions}. * @return The updated SearchIndexClientBuilder object. + * @see HttpClientOptions */ + @Override public SearchIndexClientBuilder clientOptions(ClientOptions clientOptions) { this.clientOptions = clientOptions; return this; } /** - * Adds a pipeline policy to apply to each request sent. - *

- * This method may be called multiple times, each time it is called the policy will be added to the end of added - * policy list. All policies will be added after the retry policy. + * Adds a {@link HttpPipelinePolicy pipeline policy} to apply on each request sent. + * + *

Note: It is important to understand the precedence order of the HttpTrait APIs. In + * particular, if a {@link HttpPipeline} is specified, this takes precedence over all other APIs in the trait, and + * they will be ignored. If no {@link HttpPipeline} is specified, a HTTP pipeline will be constructed internally + * based on the settings provided to this trait. Additionally, there may be other APIs in types that implement this + * trait that are also ignored if an {@link HttpPipeline} is specified, so please be sure to refer to the + * documentation of types that implement this trait to understand the full set of implications.

* - * @param policy The pipeline policies to added to the policy list. + * @param policy A {@link HttpPipelinePolicy pipeline policy}. * @return The updated SearchIndexClientBuilder object. * @throws NullPointerException If {@code policy} is {@code null}. */ + @Override public SearchIndexClientBuilder addPolicy(HttpPipelinePolicy policy) { Objects.requireNonNull(policy, "'policy' cannot be null."); @@ -237,11 +286,19 @@ public SearchIndexClientBuilder serializer(JsonSerializer jsonSerializer) { } /** - * Sets the HTTP client to use for sending requests and receiving responses. + * Sets the {@link HttpClient} to use for sending and receiving requests to and from the service. * - * @param client The HTTP client that will handle sending requests and receiving responses. + *

Note: It is important to understand the precedence order of the HttpTrait APIs. In + * particular, if a {@link HttpPipeline} is specified, this takes precedence over all other APIs in the trait, and + * they will be ignored. If no {@link HttpPipeline} is specified, a HTTP pipeline will be constructed internally + * based on the settings provided to this trait. Additionally, there may be other APIs in types that implement this + * trait that are also ignored if an {@link HttpPipeline} is specified, so please be sure to refer to the + * documentation of types that implement this trait to understand the full set of implications.

+ * + * @param client The {@link HttpClient} to use for requests. * @return The updated SearchIndexClientBuilder object. */ + @Override public SearchIndexClientBuilder httpClient(HttpClient client) { if (this.httpClient != null && client == null) { logger.info("HttpClient is being set to 'null' when it was previously configured."); @@ -252,14 +309,22 @@ public SearchIndexClientBuilder httpClient(HttpClient client) { } /** - * Sets the HTTP pipeline to use for the service client. + * Sets the {@link HttpPipeline} to use for the service client. + * + *

Note: It is important to understand the precedence order of the HttpTrait APIs. In + * particular, if a {@link HttpPipeline} is specified, this takes precedence over all other APIs in the trait, and + * they will be ignored. If no {@link HttpPipeline} is specified, a HTTP pipeline will be constructed internally + * based on the settings provided to this trait. Additionally, there may be other APIs in types that implement this + * trait that are also ignored if an {@link HttpPipeline} is specified, so please be sure to refer to the + * documentation of types that implement this trait to understand the full set of implications.

*

* If {@code pipeline} is set, all other settings are ignored, aside from {@link #endpoint(String) endpoint} when * building a {@link SearchIndexClient} or {@link SearchIndexAsyncClient}. * - * @param httpPipeline The HTTP pipeline to use for sending service requests and receiving responses. + * @param httpPipeline {@link HttpPipeline} to use for sending service requests and receiving responses. * @return The updated SearchIndexClientBuilder object. */ + @Override public SearchIndexClientBuilder pipeline(HttpPipeline httpPipeline) { if (this.httpPipeline != null && httpPipeline == null) { logger.info("HttpPipeline is being set to 'null' when it was previously configured."); @@ -278,6 +343,7 @@ public SearchIndexClientBuilder pipeline(HttpPipeline httpPipeline) { * @param configuration The configuration store that will be used. * @return The updated SearchIndexClientBuilder object. */ + @Override public SearchIndexClientBuilder configuration(Configuration configuration) { this.configuration = configuration; return this; @@ -287,6 +353,8 @@ public SearchIndexClientBuilder configuration(Configuration configuration) { * Sets the {@link HttpPipelinePolicy} that will attempt to retry requests when needed. *

* A default retry policy will be supplied if one isn't provided. + *

+ * Setting this is mutually exclusive with using {@link #retryOptions(RetryOptions)}. * * @param retryPolicy The {@link RetryPolicy} that will attempt to retry requests when needed. * @return The updated SearchIndexClientBuilder object. @@ -296,6 +364,27 @@ public SearchIndexClientBuilder retryPolicy(RetryPolicy retryPolicy) { return this; } + /** + * Sets the {@link RetryOptions} for all the requests made through the client. + * + *

Note: It is important to understand the precedence order of the HttpTrait APIs. In + * particular, if a {@link HttpPipeline} is specified, this takes precedence over all other APIs in the trait, and + * they will be ignored. If no {@link HttpPipeline} is specified, a HTTP pipeline will be constructed internally + * based on the settings provided to this trait. Additionally, there may be other APIs in types that implement this + * trait that are also ignored if an {@link HttpPipeline} is specified, so please be sure to refer to the + * documentation of types that implement this trait to understand the full set of implications.

+ *

+ * Setting this is mutually exclusive with using {@link #retryPolicy(RetryPolicy)}. + * + * @param retryOptions The {@link RetryOptions} to use for all the requests made through the client. + * @return The updated SearchIndexClientBuilder object. + */ + @Override + public SearchIndexClientBuilder retryOptions(RetryOptions retryOptions) { + this.retryOptions = retryOptions; + return this; + } + /** * Sets the {@link SearchServiceVersion} that is used when making API requests. *

diff --git a/sdk/search/azure-search-documents/src/main/java/com/azure/search/documents/indexes/SearchIndexerClientBuilder.java b/sdk/search/azure-search-documents/src/main/java/com/azure/search/documents/indexes/SearchIndexerClientBuilder.java index 1515b286a7449..2b5df0770113a 100644 --- a/sdk/search/azure-search-documents/src/main/java/com/azure/search/documents/indexes/SearchIndexerClientBuilder.java +++ b/sdk/search/azure-search-documents/src/main/java/com/azure/search/documents/indexes/SearchIndexerClientBuilder.java @@ -4,16 +4,24 @@ package com.azure.search.documents.indexes; import com.azure.core.annotation.ServiceClientBuilder; +import com.azure.core.client.traits.AzureKeyCredentialTrait; +import com.azure.core.client.traits.ConfigurationTrait; +import com.azure.core.client.traits.EndpointTrait; +import com.azure.core.client.traits.HttpTrait; +import com.azure.core.client.traits.TokenCredentialTrait; import com.azure.core.credential.AzureKeyCredential; import com.azure.core.credential.TokenCredential; import com.azure.core.http.HttpClient; import com.azure.core.http.HttpPipeline; import com.azure.core.http.HttpPipelinePosition; +import com.azure.core.http.policy.HttpLogDetailLevel; import com.azure.core.http.policy.HttpLogOptions; import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.core.http.policy.RetryOptions; import com.azure.core.http.policy.RetryPolicy; import com.azure.core.util.ClientOptions; import com.azure.core.util.Configuration; +import com.azure.core.util.HttpClientOptions; import com.azure.core.util.logging.ClientLogger; import com.azure.search.documents.SearchServiceVersion; import com.azure.search.documents.implementation.util.Constants; @@ -63,7 +71,12 @@ * @see SearchIndexerAsyncClient */ @ServiceClientBuilder(serviceClients = {SearchIndexerClient.class, SearchIndexerAsyncClient.class}) -public class SearchIndexerClientBuilder { +public class SearchIndexerClientBuilder implements + AzureKeyCredentialTrait, + ConfigurationTrait, + EndpointTrait, + HttpTrait, + TokenCredentialTrait { private final ClientLogger logger = new ClientLogger(SearchIndexerClientBuilder.class); private final List perCallPolicies = new ArrayList<>(); @@ -80,6 +93,7 @@ public class SearchIndexerClientBuilder { private HttpLogOptions httpLogOptions; private Configuration configuration; private RetryPolicy retryPolicy; + private RetryOptions retryOptions; /** * Creates a builder instance that is able to configure and construct {@link SearchIndexerClient @@ -97,6 +111,8 @@ public SearchIndexerClientBuilder() { * * @return A SearchIndexerClient with the options set from the builder. * @throws NullPointerException If {@code endpoint} are {@code null}. + * @throws IllegalStateException If both {@link #retryOptions(RetryOptions)} + * and {@link #retryPolicy(RetryPolicy)} have been set. */ public SearchIndexerClient buildClient() { return new SearchIndexerClient(buildAsyncClient()); @@ -112,6 +128,8 @@ public SearchIndexerClient buildClient() { * * @return A SearchIndexerAsyncClient with the options set from the builder. * @throws NullPointerException If {@code endpoint} are {@code null}. + * @throws IllegalStateException If both {@link #retryOptions(RetryOptions)} + * and {@link #retryPolicy(RetryPolicy)} have been set. */ public SearchIndexerAsyncClient buildAsyncClient() { Objects.requireNonNull(endpoint, "'endpoint' cannot be null."); @@ -124,8 +142,9 @@ public SearchIndexerAsyncClient buildAsyncClient() { return new SearchIndexerAsyncClient(endpoint, buildVersion, httpPipeline); } - HttpPipeline pipeline = Utility.buildHttpPipeline(clientOptions, httpLogOptions, configuration, retryPolicy, - azureKeyCredential, tokenCredential, perCallPolicies, perRetryPolicies, httpClient, logger); + HttpPipeline pipeline = Utility.buildHttpPipeline(clientOptions, httpLogOptions, configuration, + retryPolicy, retryOptions, azureKeyCredential, tokenCredential, perCallPolicies, perRetryPolicies, + httpClient, logger); return new SearchIndexerAsyncClient(endpoint, buildVersion, pipeline); } @@ -137,6 +156,7 @@ public SearchIndexerAsyncClient buildAsyncClient() { * @return The updated SearchIndexerClientBuilder object. * @throws IllegalArgumentException If {@code endpoint} is null or it cannot be parsed into a valid URL. */ + @Override public SearchIndexerClientBuilder endpoint(String endpoint) { try { new URL(endpoint); @@ -153,30 +173,42 @@ public SearchIndexerClientBuilder endpoint(String endpoint) { * @param credential The {@link AzureKeyCredential} used to authenticate HTTP requests. * @return The updated SearchIndexerClientBuilder object. */ + @Override public SearchIndexerClientBuilder credential(AzureKeyCredential credential) { this.azureKeyCredential = credential; return this; } /** - * Sets the {@link TokenCredential} used to authenticate HTTP requests. + * Sets the {@link TokenCredential} used to authorize requests sent to the service. Refer to the Azure SDK for Java + * identity and authentication + * documentation for more details on proper usage of the {@link TokenCredential} type. * - * @param credential The {@link TokenCredential} used to authenticate HTTP requests. + * @param credential {@link TokenCredential} used to authorize requests sent to the service. * @return The updated SearchIndexerClientBuilder object. */ + @Override public SearchIndexerClientBuilder credential(TokenCredential credential) { this.tokenCredential = credential; return this; } /** - * Sets the logging configuration for HTTP requests and responses. - *

- * If logging configurations aren't provided HTTP requests and responses won't be logged. + * Sets the {@link HttpLogOptions logging configuration} to use when sending and receiving requests to and from + * the service. If a {@code logLevel} is not provided, default value of {@link HttpLogDetailLevel#NONE} is set. + * + *

Note: It is important to understand the precedence order of the HttpTrait APIs. In + * particular, if a {@link HttpPipeline} is specified, this takes precedence over all other APIs in the trait, and + * they will be ignored. If no {@link HttpPipeline} is specified, a HTTP pipeline will be constructed internally + * based on the settings provided to this trait. Additionally, there may be other APIs in types that implement this + * trait that are also ignored if an {@link HttpPipeline} is specified, so please be sure to refer to the + * documentation of types that implement this trait to understand the full set of implications.

* - * @param logOptions The logging configuration for HTTP requests and responses. + * @param logOptions The {@link HttpLogOptions logging configuration} to use when sending and receiving requests to + * and from the service. * @return The updated SearchIndexerClientBuilder object. */ + @Override public SearchIndexerClientBuilder httpLogOptions(HttpLogOptions logOptions) { httpLogOptions = logOptions; return this; @@ -192,26 +224,44 @@ public static HttpLogOptions getDefaultLogOptions() { } /** - * Sets the client options such as application ID and custom headers to set on a request. + * Allows for setting common properties such as application ID, headers, proxy configuration, etc. Note that it is + * recommended that this method be called with an instance of the {@link HttpClientOptions} + * class (a subclass of the {@link ClientOptions} base class). The HttpClientOptions subclass provides more + * configuration options suitable for HTTP clients, which is applicable for any class that implements this HttpTrait + * interface. + * + *

Note: It is important to understand the precedence order of the HttpTrait APIs. In + * particular, if a {@link HttpPipeline} is specified, this takes precedence over all other APIs in the trait, and + * they will be ignored. If no {@link HttpPipeline} is specified, a HTTP pipeline will be constructed internally + * based on the settings provided to this trait. Additionally, there may be other APIs in types that implement this + * trait that are also ignored if an {@link HttpPipeline} is specified, so please be sure to refer to the + * documentation of types that implement this trait to understand the full set of implications.

* - * @param clientOptions The client options. + * @param clientOptions A configured instance of {@link HttpClientOptions}. * @return The updated SearchIndexerClientBuilder object. + * @see HttpClientOptions */ + @Override public SearchIndexerClientBuilder clientOptions(ClientOptions clientOptions) { this.clientOptions = clientOptions; return this; } /** - * Adds a pipeline policy to apply to each request sent. - *

- * This method may be called multiple times, each time it is called the policy will be added to the end of added - * policy list. All policies will be added after the retry policy. + * Adds a {@link HttpPipelinePolicy pipeline policy} to apply on each request sent. + * + *

Note: It is important to understand the precedence order of the HttpTrait APIs. In + * particular, if a {@link HttpPipeline} is specified, this takes precedence over all other APIs in the trait, and + * they will be ignored. If no {@link HttpPipeline} is specified, a HTTP pipeline will be constructed internally + * based on the settings provided to this trait. Additionally, there may be other APIs in types that implement this + * trait that are also ignored if an {@link HttpPipeline} is specified, so please be sure to refer to the + * documentation of types that implement this trait to understand the full set of implications.

* - * @param policy The pipeline policies to added to the policy list. + * @param policy A {@link HttpPipelinePolicy pipeline policy}. * @return The updated SearchIndexerClientBuilder object. * @throws NullPointerException If {@code policy} is {@code null}. */ + @Override public SearchIndexerClientBuilder addPolicy(HttpPipelinePolicy policy) { Objects.requireNonNull(policy, "'policy' cannot be null."); @@ -225,11 +275,19 @@ public SearchIndexerClientBuilder addPolicy(HttpPipelinePolicy policy) { } /** - * Sets the HTTP client to use for sending requests and receiving responses. + * Sets the {@link HttpClient} to use for sending and receiving requests to and from the service. * - * @param client The HTTP client that will handle sending requests and receiving responses. + *

Note: It is important to understand the precedence order of the HttpTrait APIs. In + * particular, if a {@link HttpPipeline} is specified, this takes precedence over all other APIs in the trait, and + * they will be ignored. If no {@link HttpPipeline} is specified, a HTTP pipeline will be constructed internally + * based on the settings provided to this trait. Additionally, there may be other APIs in types that implement this + * trait that are also ignored if an {@link HttpPipeline} is specified, so please be sure to refer to the + * documentation of types that implement this trait to understand the full set of implications.

+ * + * @param client The {@link HttpClient} to use for requests. * @return The updated SearchIndexerClientBuilder object. */ + @Override public SearchIndexerClientBuilder httpClient(HttpClient client) { if (this.httpClient != null && client == null) { logger.info("HttpClient is being set to 'null' when it was previously configured."); @@ -240,14 +298,22 @@ public SearchIndexerClientBuilder httpClient(HttpClient client) { } /** - * Sets the HTTP pipeline to use for the service client. + * Sets the {@link HttpPipeline} to use for the service client. + * + *

Note: It is important to understand the precedence order of the HttpTrait APIs. In + * particular, if a {@link HttpPipeline} is specified, this takes precedence over all other APIs in the trait, and + * they will be ignored. If no {@link HttpPipeline} is specified, a HTTP pipeline will be constructed internally + * based on the settings provided to this trait. Additionally, there may be other APIs in types that implement this + * trait that are also ignored if an {@link HttpPipeline} is specified, so please be sure to refer to the + * documentation of types that implement this trait to understand the full set of implications.

*

* If {@code pipeline} is set, all other settings are ignored, aside from {@link #endpoint(String) endpoint} when * building a {@link SearchIndexerClient} or {@link SearchIndexerAsyncClient}. * - * @param httpPipeline The HTTP pipeline to use for sending service requests and receiving responses. + * @param httpPipeline {@link HttpPipeline} to use for sending service requests and receiving responses. * @return The updated SearchIndexerClientBuilder object. */ + @Override public SearchIndexerClientBuilder pipeline(HttpPipeline httpPipeline) { if (this.httpPipeline != null && httpPipeline == null) { logger.info("HttpPipeline is being set to 'null' when it was previously configured."); @@ -266,6 +332,7 @@ public SearchIndexerClientBuilder pipeline(HttpPipeline httpPipeline) { * @param configuration The configuration store that will be used. * @return The updated SearchIndexerClientBuilder object. */ + @Override public SearchIndexerClientBuilder configuration(Configuration configuration) { this.configuration = configuration; return this; @@ -275,6 +342,8 @@ public SearchIndexerClientBuilder configuration(Configuration configuration) { * Sets the {@link HttpPipelinePolicy} that will attempt to retry requests when needed. *

* A default retry policy will be supplied if one isn't provided. + *

+ * Setting this is mutually exclusive with using {@link #retryOptions(RetryOptions)}. * * @param retryPolicy The {@link RetryPolicy} that will attempt to retry requests when needed. * @return The updated SearchIndexerClientBuilder object. @@ -284,6 +353,27 @@ public SearchIndexerClientBuilder retryPolicy(RetryPolicy retryPolicy) { return this; } + /** + * Sets the {@link RetryOptions} for all the requests made through the client. + * + *

Note: It is important to understand the precedence order of the HttpTrait APIs. In + * particular, if a {@link HttpPipeline} is specified, this takes precedence over all other APIs in the trait, and + * they will be ignored. If no {@link HttpPipeline} is specified, a HTTP pipeline will be constructed internally + * based on the settings provided to this trait. Additionally, there may be other APIs in types that implement this + * trait that are also ignored if an {@link HttpPipeline} is specified, so please be sure to refer to the + * documentation of types that implement this trait to understand the full set of implications.

+ *

+ * Setting this is mutually exclusive with using {@link #retryPolicy(RetryPolicy)}. + * + * @param retryOptions The {@link RetryOptions} to use for all the requests made through the client. + * @return The updated SearchIndexerClientBuilder object. + */ + @Override + public SearchIndexerClientBuilder retryOptions(RetryOptions retryOptions) { + this.retryOptions = retryOptions; + return this; + } + /** * Sets the {@link SearchServiceVersion} that is used when making API requests. *

diff --git a/sdk/search/azure-search-documents/src/test/java/com/azure/search/documents/SearchClientBuilderTests.java b/sdk/search/azure-search-documents/src/test/java/com/azure/search/documents/SearchClientBuilderTests.java index bdbe2dbc73d78..058c208fbb12d 100644 --- a/sdk/search/azure-search-documents/src/test/java/com/azure/search/documents/SearchClientBuilderTests.java +++ b/sdk/search/azure-search-documents/src/test/java/com/azure/search/documents/SearchClientBuilderTests.java @@ -5,8 +5,10 @@ import com.azure.core.credential.AzureKeyCredential; import com.azure.core.exception.HttpResponseException; +import com.azure.core.http.policy.ExponentialBackoffOptions; import com.azure.core.http.policy.FixedDelay; import com.azure.core.http.policy.HttpLogOptions; +import com.azure.core.http.policy.RetryOptions; import com.azure.core.http.policy.RetryPolicy; import com.azure.core.test.http.MockHttpResponse; import com.azure.core.util.ClientOptions; @@ -196,4 +198,16 @@ public void clientOptionHeadersAreAddedLast() { assertThrows(HttpResponseException.class, searchClient::getDocumentCount); } + + @Test + public void bothRetryOptionsAndRetryPolicySet() { + assertThrows(IllegalStateException.class, () -> new SearchClientBuilder() + .endpoint(searchEndpoint) + .credential(searchApiKeyCredential) + .indexName(indexName) + .serviceVersion(apiVersion) + .retryOptions(new RetryOptions(new ExponentialBackoffOptions())) + .retryPolicy(new RetryPolicy()) + .buildClient()); + } } diff --git a/sdk/search/azure-search-documents/src/test/java/com/azure/search/documents/indexes/SearchIndexClientBuilderTests.java b/sdk/search/azure-search-documents/src/test/java/com/azure/search/documents/indexes/SearchIndexClientBuilderTests.java index 1b5f8fbf2d53a..0c2cfc79f8b09 100644 --- a/sdk/search/azure-search-documents/src/test/java/com/azure/search/documents/indexes/SearchIndexClientBuilderTests.java +++ b/sdk/search/azure-search-documents/src/test/java/com/azure/search/documents/indexes/SearchIndexClientBuilderTests.java @@ -9,8 +9,10 @@ import com.azure.core.http.HttpMethod; import com.azure.core.http.HttpRequest; import com.azure.core.http.HttpResponse; +import com.azure.core.http.policy.ExponentialBackoffOptions; import com.azure.core.http.policy.FixedDelay; import com.azure.core.http.policy.HttpLogOptions; +import com.azure.core.http.policy.RetryOptions; import com.azure.core.http.policy.RetryPolicy; import com.azure.core.test.http.MockHttpResponse; import com.azure.core.util.ClientOptions; @@ -212,4 +214,15 @@ public void clientOptionHeadersAreAddedLast() { assertThrows(HttpResponseException.class, searchIndexClient::getServiceStatistics); } + + @Test + public void bothRetryOptionsAndRetryPolicySet() { + assertThrows(IllegalStateException.class, () -> new SearchIndexClientBuilder() + .endpoint(searchEndpoint) + .credential(searchApiKeyCredential) + .serviceVersion(apiVersion) + .retryOptions(new RetryOptions(new ExponentialBackoffOptions())) + .retryPolicy(new RetryPolicy()) + .buildClient()); + } } diff --git a/sdk/search/azure-search-documents/src/test/java/com/azure/search/documents/indexes/SearchIndexerClientBuilderTests.java b/sdk/search/azure-search-documents/src/test/java/com/azure/search/documents/indexes/SearchIndexerClientBuilderTests.java index 463e0da2d685c..822bc0a7ac0fa 100644 --- a/sdk/search/azure-search-documents/src/test/java/com/azure/search/documents/indexes/SearchIndexerClientBuilderTests.java +++ b/sdk/search/azure-search-documents/src/test/java/com/azure/search/documents/indexes/SearchIndexerClientBuilderTests.java @@ -9,8 +9,10 @@ import com.azure.core.http.HttpMethod; import com.azure.core.http.HttpRequest; import com.azure.core.http.HttpResponse; +import com.azure.core.http.policy.ExponentialBackoffOptions; import com.azure.core.http.policy.FixedDelay; import com.azure.core.http.policy.HttpLogOptions; +import com.azure.core.http.policy.RetryOptions; import com.azure.core.http.policy.RetryPolicy; import com.azure.core.test.http.MockHttpResponse; import com.azure.core.util.ClientOptions; @@ -212,4 +214,15 @@ public void clientOptionHeadersAreAddedLast() { assertThrows(HttpResponseException.class, () -> searchIndexerClient.getIndexer("anindexer")); } + + @Test + public void bothRetryOptionsAndRetryPolicySet() { + assertThrows(IllegalStateException.class, () -> new SearchIndexerClientBuilder() + .endpoint(searchEndpoint) + .credential(searchApiKeyCredential) + .serviceVersion(apiVersion) + .retryOptions(new RetryOptions(new ExponentialBackoffOptions())) + .retryPolicy(new RetryPolicy()) + .buildClient()); + } }