From 2c543a153f9d3e8ca043439dfc06b8cb04c66a51 Mon Sep 17 00:00:00 2001 From: Nicole Lee Date: Tue, 28 Jul 2026 18:18:50 +0000 Subject: [PATCH 1/7] test(showcase): add integration tests for exponential backoff retries using SequenceService --- .../google/showcase/v1beta1/it/ITRetries.java | 193 ++++++++++++++++++ .../it/util/TestClientInitializer.java | 73 +++++++ 2 files changed, 266 insertions(+) create mode 100644 java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITRetries.java diff --git a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITRetries.java b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITRetries.java new file mode 100644 index 000000000000..01d883b76f81 --- /dev/null +++ b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITRetries.java @@ -0,0 +1,193 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.showcase.v1beta1.it; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.api.gax.retrying.RetrySettings; +import com.google.api.gax.rpc.StatusCode; +import com.google.common.collect.ImmutableSet; +import com.google.rpc.Status; +import com.google.showcase.v1beta1.AttemptSequenceRequest; +import com.google.showcase.v1beta1.CreateSequenceRequest; +import com.google.showcase.v1beta1.GetSequenceReportRequest; +import com.google.showcase.v1beta1.Sequence; +import com.google.showcase.v1beta1.SequenceReport; +import com.google.showcase.v1beta1.SequenceServiceClient; +import com.google.showcase.v1beta1.it.util.TestClientInitializer; +import java.util.List; +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class ITRetries { + + private static final Sequence STANDARD_SEQUENCE = + Sequence.newBuilder() + .addResponses( + Sequence.Response.newBuilder() + .setStatus( + Status.newBuilder() + .setCode(com.google.rpc.Code.UNAVAILABLE.getNumber()) + .build()) + .build()) + .addResponses( + Sequence.Response.newBuilder() + .setStatus( + Status.newBuilder() + .setCode(com.google.rpc.Code.UNAVAILABLE.getNumber()) + .build()) + .build()) + .addResponses( + Sequence.Response.newBuilder() + .setStatus( + Status.newBuilder() + .setCode(com.google.rpc.Code.UNAVAILABLE.getNumber()) + .build()) + .build()) + .addResponses( + Sequence.Response.newBuilder() + .setStatus( + Status.newBuilder().setCode(com.google.rpc.Code.OK.getNumber()).build()) + .build()) + .build(); + + @SuppressWarnings("deprecation") + private static final RetrySettings STANDARD_RETRY_SETTINGS = + RetrySettings.newBuilder() + .setInitialRetryDelayDuration(java.time.Duration.ofMillis(100L)) + .setRetryDelayMultiplier(2.0) + .setMaxRetryDelayDuration(java.time.Duration.ofMillis(1000L)) + .setInitialRpcTimeoutDuration(java.time.Duration.ofMillis(1000L)) + .setRpcTimeoutMultiplier(1.0) + .setMaxRpcTimeoutDuration(java.time.Duration.ofMillis(1000L)) + .setTotalTimeoutDuration(java.time.Duration.ofMillis(5000L)) + .setMaxAttempts(4) + .setJittered(false) + .build(); + + private static SequenceServiceClient grpcClient; + private static SequenceServiceClient httpjsonClient; + + @BeforeAll + static void createClients() throws Exception { + grpcClient = TestClientInitializer.createGrpcSequenceClient(); + httpjsonClient = TestClientInitializer.createHttpJsonSequenceClient(); + } + + @AfterAll + static void destroyClients() throws InterruptedException { + grpcClient.close(); + httpjsonClient.close(); + + grpcClient.awaitTermination(TestClientInitializer.AWAIT_TERMINATION_SECONDS, TimeUnit.SECONDS); + httpjsonClient.awaitTermination( + TestClientInitializer.AWAIT_TERMINATION_SECONDS, TimeUnit.SECONDS); + } + + @Test + @SuppressWarnings("deprecation") + void testGrpc_retryExponentialBackoff() throws Exception { + // Create a custom client with these retry settings on attemptSequence + try (SequenceServiceClient retryClient = + TestClientInitializer.createGrpcSequenceClientWithRetrySettings( + STANDARD_RETRY_SETTINGS, ImmutableSet.of(StatusCode.Code.UNAVAILABLE))) { + + Sequence createdSequence = + grpcClient.createSequence( + CreateSequenceRequest.newBuilder().setSequence(STANDARD_SEQUENCE).build()); + + // 3. Trigger the sequence attempts using the retrying client + retryClient.attemptSequence( + AttemptSequenceRequest.newBuilder().setName(createdSequence.getName()).build()); + + // 4. Retrieve the sequence report to inspect delay measurements + SequenceReport report = + grpcClient.getSequenceReport( + GetSequenceReportRequest.newBuilder() + .setName(createdSequence.getName() + "/sequenceReport") + .build()); + + // 5. Assert attempts count and delays + verifySequenceReport(report); + } + } + + @Test + @SuppressWarnings("deprecation") + void testHttpJson_retryExponentialBackoff() throws Exception { + // Create a custom client with these retry settings on attemptSequence + try (SequenceServiceClient retryClient = + TestClientInitializer.createHttpJsonSequenceClientWithRetrySettings( + STANDARD_RETRY_SETTINGS, ImmutableSet.of(StatusCode.Code.UNAVAILABLE))) { + + Sequence createdSequence = + httpjsonClient.createSequence( + CreateSequenceRequest.newBuilder().setSequence(STANDARD_SEQUENCE).build()); + + // 3. Trigger the sequence attempts using the retrying client + retryClient.attemptSequence( + AttemptSequenceRequest.newBuilder().setName(createdSequence.getName()).build()); + + // 4. Retrieve the sequence report to inspect delay measurements + SequenceReport report = + httpjsonClient.getSequenceReport( + GetSequenceReportRequest.newBuilder() + .setName(createdSequence.getName() + "/sequenceReport") + .build()); + + // 5. Assert attempts count and delays + verifySequenceReport(report); + } + } + + private void verifySequenceReport(SequenceReport report) { + List attempts = report.getAttemptsList(); + assertThat(attempts).hasSize(4); + + // Verify the status of each attempt + assertThat(attempts.get(0).getStatus().getCode()) + .isEqualTo(com.google.rpc.Code.UNAVAILABLE.getNumber()); + assertThat(attempts.get(1).getStatus().getCode()) + .isEqualTo(com.google.rpc.Code.UNAVAILABLE.getNumber()); + assertThat(attempts.get(2).getStatus().getCode()) + .isEqualTo(com.google.rpc.Code.UNAVAILABLE.getNumber()); + assertThat(attempts.get(3).getStatus().getCode()).isEqualTo(com.google.rpc.Code.OK.getNumber()); + + // Verify delay intervals are within expected tolerances: + // Attempt 1 -> 2: ~100ms delay. Range [80ms, 250ms] + long delay1 = getDelayMs(attempts.get(1)); + assertThat(delay1).isAtLeast(80L); + assertThat(delay1).isLessThan(250L); + + // Attempt 2 -> 3: ~200ms delay. Range [180ms, 400ms] + long delay2 = getDelayMs(attempts.get(2)); + assertThat(delay2).isAtLeast(180L); + assertThat(delay2).isLessThan(400L); + + // Attempt 3 -> 4: ~400ms delay. Range [380ms, 700ms] + long delay3 = getDelayMs(attempts.get(3)); + assertThat(delay3).isAtLeast(380L); + assertThat(delay3).isLessThan(700L); + } + + private long getDelayMs(SequenceReport.Attempt attempt) { + com.google.protobuf.Duration attemptDelay = attempt.getAttemptDelay(); + return attemptDelay.getSeconds() * 1000 + attemptDelay.getNanos() / 1_000_000; + } +} diff --git a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/util/TestClientInitializer.java b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/util/TestClientInitializer.java index d9f65674bd77..1c1012f1e84a 100644 --- a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/util/TestClientInitializer.java +++ b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/util/TestClientInitializer.java @@ -33,9 +33,12 @@ import com.google.showcase.v1beta1.EchoSettings; import com.google.showcase.v1beta1.IdentityClient; import com.google.showcase.v1beta1.IdentitySettings; +import com.google.showcase.v1beta1.SequenceServiceClient; +import com.google.showcase.v1beta1.SequenceServiceSettings; import com.google.showcase.v1beta1.WaitRequest; import com.google.showcase.v1beta1.stub.EchoStub; import com.google.showcase.v1beta1.stub.EchoStubSettings; +import com.google.showcase.v1beta1.stub.SequenceServiceStubSettings; import io.grpc.ClientInterceptor; import io.grpc.ManagedChannelBuilder; import java.io.IOException; @@ -476,4 +479,74 @@ public String getServiceName() { return "showcase"; } } + + public static SequenceServiceClient createGrpcSequenceClient() throws Exception { + SequenceServiceSettings settings = + SequenceServiceSettings.newBuilder() + .setCredentialsProvider(NoCredentialsProvider.create()) + .setTransportChannelProvider( + SequenceServiceSettings.defaultGrpcTransportProviderBuilder() + .setChannelConfigurator(ManagedChannelBuilder::usePlaintext) + .build()) + .setEndpoint(DEFAULT_GRPC_ENDPOINT) + .build(); + return SequenceServiceClient.create(settings); + } + + public static SequenceServiceClient createHttpJsonSequenceClient() throws Exception { + SequenceServiceSettings settings = + SequenceServiceSettings.newHttpJsonBuilder() + .setCredentialsProvider(NoCredentialsProvider.create()) + .setTransportChannelProvider( + SequenceServiceSettings.defaultHttpJsonTransportProviderBuilder() + .setHttpTransport( + new NetHttpTransport.Builder().doNotValidateCertificate().build()) + .setEndpoint(DEFAULT_HTTPJSON_ENDPOINT) + .build()) + .build(); + return SequenceServiceClient.create(settings); + } + + public static SequenceServiceClient createGrpcSequenceClientWithRetrySettings( + RetrySettings retrySettings, Set retryableCodes) throws Exception { + SequenceServiceStubSettings.Builder stubSettingsBuilder = + SequenceServiceStubSettings.newBuilder(); + stubSettingsBuilder + .attemptSequenceSettings() + .setRetrySettings(retrySettings) + .setRetryableCodes(retryableCodes); + SequenceServiceSettings settings = SequenceServiceSettings.create(stubSettingsBuilder.build()); + settings = + settings.toBuilder() + .setCredentialsProvider(NoCredentialsProvider.create()) + .setTransportChannelProvider( + SequenceServiceSettings.defaultGrpcTransportProviderBuilder() + .setChannelConfigurator(ManagedChannelBuilder::usePlaintext) + .build()) + .setEndpoint(DEFAULT_GRPC_ENDPOINT) + .build(); + return SequenceServiceClient.create(settings); + } + + public static SequenceServiceClient createHttpJsonSequenceClientWithRetrySettings( + RetrySettings retrySettings, Set retryableCodes) throws Exception { + SequenceServiceStubSettings.Builder stubSettingsBuilder = + SequenceServiceStubSettings.newHttpJsonBuilder(); + stubSettingsBuilder + .attemptSequenceSettings() + .setRetrySettings(retrySettings) + .setRetryableCodes(retryableCodes); + SequenceServiceSettings settings = SequenceServiceSettings.create(stubSettingsBuilder.build()); + settings = + settings.toBuilder() + .setCredentialsProvider(NoCredentialsProvider.create()) + .setTransportChannelProvider( + SequenceServiceSettings.defaultHttpJsonTransportProviderBuilder() + .setHttpTransport( + new NetHttpTransport.Builder().doNotValidateCertificate().build()) + .setEndpoint(DEFAULT_HTTPJSON_ENDPOINT) + .build()) + .build(); + return SequenceServiceClient.create(settings); + } } From 490cb3686f395593df9dedbb96e77b25a4d48f8f Mon Sep 17 00:00:00 2001 From: Nicole Lee Date: Tue, 28 Jul 2026 18:41:47 +0000 Subject: [PATCH 2/7] test(showcase): simplify retry client configuration to use SequenceServiceSettings.Builder directly --- .../it/util/TestClientInitializer.java | 50 ++++++++----------- 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/util/TestClientInitializer.java b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/util/TestClientInitializer.java index 1c1012f1e84a..283b2a4b8950 100644 --- a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/util/TestClientInitializer.java +++ b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/util/TestClientInitializer.java @@ -38,7 +38,6 @@ import com.google.showcase.v1beta1.WaitRequest; import com.google.showcase.v1beta1.stub.EchoStub; import com.google.showcase.v1beta1.stub.EchoStubSettings; -import com.google.showcase.v1beta1.stub.SequenceServiceStubSettings; import io.grpc.ClientInterceptor; import io.grpc.ManagedChannelBuilder; import java.io.IOException; @@ -509,44 +508,35 @@ public static SequenceServiceClient createHttpJsonSequenceClient() throws Except public static SequenceServiceClient createGrpcSequenceClientWithRetrySettings( RetrySettings retrySettings, Set retryableCodes) throws Exception { - SequenceServiceStubSettings.Builder stubSettingsBuilder = - SequenceServiceStubSettings.newBuilder(); - stubSettingsBuilder + SequenceServiceSettings.Builder settingsBuilder = SequenceServiceSettings.newBuilder(); + settingsBuilder .attemptSequenceSettings() .setRetrySettings(retrySettings) .setRetryableCodes(retryableCodes); - SequenceServiceSettings settings = SequenceServiceSettings.create(stubSettingsBuilder.build()); - settings = - settings.toBuilder() - .setCredentialsProvider(NoCredentialsProvider.create()) - .setTransportChannelProvider( - SequenceServiceSettings.defaultGrpcTransportProviderBuilder() - .setChannelConfigurator(ManagedChannelBuilder::usePlaintext) - .build()) - .setEndpoint(DEFAULT_GRPC_ENDPOINT) - .build(); - return SequenceServiceClient.create(settings); + settingsBuilder + .setCredentialsProvider(NoCredentialsProvider.create()) + .setTransportChannelProvider( + SequenceServiceSettings.defaultGrpcTransportProviderBuilder() + .setChannelConfigurator(ManagedChannelBuilder::usePlaintext) + .build()) + .setEndpoint(DEFAULT_GRPC_ENDPOINT); + return SequenceServiceClient.create(settingsBuilder.build()); } public static SequenceServiceClient createHttpJsonSequenceClientWithRetrySettings( RetrySettings retrySettings, Set retryableCodes) throws Exception { - SequenceServiceStubSettings.Builder stubSettingsBuilder = - SequenceServiceStubSettings.newHttpJsonBuilder(); - stubSettingsBuilder + SequenceServiceSettings.Builder settingsBuilder = SequenceServiceSettings.newHttpJsonBuilder(); + settingsBuilder .attemptSequenceSettings() .setRetrySettings(retrySettings) .setRetryableCodes(retryableCodes); - SequenceServiceSettings settings = SequenceServiceSettings.create(stubSettingsBuilder.build()); - settings = - settings.toBuilder() - .setCredentialsProvider(NoCredentialsProvider.create()) - .setTransportChannelProvider( - SequenceServiceSettings.defaultHttpJsonTransportProviderBuilder() - .setHttpTransport( - new NetHttpTransport.Builder().doNotValidateCertificate().build()) - .setEndpoint(DEFAULT_HTTPJSON_ENDPOINT) - .build()) - .build(); - return SequenceServiceClient.create(settings); + settingsBuilder + .setCredentialsProvider(NoCredentialsProvider.create()) + .setTransportChannelProvider( + SequenceServiceSettings.defaultHttpJsonTransportProviderBuilder() + .setHttpTransport(new NetHttpTransport.Builder().doNotValidateCertificate().build()) + .setEndpoint(DEFAULT_HTTPJSON_ENDPOINT) + .build()); + return SequenceServiceClient.create(settingsBuilder.build()); } } From 51960b2f4e2e05ecf117b13ba2a4ddaf11979f2c Mon Sep 17 00:00:00 2001 From: Nicole Lee Date: Wed, 29 Jul 2026 15:52:15 +0000 Subject: [PATCH 3/7] test(showcase): use lower bounds only for retry delays to prevent flakiness --- .../com/google/showcase/v1beta1/it/ITRetries.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITRetries.java b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITRetries.java index 01d883b76f81..ff6c6ad13a48 100644 --- a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITRetries.java +++ b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITRetries.java @@ -169,21 +169,18 @@ private void verifySequenceReport(SequenceReport report) { .isEqualTo(com.google.rpc.Code.UNAVAILABLE.getNumber()); assertThat(attempts.get(3).getStatus().getCode()).isEqualTo(com.google.rpc.Code.OK.getNumber()); - // Verify delay intervals are within expected tolerances: - // Attempt 1 -> 2: ~100ms delay. Range [80ms, 250ms] + // Verify delay intervals are at least the expected exponential backoff thresholds: + // Attempt 1 -> 2: scheduled 100ms. Must be at least 80ms (no upper bound) long delay1 = getDelayMs(attempts.get(1)); assertThat(delay1).isAtLeast(80L); - assertThat(delay1).isLessThan(250L); - // Attempt 2 -> 3: ~200ms delay. Range [180ms, 400ms] + // Attempt 2 -> 3: scheduled 200ms. Must be at least 180ms (no upper bound) long delay2 = getDelayMs(attempts.get(2)); assertThat(delay2).isAtLeast(180L); - assertThat(delay2).isLessThan(400L); - // Attempt 3 -> 4: ~400ms delay. Range [380ms, 700ms] + // Attempt 3 -> 4: scheduled 400ms. Must be at least 380ms (no upper bound) long delay3 = getDelayMs(attempts.get(3)); assertThat(delay3).isAtLeast(380L); - assertThat(delay3).isLessThan(700L); } private long getDelayMs(SequenceReport.Attempt attempt) { From 4977b9b7c6bad84cd84e98c47d2a8ade1186185e Mon Sep 17 00:00:00 2001 From: Nicole Lee Date: Thu, 30 Jul 2026 05:52:02 +0000 Subject: [PATCH 4/7] test(showcase): added more retries test --- .../google/showcase/v1beta1/it/ITRetries.java | 442 +++++++++++++++--- 1 file changed, 386 insertions(+), 56 deletions(-) diff --git a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITRetries.java b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITRetries.java index ff6c6ad13a48..ebd0bb38441c 100644 --- a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITRetries.java +++ b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITRetries.java @@ -19,8 +19,10 @@ import static com.google.common.truth.Truth.assertThat; import com.google.api.gax.retrying.RetrySettings; +import com.google.api.gax.rpc.ApiException; import com.google.api.gax.rpc.StatusCode; import com.google.common.collect.ImmutableSet; +import com.google.rpc.Code; import com.google.rpc.Status; import com.google.showcase.v1beta1.AttemptSequenceRequest; import com.google.showcase.v1beta1.CreateSequenceRequest; @@ -29,8 +31,10 @@ import com.google.showcase.v1beta1.SequenceReport; import com.google.showcase.v1beta1.SequenceServiceClient; import com.google.showcase.v1beta1.it.util.TestClientInitializer; +import java.time.Duration; import java.util.List; import java.util.concurrent.TimeUnit; +import org.awaitility.Awaitility; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -81,6 +85,20 @@ class ITRetries { .setJittered(false) .build(); + @SuppressWarnings("deprecation") + private static final RetrySettings NO_RETRY_SETTINGS = + RetrySettings.newBuilder() + .setInitialRetryDelayDuration(java.time.Duration.ofMillis(100L)) + .setRetryDelayMultiplier(2.0) + .setMaxRetryDelayDuration(java.time.Duration.ofMillis(1000L)) + .setInitialRpcTimeoutDuration(java.time.Duration.ofMillis(1000L)) + .setRpcTimeoutMultiplier(1.0) + .setMaxRpcTimeoutDuration(java.time.Duration.ofMillis(1000L)) + .setTotalTimeoutDuration(java.time.Duration.ofMillis(5000L)) + .setMaxAttempts(1) + .setJittered(false) + .build(); + private static SequenceServiceClient grpcClient; private static SequenceServiceClient httpjsonClient; @@ -103,56 +121,331 @@ static void destroyClients() throws InterruptedException { @Test @SuppressWarnings("deprecation") void testGrpc_retryExponentialBackoff() throws Exception { - // Create a custom client with these retry settings on attemptSequence try (SequenceServiceClient retryClient = TestClientInitializer.createGrpcSequenceClientWithRetrySettings( STANDARD_RETRY_SETTINGS, ImmutableSet.of(StatusCode.Code.UNAVAILABLE))) { - Sequence createdSequence = - grpcClient.createSequence( - CreateSequenceRequest.newBuilder().setSequence(STANDARD_SEQUENCE).build()); + TestResult result = runAttempt(grpcClient, retryClient, STANDARD_SEQUENCE, 4); - // 3. Trigger the sequence attempts using the retrying client - retryClient.attemptSequence( - AttemptSequenceRequest.newBuilder().setName(createdSequence.getName()).build()); + assertThat(result.exception).isNull(); + verifySequenceReport(result.report); + } + } + + @Test + @SuppressWarnings("deprecation") + void testHttpJson_retryExponentialBackoff() throws Exception { + try (SequenceServiceClient retryClient = + TestClientInitializer.createHttpJsonSequenceClientWithRetrySettings( + STANDARD_RETRY_SETTINGS, ImmutableSet.of(StatusCode.Code.UNAVAILABLE))) { - // 4. Retrieve the sequence report to inspect delay measurements - SequenceReport report = - grpcClient.getSequenceReport( - GetSequenceReportRequest.newBuilder() - .setName(createdSequence.getName() + "/sequenceReport") - .build()); + TestResult result = runAttempt(httpjsonClient, retryClient, STANDARD_SEQUENCE, 4); - // 5. Assert attempts count and delays - verifySequenceReport(report); + assertThat(result.exception).isNull(); + verifySequenceReport(result.report); } } @Test @SuppressWarnings("deprecation") - void testHttpJson_retryExponentialBackoff() throws Exception { - // Create a custom client with these retry settings on attemptSequence + void testGrpc_noRetry() throws Exception { + try (SequenceServiceClient retryClient = + TestClientInitializer.createGrpcSequenceClientWithRetrySettings( + NO_RETRY_SETTINGS, ImmutableSet.of(StatusCode.Code.UNAVAILABLE))) { + + Sequence sequence = buildSequence(Code.UNAVAILABLE, Code.OK); + + TestResult result = runAttempt(grpcClient, retryClient, sequence, 1); + + assertThat(result.exception).isNotNull(); + assertThat(result.exception.getStatusCode().getCode()).isEqualTo(StatusCode.Code.UNAVAILABLE); + assertThat(result.report.getAttempts(0).getStatus().getCode()) + .isEqualTo(Code.UNAVAILABLE.getNumber()); + } + } + + @Test + @SuppressWarnings("deprecation") + void testHttpJson_noRetry() throws Exception { try (SequenceServiceClient retryClient = TestClientInitializer.createHttpJsonSequenceClientWithRetrySettings( + NO_RETRY_SETTINGS, ImmutableSet.of(StatusCode.Code.UNAVAILABLE))) { + + Sequence sequence = buildSequence(Code.UNAVAILABLE, Code.OK); + + TestResult result = runAttempt(httpjsonClient, retryClient, sequence, 1); + + assertThat(result.exception).isNotNull(); + assertThat(result.exception.getStatusCode().getCode()).isEqualTo(StatusCode.Code.UNAVAILABLE); + assertThat(result.report.getAttempts(0).getStatus().getCode()) + .isEqualTo(Code.UNAVAILABLE.getNumber()); + } + } + + @Test + @SuppressWarnings("deprecation") + void testGrpc_nonRetryableError() throws Exception { + try (SequenceServiceClient retryClient = + TestClientInitializer.createGrpcSequenceClientWithRetrySettings( STANDARD_RETRY_SETTINGS, ImmutableSet.of(StatusCode.Code.UNAVAILABLE))) { - Sequence createdSequence = - httpjsonClient.createSequence( - CreateSequenceRequest.newBuilder().setSequence(STANDARD_SEQUENCE).build()); + Sequence sequence = buildSequence(Code.INVALID_ARGUMENT, Code.OK); - // 3. Trigger the sequence attempts using the retrying client - retryClient.attemptSequence( - AttemptSequenceRequest.newBuilder().setName(createdSequence.getName()).build()); + TestResult result = runAttempt(grpcClient, retryClient, sequence, 1); + + assertThat(result.exception).isNotNull(); + assertThat(result.exception.getStatusCode().getCode()) + .isEqualTo(StatusCode.Code.INVALID_ARGUMENT); + assertThat(result.report.getAttempts(0).getStatus().getCode()) + .isEqualTo(Code.INVALID_ARGUMENT.getNumber()); + } + } + + @Test + @SuppressWarnings("deprecation") + void testHttpJson_nonRetryableError() throws Exception { + try (SequenceServiceClient retryClient = + TestClientInitializer.createHttpJsonSequenceClientWithRetrySettings( + STANDARD_RETRY_SETTINGS, ImmutableSet.of(StatusCode.Code.UNAVAILABLE))) { + + Sequence sequence = buildSequence(Code.INVALID_ARGUMENT, Code.OK); + + TestResult result = runAttempt(httpjsonClient, retryClient, sequence, 1); + + assertThat(result.exception).isNotNull(); + assertThat(result.exception.getStatusCode().getCode()) + .isEqualTo(StatusCode.Code.INVALID_ARGUMENT); + assertThat(result.report.getAttempts(0).getStatus().getCode()) + .isEqualTo(Code.INVALID_ARGUMENT.getNumber()); + } + } + + @Test + @SuppressWarnings("deprecation") + void testGrpc_retryMultipleStatus() throws Exception { + try (SequenceServiceClient retryClient = + TestClientInitializer.createGrpcSequenceClientWithRetrySettings( + STANDARD_RETRY_SETTINGS, + ImmutableSet.of( + StatusCode.Code.UNAVAILABLE, + StatusCode.Code.RESOURCE_EXHAUSTED, + StatusCode.Code.DEADLINE_EXCEEDED))) { + + Sequence sequence = + buildSequence(Code.UNAVAILABLE, Code.RESOURCE_EXHAUSTED, Code.DEADLINE_EXCEEDED, Code.OK); + + TestResult result = runAttempt(grpcClient, retryClient, sequence, 4); + + assertThat(result.exception).isNull(); + List attempts = result.report.getAttemptsList(); + assertThat(attempts.get(0).getStatus().getCode()).isEqualTo(Code.UNAVAILABLE.getNumber()); + assertThat(attempts.get(1).getStatus().getCode()) + .isEqualTo(Code.RESOURCE_EXHAUSTED.getNumber()); + assertThat(attempts.get(2).getStatus().getCode()) + .isEqualTo(Code.DEADLINE_EXCEEDED.getNumber()); + assertThat(attempts.get(3).getStatus().getCode()).isEqualTo(Code.OK.getNumber()); + } + } + + @Test + @SuppressWarnings("deprecation") + void testHttpJson_retryMultipleStatus() throws Exception { + try (SequenceServiceClient retryClient = + TestClientInitializer.createHttpJsonSequenceClientWithRetrySettings( + STANDARD_RETRY_SETTINGS, + ImmutableSet.of( + StatusCode.Code.UNAVAILABLE, + StatusCode.Code.RESOURCE_EXHAUSTED, + StatusCode.Code.DEADLINE_EXCEEDED))) { + + Sequence sequence = + buildSequence(Code.UNAVAILABLE, Code.RESOURCE_EXHAUSTED, Code.DEADLINE_EXCEEDED, Code.OK); + + TestResult result = runAttempt(httpjsonClient, retryClient, sequence, 4); + + assertThat(result.exception).isNull(); + List attempts = result.report.getAttemptsList(); + assertThat(attempts.get(0).getStatus().getCode()).isEqualTo(Code.UNAVAILABLE.getNumber()); + assertThat(attempts.get(1).getStatus().getCode()) + .isEqualTo(Code.RESOURCE_EXHAUSTED.getNumber()); + assertThat(attempts.get(2).getStatus().getCode()) + .isEqualTo(Code.DEADLINE_EXCEEDED.getNumber()); + assertThat(attempts.get(3).getStatus().getCode()).isEqualTo(Code.OK.getNumber()); + } + } + + @Test + @SuppressWarnings("deprecation") + void testGrpc_retryOnRpcTimeoutExceeded() throws Exception { + RetrySettings timeoutRetrySettings = + RetrySettings.newBuilder() + .setInitialRetryDelayDuration(java.time.Duration.ofMillis(10L)) + .setRetryDelayMultiplier(1.0) + .setMaxRetryDelayDuration(java.time.Duration.ofMillis(10L)) + .setInitialRpcTimeoutDuration(java.time.Duration.ofMillis(100L)) + .setRpcTimeoutMultiplier(1.0) + .setMaxRpcTimeoutDuration(java.time.Duration.ofMillis(100L)) + .setTotalTimeoutDuration(java.time.Duration.ofMillis(10000L)) + .setMaxAttempts(10) + .setJittered(false) + .build(); + + try (SequenceServiceClient retryClient = + TestClientInitializer.createGrpcSequenceClientWithRetrySettings( + timeoutRetrySettings, ImmutableSet.of(StatusCode.Code.DEADLINE_EXCEEDED))) { + + Sequence.Builder sequenceBuilder = Sequence.newBuilder(); + for (int i = 0; i < 10; i++) { + sequenceBuilder.addResponses( + Sequence.Response.newBuilder() + .setStatus(Status.newBuilder().setCode(Code.OK.getNumber()).build()) + .setDelay(com.google.protobuf.Duration.newBuilder().setNanos(200_000_000).build()) + .build()); + } + + TestResult result = runAttempt(grpcClient, retryClient, sequenceBuilder.build(), 10); + + assertThat(result.exception).isNotNull(); + assertThat(result.exception.getStatusCode().getCode()) + .isEqualTo(StatusCode.Code.DEADLINE_EXCEEDED); + for (int i = 0; i < 10; i++) { + assertThat(result.report.getAttempts(i).getStatus().getCode()) + .isIn(ImmutableSet.of(Code.OK.getNumber(), Code.DEADLINE_EXCEEDED.getNumber())); + } + } + } + + @Test + @SuppressWarnings("deprecation") + void testHttpJson_retryOnRpcTimeoutExceeded() throws Exception { + RetrySettings timeoutRetrySettings = + RetrySettings.newBuilder() + .setInitialRetryDelayDuration(java.time.Duration.ofMillis(10L)) + .setRetryDelayMultiplier(1.0) + .setMaxRetryDelayDuration(java.time.Duration.ofMillis(10L)) + .setInitialRpcTimeoutDuration(java.time.Duration.ofMillis(100L)) + .setRpcTimeoutMultiplier(1.0) + .setMaxRpcTimeoutDuration(java.time.Duration.ofMillis(100L)) + .setTotalTimeoutDuration(java.time.Duration.ofMillis(10000L)) + .setMaxAttempts(10) + .setJittered(false) + .build(); + + try (SequenceServiceClient retryClient = + TestClientInitializer.createHttpJsonSequenceClientWithRetrySettings( + timeoutRetrySettings, ImmutableSet.of(StatusCode.Code.DEADLINE_EXCEEDED))) { + + Sequence.Builder sequenceBuilder = Sequence.newBuilder(); + for (int i = 0; i < 10; i++) { + sequenceBuilder.addResponses( + Sequence.Response.newBuilder() + .setStatus(Status.newBuilder().setCode(Code.OK.getNumber()).build()) + .setDelay(com.google.protobuf.Duration.newBuilder().setNanos(200_000_000).build()) + .build()); + } + + TestResult result = runAttempt(httpjsonClient, retryClient, sequenceBuilder.build(), 10); + + assertThat(result.exception).isNotNull(); + assertThat(result.exception.getStatusCode().getCode()) + .isEqualTo(StatusCode.Code.DEADLINE_EXCEEDED); + for (int i = 0; i < 10; i++) { + assertThat(result.report.getAttempts(i).getStatus().getCode()) + .isIn(ImmutableSet.of(Code.OK.getNumber(), Code.DEADLINE_EXCEEDED.getNumber())); + } + } + } - // 4. Retrieve the sequence report to inspect delay measurements - SequenceReport report = - httpjsonClient.getSequenceReport( - GetSequenceReportRequest.newBuilder() - .setName(createdSequence.getName() + "/sequenceReport") - .build()); + @Test + @SuppressWarnings("deprecation") + void testGrpc_retryTotalTimeoutExceeded() throws Exception { + RetrySettings totalTimeoutRetrySettings = + RetrySettings.newBuilder() + .setInitialRetryDelayDuration(java.time.Duration.ofMillis(100L)) + .setRetryDelayMultiplier(1.0) + .setMaxRetryDelayDuration(java.time.Duration.ofMillis(100L)) + .setInitialRpcTimeoutDuration(java.time.Duration.ofMillis(2000L)) + .setRpcTimeoutMultiplier(1.0) + .setMaxRpcTimeoutDuration(java.time.Duration.ofMillis(2000L)) + .setTotalTimeoutDuration(java.time.Duration.ofMillis(1500L)) + .setMaxAttempts(10) + .setJittered(false) + .build(); + + try (SequenceServiceClient retryClient = + TestClientInitializer.createGrpcSequenceClientWithRetrySettings( + totalTimeoutRetrySettings, ImmutableSet.of(StatusCode.Code.UNAVAILABLE))) { + + Sequence sequence = + Sequence.newBuilder() + .addResponses( + Sequence.Response.newBuilder() + .setStatus(Status.newBuilder().setCode(Code.UNAVAILABLE.getNumber()).build()) + .setDelay(com.google.protobuf.Duration.newBuilder().setSeconds(1L).build()) + .build()) + .addResponses( + Sequence.Response.newBuilder() + .setStatus(Status.newBuilder().setCode(Code.UNAVAILABLE.getNumber()).build()) + .setDelay(com.google.protobuf.Duration.newBuilder().setSeconds(1L).build()) + .build()) + .addResponses( + Sequence.Response.newBuilder() + .setStatus(Status.newBuilder().setCode(Code.OK.getNumber()).build()) + .build()) + .build(); + + TestResult result = runAttempt(grpcClient, retryClient, sequence, 2); + + assertThat(result.exception).isNotNull(); + assertThat(result.exception.getStatusCode().getCode()) + .isEqualTo(StatusCode.Code.DEADLINE_EXCEEDED); + } + } + + @Test + @SuppressWarnings("deprecation") + void testHttpJson_retryTotalTimeoutExceeded() throws Exception { + RetrySettings totalTimeoutRetrySettings = + RetrySettings.newBuilder() + .setInitialRetryDelayDuration(java.time.Duration.ofMillis(10L)) + .setRetryDelayMultiplier(1.0) + .setMaxRetryDelayDuration(java.time.Duration.ofMillis(10L)) + .setInitialRpcTimeoutDuration(java.time.Duration.ofMillis(2000L)) + .setRpcTimeoutMultiplier(1.0) + .setMaxRpcTimeoutDuration(java.time.Duration.ofMillis(2000L)) + .setTotalTimeoutDuration(java.time.Duration.ofMillis(1000L)) + .setMaxAttempts(10) + .setJittered(false) + .build(); + + try (SequenceServiceClient retryClient = + TestClientInitializer.createHttpJsonSequenceClientWithRetrySettings( + totalTimeoutRetrySettings, ImmutableSet.of(StatusCode.Code.UNAVAILABLE))) { + + Sequence sequence = + Sequence.newBuilder() + .addResponses( + Sequence.Response.newBuilder() + .setStatus(Status.newBuilder().setCode(Code.UNAVAILABLE.getNumber()).build()) + .setDelay( + com.google.protobuf.Duration.newBuilder().setNanos(200_000_000).build()) + .build()) + .addResponses( + Sequence.Response.newBuilder() + .setStatus(Status.newBuilder().setCode(Code.UNAVAILABLE.getNumber()).build()) + .setDelay(com.google.protobuf.Duration.newBuilder().setSeconds(2L).build()) + .build()) + .addResponses( + Sequence.Response.newBuilder() + .setStatus(Status.newBuilder().setCode(Code.OK.getNumber()).build()) + .build()) + .build(); - // 5. Assert attempts count and delays - verifySequenceReport(report); + TestResult result = runAttempt(httpjsonClient, retryClient, sequence, 2); + + assertThat(result.exception).isNotNull(); + assertThat(result.exception.getStatusCode().getCode()) + .isEqualTo(StatusCode.Code.DEADLINE_EXCEEDED); } } @@ -161,30 +454,67 @@ private void verifySequenceReport(SequenceReport report) { assertThat(attempts).hasSize(4); // Verify the status of each attempt - assertThat(attempts.get(0).getStatus().getCode()) - .isEqualTo(com.google.rpc.Code.UNAVAILABLE.getNumber()); - assertThat(attempts.get(1).getStatus().getCode()) - .isEqualTo(com.google.rpc.Code.UNAVAILABLE.getNumber()); - assertThat(attempts.get(2).getStatus().getCode()) - .isEqualTo(com.google.rpc.Code.UNAVAILABLE.getNumber()); - assertThat(attempts.get(3).getStatus().getCode()).isEqualTo(com.google.rpc.Code.OK.getNumber()); - - // Verify delay intervals are at least the expected exponential backoff thresholds: - // Attempt 1 -> 2: scheduled 100ms. Must be at least 80ms (no upper bound) - long delay1 = getDelayMs(attempts.get(1)); - assertThat(delay1).isAtLeast(80L); - - // Attempt 2 -> 3: scheduled 200ms. Must be at least 180ms (no upper bound) - long delay2 = getDelayMs(attempts.get(2)); - assertThat(delay2).isAtLeast(180L); - - // Attempt 3 -> 4: scheduled 400ms. Must be at least 380ms (no upper bound) - long delay3 = getDelayMs(attempts.get(3)); - assertThat(delay3).isAtLeast(380L); - } - - private long getDelayMs(SequenceReport.Attempt attempt) { - com.google.protobuf.Duration attemptDelay = attempt.getAttemptDelay(); - return attemptDelay.getSeconds() * 1000 + attemptDelay.getNanos() / 1_000_000; + assertThat(attempts.get(0).getStatus().getCode()).isEqualTo(Code.UNAVAILABLE.getNumber()); + assertThat(attempts.get(1).getStatus().getCode()).isEqualTo(Code.UNAVAILABLE.getNumber()); + assertThat(attempts.get(2).getStatus().getCode()).isEqualTo(Code.UNAVAILABLE.getNumber()); + assertThat(attempts.get(3).getStatus().getCode()).isEqualTo(Code.OK.getNumber()); + } + + private Sequence buildSequence(Code... codes) { + Sequence.Builder builder = Sequence.newBuilder(); + for (Code code : codes) { + builder.addResponses( + Sequence.Response.newBuilder() + .setStatus(Status.newBuilder().setCode(code.getNumber()).build()) + .build()); + } + return builder.build(); + } + + private static class TestResult { + private final SequenceReport report; + private final ApiException exception; + + private TestResult(SequenceReport report, ApiException exception) { + this.report = report; + this.exception = exception; + } + } + + private TestResult runAttempt( + SequenceServiceClient client, + SequenceServiceClient retryClient, + Sequence sequence, + int expectedAttempts) { + Sequence createdSequence = + client.createSequence(CreateSequenceRequest.newBuilder().setSequence(sequence).build()); + + ApiException exception = null; + try { + retryClient.attemptSequence( + AttemptSequenceRequest.newBuilder().setName(createdSequence.getName()).build()); + } catch (ApiException e) { + exception = e; + } + + Awaitility.await() + .atMost(Duration.ofSeconds(3)) + .untilAsserted( + () -> { + SequenceReport report = + client.getSequenceReport( + GetSequenceReportRequest.newBuilder() + .setName(createdSequence.getName() + "/sequenceReport") + .build()); + assertThat(report.getAttemptsCount()).isEqualTo(expectedAttempts); + }); + + SequenceReport finalReport = + client.getSequenceReport( + GetSequenceReportRequest.newBuilder() + .setName(createdSequence.getName() + "/sequenceReport") + .build()); + + return new TestResult(finalReport, exception); } } From 0fd959092a06ecf4893e566b20ab27305f183938 Mon Sep 17 00:00:00 2001 From: Nicole Lee Date: Thu, 30 Jul 2026 06:01:38 +0000 Subject: [PATCH 5/7] test(showcase): removed fully qualified names --- .../google/showcase/v1beta1/it/ITRetries.java | 92 +++++++++---------- 1 file changed, 41 insertions(+), 51 deletions(-) diff --git a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITRetries.java b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITRetries.java index ebd0bb38441c..14627e1d0261 100644 --- a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITRetries.java +++ b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITRetries.java @@ -22,6 +22,7 @@ import com.google.api.gax.rpc.ApiException; import com.google.api.gax.rpc.StatusCode; import com.google.common.collect.ImmutableSet; +import com.google.protobuf.util.Durations; import com.google.rpc.Code; import com.google.rpc.Status; import com.google.showcase.v1beta1.AttemptSequenceRequest; @@ -45,42 +46,32 @@ class ITRetries { Sequence.newBuilder() .addResponses( Sequence.Response.newBuilder() - .setStatus( - Status.newBuilder() - .setCode(com.google.rpc.Code.UNAVAILABLE.getNumber()) - .build()) + .setStatus(Status.newBuilder().setCode(Code.UNAVAILABLE.getNumber()).build()) .build()) .addResponses( Sequence.Response.newBuilder() - .setStatus( - Status.newBuilder() - .setCode(com.google.rpc.Code.UNAVAILABLE.getNumber()) - .build()) + .setStatus(Status.newBuilder().setCode(Code.UNAVAILABLE.getNumber()).build()) .build()) .addResponses( Sequence.Response.newBuilder() - .setStatus( - Status.newBuilder() - .setCode(com.google.rpc.Code.UNAVAILABLE.getNumber()) - .build()) + .setStatus(Status.newBuilder().setCode(Code.UNAVAILABLE.getNumber()).build()) .build()) .addResponses( Sequence.Response.newBuilder() - .setStatus( - Status.newBuilder().setCode(com.google.rpc.Code.OK.getNumber()).build()) + .setStatus(Status.newBuilder().setCode(Code.OK.getNumber()).build()) .build()) .build(); @SuppressWarnings("deprecation") private static final RetrySettings STANDARD_RETRY_SETTINGS = RetrySettings.newBuilder() - .setInitialRetryDelayDuration(java.time.Duration.ofMillis(100L)) + .setInitialRetryDelayDuration(Duration.ofMillis(100L)) .setRetryDelayMultiplier(2.0) - .setMaxRetryDelayDuration(java.time.Duration.ofMillis(1000L)) - .setInitialRpcTimeoutDuration(java.time.Duration.ofMillis(1000L)) + .setMaxRetryDelayDuration(Duration.ofMillis(1000L)) + .setInitialRpcTimeoutDuration(Duration.ofMillis(1000L)) .setRpcTimeoutMultiplier(1.0) - .setMaxRpcTimeoutDuration(java.time.Duration.ofMillis(1000L)) - .setTotalTimeoutDuration(java.time.Duration.ofMillis(5000L)) + .setMaxRpcTimeoutDuration(Duration.ofMillis(1000L)) + .setTotalTimeoutDuration(Duration.ofMillis(5000L)) .setMaxAttempts(4) .setJittered(false) .build(); @@ -88,13 +79,13 @@ class ITRetries { @SuppressWarnings("deprecation") private static final RetrySettings NO_RETRY_SETTINGS = RetrySettings.newBuilder() - .setInitialRetryDelayDuration(java.time.Duration.ofMillis(100L)) + .setInitialRetryDelayDuration(Duration.ofMillis(100L)) .setRetryDelayMultiplier(2.0) - .setMaxRetryDelayDuration(java.time.Duration.ofMillis(1000L)) - .setInitialRpcTimeoutDuration(java.time.Duration.ofMillis(1000L)) + .setMaxRetryDelayDuration(Duration.ofMillis(1000L)) + .setInitialRpcTimeoutDuration(Duration.ofMillis(1000L)) .setRpcTimeoutMultiplier(1.0) - .setMaxRpcTimeoutDuration(java.time.Duration.ofMillis(1000L)) - .setTotalTimeoutDuration(java.time.Duration.ofMillis(5000L)) + .setMaxRpcTimeoutDuration(Duration.ofMillis(1000L)) + .setTotalTimeoutDuration(Duration.ofMillis(5000L)) .setMaxAttempts(1) .setJittered(false) .build(); @@ -279,13 +270,13 @@ void testHttpJson_retryMultipleStatus() throws Exception { void testGrpc_retryOnRpcTimeoutExceeded() throws Exception { RetrySettings timeoutRetrySettings = RetrySettings.newBuilder() - .setInitialRetryDelayDuration(java.time.Duration.ofMillis(10L)) + .setInitialRetryDelayDuration(Duration.ofMillis(10L)) .setRetryDelayMultiplier(1.0) - .setMaxRetryDelayDuration(java.time.Duration.ofMillis(10L)) - .setInitialRpcTimeoutDuration(java.time.Duration.ofMillis(100L)) + .setMaxRetryDelayDuration(Duration.ofMillis(10L)) + .setInitialRpcTimeoutDuration(Duration.ofMillis(100L)) .setRpcTimeoutMultiplier(1.0) - .setMaxRpcTimeoutDuration(java.time.Duration.ofMillis(100L)) - .setTotalTimeoutDuration(java.time.Duration.ofMillis(10000L)) + .setMaxRpcTimeoutDuration(Duration.ofMillis(100L)) + .setTotalTimeoutDuration(Duration.ofMillis(10000L)) .setMaxAttempts(10) .setJittered(false) .build(); @@ -299,7 +290,7 @@ void testGrpc_retryOnRpcTimeoutExceeded() throws Exception { sequenceBuilder.addResponses( Sequence.Response.newBuilder() .setStatus(Status.newBuilder().setCode(Code.OK.getNumber()).build()) - .setDelay(com.google.protobuf.Duration.newBuilder().setNanos(200_000_000).build()) + .setDelay(Durations.fromMillis(200L)) .build()); } @@ -320,13 +311,13 @@ void testGrpc_retryOnRpcTimeoutExceeded() throws Exception { void testHttpJson_retryOnRpcTimeoutExceeded() throws Exception { RetrySettings timeoutRetrySettings = RetrySettings.newBuilder() - .setInitialRetryDelayDuration(java.time.Duration.ofMillis(10L)) + .setInitialRetryDelayDuration(Duration.ofMillis(10L)) .setRetryDelayMultiplier(1.0) - .setMaxRetryDelayDuration(java.time.Duration.ofMillis(10L)) - .setInitialRpcTimeoutDuration(java.time.Duration.ofMillis(100L)) + .setMaxRetryDelayDuration(Duration.ofMillis(10L)) + .setInitialRpcTimeoutDuration(Duration.ofMillis(100L)) .setRpcTimeoutMultiplier(1.0) - .setMaxRpcTimeoutDuration(java.time.Duration.ofMillis(100L)) - .setTotalTimeoutDuration(java.time.Duration.ofMillis(10000L)) + .setMaxRpcTimeoutDuration(Duration.ofMillis(100L)) + .setTotalTimeoutDuration(Duration.ofMillis(10000L)) .setMaxAttempts(10) .setJittered(false) .build(); @@ -340,7 +331,7 @@ void testHttpJson_retryOnRpcTimeoutExceeded() throws Exception { sequenceBuilder.addResponses( Sequence.Response.newBuilder() .setStatus(Status.newBuilder().setCode(Code.OK.getNumber()).build()) - .setDelay(com.google.protobuf.Duration.newBuilder().setNanos(200_000_000).build()) + .setDelay(Durations.fromMillis(200L)) .build()); } @@ -361,13 +352,13 @@ void testHttpJson_retryOnRpcTimeoutExceeded() throws Exception { void testGrpc_retryTotalTimeoutExceeded() throws Exception { RetrySettings totalTimeoutRetrySettings = RetrySettings.newBuilder() - .setInitialRetryDelayDuration(java.time.Duration.ofMillis(100L)) + .setInitialRetryDelayDuration(Duration.ofMillis(100L)) .setRetryDelayMultiplier(1.0) - .setMaxRetryDelayDuration(java.time.Duration.ofMillis(100L)) - .setInitialRpcTimeoutDuration(java.time.Duration.ofMillis(2000L)) + .setMaxRetryDelayDuration(Duration.ofMillis(100L)) + .setInitialRpcTimeoutDuration(Duration.ofMillis(2000L)) .setRpcTimeoutMultiplier(1.0) - .setMaxRpcTimeoutDuration(java.time.Duration.ofMillis(2000L)) - .setTotalTimeoutDuration(java.time.Duration.ofMillis(1500L)) + .setMaxRpcTimeoutDuration(Duration.ofMillis(2000L)) + .setTotalTimeoutDuration(Duration.ofMillis(1500L)) .setMaxAttempts(10) .setJittered(false) .build(); @@ -381,12 +372,12 @@ void testGrpc_retryTotalTimeoutExceeded() throws Exception { .addResponses( Sequence.Response.newBuilder() .setStatus(Status.newBuilder().setCode(Code.UNAVAILABLE.getNumber()).build()) - .setDelay(com.google.protobuf.Duration.newBuilder().setSeconds(1L).build()) + .setDelay(Durations.fromSeconds(1L)) .build()) .addResponses( Sequence.Response.newBuilder() .setStatus(Status.newBuilder().setCode(Code.UNAVAILABLE.getNumber()).build()) - .setDelay(com.google.protobuf.Duration.newBuilder().setSeconds(1L).build()) + .setDelay(Durations.fromSeconds(1L)) .build()) .addResponses( Sequence.Response.newBuilder() @@ -407,13 +398,13 @@ void testGrpc_retryTotalTimeoutExceeded() throws Exception { void testHttpJson_retryTotalTimeoutExceeded() throws Exception { RetrySettings totalTimeoutRetrySettings = RetrySettings.newBuilder() - .setInitialRetryDelayDuration(java.time.Duration.ofMillis(10L)) + .setInitialRetryDelayDuration(Duration.ofMillis(10L)) .setRetryDelayMultiplier(1.0) - .setMaxRetryDelayDuration(java.time.Duration.ofMillis(10L)) - .setInitialRpcTimeoutDuration(java.time.Duration.ofMillis(2000L)) + .setMaxRetryDelayDuration(Duration.ofMillis(10L)) + .setInitialRpcTimeoutDuration(Duration.ofMillis(2000L)) .setRpcTimeoutMultiplier(1.0) - .setMaxRpcTimeoutDuration(java.time.Duration.ofMillis(2000L)) - .setTotalTimeoutDuration(java.time.Duration.ofMillis(1000L)) + .setMaxRpcTimeoutDuration(Duration.ofMillis(2000L)) + .setTotalTimeoutDuration(Duration.ofMillis(1000L)) .setMaxAttempts(10) .setJittered(false) .build(); @@ -427,13 +418,12 @@ void testHttpJson_retryTotalTimeoutExceeded() throws Exception { .addResponses( Sequence.Response.newBuilder() .setStatus(Status.newBuilder().setCode(Code.UNAVAILABLE.getNumber()).build()) - .setDelay( - com.google.protobuf.Duration.newBuilder().setNanos(200_000_000).build()) + .setDelay(Durations.fromMillis(200L)) .build()) .addResponses( Sequence.Response.newBuilder() .setStatus(Status.newBuilder().setCode(Code.UNAVAILABLE.getNumber()).build()) - .setDelay(com.google.protobuf.Duration.newBuilder().setSeconds(2L).build()) + .setDelay(Durations.fromSeconds(2L)) .build()) .addResponses( Sequence.Response.newBuilder() From e698ada583c2ebe1175ed245f3cdf15ee946482d Mon Sep 17 00:00:00 2001 From: Nicole Lee Date: Thu, 30 Jul 2026 14:16:50 +0000 Subject: [PATCH 6/7] test(showcase): removed redundant deprecation annotations --- .../com/google/showcase/v1beta1/it/ITRetries.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITRetries.java b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITRetries.java index 14627e1d0261..1c2ef4756b65 100644 --- a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITRetries.java +++ b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITRetries.java @@ -110,7 +110,6 @@ static void destroyClients() throws InterruptedException { } @Test - @SuppressWarnings("deprecation") void testGrpc_retryExponentialBackoff() throws Exception { try (SequenceServiceClient retryClient = TestClientInitializer.createGrpcSequenceClientWithRetrySettings( @@ -124,7 +123,6 @@ void testGrpc_retryExponentialBackoff() throws Exception { } @Test - @SuppressWarnings("deprecation") void testHttpJson_retryExponentialBackoff() throws Exception { try (SequenceServiceClient retryClient = TestClientInitializer.createHttpJsonSequenceClientWithRetrySettings( @@ -138,7 +136,6 @@ void testHttpJson_retryExponentialBackoff() throws Exception { } @Test - @SuppressWarnings("deprecation") void testGrpc_noRetry() throws Exception { try (SequenceServiceClient retryClient = TestClientInitializer.createGrpcSequenceClientWithRetrySettings( @@ -156,7 +153,6 @@ void testGrpc_noRetry() throws Exception { } @Test - @SuppressWarnings("deprecation") void testHttpJson_noRetry() throws Exception { try (SequenceServiceClient retryClient = TestClientInitializer.createHttpJsonSequenceClientWithRetrySettings( @@ -174,7 +170,6 @@ void testHttpJson_noRetry() throws Exception { } @Test - @SuppressWarnings("deprecation") void testGrpc_nonRetryableError() throws Exception { try (SequenceServiceClient retryClient = TestClientInitializer.createGrpcSequenceClientWithRetrySettings( @@ -193,7 +188,6 @@ void testGrpc_nonRetryableError() throws Exception { } @Test - @SuppressWarnings("deprecation") void testHttpJson_nonRetryableError() throws Exception { try (SequenceServiceClient retryClient = TestClientInitializer.createHttpJsonSequenceClientWithRetrySettings( @@ -212,7 +206,6 @@ void testHttpJson_nonRetryableError() throws Exception { } @Test - @SuppressWarnings("deprecation") void testGrpc_retryMultipleStatus() throws Exception { try (SequenceServiceClient retryClient = TestClientInitializer.createGrpcSequenceClientWithRetrySettings( @@ -239,7 +232,6 @@ void testGrpc_retryMultipleStatus() throws Exception { } @Test - @SuppressWarnings("deprecation") void testHttpJson_retryMultipleStatus() throws Exception { try (SequenceServiceClient retryClient = TestClientInitializer.createHttpJsonSequenceClientWithRetrySettings( @@ -266,7 +258,6 @@ void testHttpJson_retryMultipleStatus() throws Exception { } @Test - @SuppressWarnings("deprecation") void testGrpc_retryOnRpcTimeoutExceeded() throws Exception { RetrySettings timeoutRetrySettings = RetrySettings.newBuilder() @@ -307,7 +298,6 @@ void testGrpc_retryOnRpcTimeoutExceeded() throws Exception { } @Test - @SuppressWarnings("deprecation") void testHttpJson_retryOnRpcTimeoutExceeded() throws Exception { RetrySettings timeoutRetrySettings = RetrySettings.newBuilder() @@ -348,7 +338,6 @@ void testHttpJson_retryOnRpcTimeoutExceeded() throws Exception { } @Test - @SuppressWarnings("deprecation") void testGrpc_retryTotalTimeoutExceeded() throws Exception { RetrySettings totalTimeoutRetrySettings = RetrySettings.newBuilder() @@ -394,7 +383,6 @@ void testGrpc_retryTotalTimeoutExceeded() throws Exception { } @Test - @SuppressWarnings("deprecation") void testHttpJson_retryTotalTimeoutExceeded() throws Exception { RetrySettings totalTimeoutRetrySettings = RetrySettings.newBuilder() From 50777888557be49444c39a3a1e44d6c24577f6b6 Mon Sep 17 00:00:00 2001 From: Nicole Lee Date: Thu, 30 Jul 2026 14:24:14 +0000 Subject: [PATCH 7/7] test(showcase): added comments --- .../google/showcase/v1beta1/it/ITRetries.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITRetries.java b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITRetries.java index 1c2ef4756b65..40a91af70f50 100644 --- a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITRetries.java +++ b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITRetries.java @@ -40,6 +40,10 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +/** + * Integration tests for verifying that client libraries correctly handle retry behaviors and + * timeout settings over gRPC and HTTP/JSON transports. + */ class ITRetries { private static final Sequence STANDARD_SEQUENCE = @@ -109,6 +113,8 @@ static void destroyClients() throws InterruptedException { TestClientInitializer.AWAIT_TERMINATION_SECONDS, TimeUnit.SECONDS); } + // Tests that the client retries on UNAVAILABLE errors up to maxAttempts (4) and succeeds when + // receiving OK. @Test void testGrpc_retryExponentialBackoff() throws Exception { try (SequenceServiceClient retryClient = @@ -122,6 +128,8 @@ void testGrpc_retryExponentialBackoff() throws Exception { } } + // Tests that the client retries on UNAVAILABLE errors up to maxAttempts (4) and succeeds when + // receiving OK. @Test void testHttpJson_retryExponentialBackoff() throws Exception { try (SequenceServiceClient retryClient = @@ -135,6 +143,8 @@ void testHttpJson_retryExponentialBackoff() throws Exception { } } + // Tests that configuring maxAttempts = 1 causes the client to fail immediately on the first error + // without retrying. @Test void testGrpc_noRetry() throws Exception { try (SequenceServiceClient retryClient = @@ -152,6 +162,8 @@ void testGrpc_noRetry() throws Exception { } } + // Tests that configuring maxAttempts = 1 causes the client to fail immediately on the first error + // without retrying. @Test void testHttpJson_noRetry() throws Exception { try (SequenceServiceClient retryClient = @@ -169,6 +181,8 @@ void testHttpJson_noRetry() throws Exception { } } + // Tests that encountering a non-retryable error (INVALID_ARGUMENT) stops retries immediately, + // even if maxAttempts > 1. @Test void testGrpc_nonRetryableError() throws Exception { try (SequenceServiceClient retryClient = @@ -187,6 +201,8 @@ void testGrpc_nonRetryableError() throws Exception { } } + // Tests that encountering a non-retryable error (INVALID_ARGUMENT) stops retries immediately, + // even if maxAttempts > 1. @Test void testHttpJson_nonRetryableError() throws Exception { try (SequenceServiceClient retryClient = @@ -205,6 +221,8 @@ void testHttpJson_nonRetryableError() throws Exception { } } + // Tests that the client retries through a sequence of different retryable status codes + // (UNAVAILABLE -> RESOURCE_EXHAUSTED -> DEADLINE_EXCEEDED). @Test void testGrpc_retryMultipleStatus() throws Exception { try (SequenceServiceClient retryClient = @@ -231,6 +249,8 @@ void testGrpc_retryMultipleStatus() throws Exception { } } + // Tests that the client retries through a sequence of different retryable status codes + // (UNAVAILABLE -> RESOURCE_EXHAUSTED -> DEADLINE_EXCEEDED). @Test void testHttpJson_retryMultipleStatus() throws Exception { try (SequenceServiceClient retryClient = @@ -257,6 +277,8 @@ void testHttpJson_retryMultipleStatus() throws Exception { } } + // Tests that individual attempt timeouts (rpcTimeout) trigger a retry when the server response + // delay exceeds the timeout. @Test void testGrpc_retryOnRpcTimeoutExceeded() throws Exception { RetrySettings timeoutRetrySettings = @@ -297,6 +319,8 @@ void testGrpc_retryOnRpcTimeoutExceeded() throws Exception { } } + // Tests that individual attempt timeouts (rpcTimeout) trigger a retry when the server response + // delay exceeds the timeout. @Test void testHttpJson_retryOnRpcTimeoutExceeded() throws Exception { RetrySettings timeoutRetrySettings = @@ -337,6 +361,8 @@ void testHttpJson_retryOnRpcTimeoutExceeded() throws Exception { } } + // Tests that the operation deadline (totalTimeout) halts the retry loop when cumulative delay + // exceeds totalTimeout. @Test void testGrpc_retryTotalTimeoutExceeded() throws Exception { RetrySettings totalTimeoutRetrySettings = @@ -382,6 +408,8 @@ void testGrpc_retryTotalTimeoutExceeded() throws Exception { } } + // Tests that the operation deadline (totalTimeout) halts the retry loop when cumulative delay + // exceeds totalTimeout. @Test void testHttpJson_retryTotalTimeoutExceeded() throws Exception { RetrySettings totalTimeoutRetrySettings =