From c02a74732a96daee2bcff1c4096e7cade54312d1 Mon Sep 17 00:00:00 2001 From: blakeli Date: Fri, 10 Jul 2026 16:37:24 -0400 Subject: [PATCH 1/3] chore(showcase): migrate Thread.sleep calls to Awaitility --- java-showcase/gapic-showcase/pom.xml | 7 ++++ .../showcase/v1beta1/it/ITClientShutdown.java | 9 ++--- .../v1beta1/it/ITCompositeTracer.java | 10 ++--- .../v1beta1/it/ITOtelGoldenMetrics.java | 32 ++++++++-------- .../showcase/v1beta1/it/ITOtelMetrics.java | 38 +++++++++++-------- 5 files changed, 53 insertions(+), 43 deletions(-) diff --git a/java-showcase/gapic-showcase/pom.xml b/java-showcase/gapic-showcase/pom.xml index e36caea4a8a5..361cafd71360 100644 --- a/java-showcase/gapic-showcase/pom.xml +++ b/java-showcase/gapic-showcase/pom.xml @@ -257,6 +257,13 @@ test + + org.awaitility + awaitility + 4.3.0 + test + + diff --git a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITClientShutdown.java b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITClientShutdown.java index e55ee8d1ed5a..7fe91c068e3f 100644 --- a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITClientShutdown.java +++ b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITClientShutdown.java @@ -143,12 +143,9 @@ private void assertClientTerminated(EchoClient echoClient) throws InterruptedExc // check that everything is properly terminated after close() is called. echoClient.close(); - // Loop until the client has terminated successfully. For tests that use this, - // try to ensure there is a timeout associated, otherwise this may run forever. - // Future enhancement: Use awaitility instead of busy waiting - while (!echoClient.isTerminated()) { - Thread.sleep(500L); - } + org.awaitility.Awaitility.await() + .atMost(java.time.Duration.ofMillis(DEFAULT_CLIENT_TERMINATION_MS)) + .until(echoClient::isTerminated); // The busy-wait time won't be accurate, so account for a bit of buffer long end = System.currentTimeMillis(); diff --git a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITCompositeTracer.java b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITCompositeTracer.java index b1a66f206c6b..a3385171b72a 100644 --- a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITCompositeTracer.java +++ b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITCompositeTracer.java @@ -49,9 +49,11 @@ import io.opentelemetry.sdk.trace.SdkTracerProvider; import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; +import java.time.Duration; import java.util.Arrays; import java.util.Collection; import java.util.List; +import org.awaitility.Awaitility; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -124,13 +126,11 @@ void testCompositeTracer() throws Exception { .get(AttributeKey.stringKey(ObservabilityAttributes.SERVER_ADDRESS_ATTRIBUTE))) .isEqualTo(SHOWCASE_SERVER_ADDRESS); - Thread.sleep(100); // Verify metric name and one basic attribute server.address + Awaitility.await() + .atMost(Duration.ofSeconds(10)) + .until(() -> !metricReader.collectAllMetrics().isEmpty()); Collection actualMetrics = metricReader.collectAllMetrics(); - for (int i = 0; i < 10 && actualMetrics.isEmpty(); i++) { - Thread.sleep(1000L); - actualMetrics = metricReader.collectAllMetrics(); - } assertThat(actualMetrics).isNotEmpty(); MetricData metricData = diff --git a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelGoldenMetrics.java b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelGoldenMetrics.java index 5385ecc67774..b2df38c94fb0 100644 --- a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelGoldenMetrics.java +++ b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelGoldenMetrics.java @@ -63,6 +63,7 @@ import java.io.InputStream; import java.time.Duration; import java.util.Collection; +import org.awaitility.Awaitility; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -106,8 +107,7 @@ void testMetrics_successfulEcho_grpc() throws Exception { // This is implemented by adding a TraceFinisher to ApiFuture as a callback in // TracedUnaryCallable, // which could be executed in a different thread. - Thread.sleep(100); - Collection metrics = metricReader.collectAllMetrics(); + Collection metrics = waitAndCollectMetrics(); assertThat(metrics).isNotEmpty(); MetricData durationMetric = @@ -192,8 +192,7 @@ public void sendMessage(ReqT message) {} UnavailableException.class, () -> client.echo(EchoRequest.newBuilder().setContent("metrics-test").build())); - Thread.sleep(100); - Collection metrics = metricReader.collectAllMetrics(); + Collection metrics = waitAndCollectMetrics(); assertThat(metrics).isNotEmpty(); MetricData durationMetric = @@ -224,8 +223,7 @@ void testMetrics_successfulEcho_httpjson() throws Exception { client.echo(EchoRequest.newBuilder().setContent("metrics-test").build()); - Thread.sleep(100); - Collection metrics = metricReader.collectAllMetrics(); + Collection metrics = waitAndCollectMetrics(); assertThat(metrics).isNotEmpty(); MetricData durationMetric = @@ -366,8 +364,7 @@ public String getHeaderValue(int index) { UnavailableException.class, () -> client.echo(EchoRequest.newBuilder().setContent("metrics-test").build())); - Thread.sleep(100); - Collection metrics = metricReader.collectAllMetrics(); + Collection metrics = waitAndCollectMetrics(); assertThat(metrics).isNotEmpty(); MetricData durationMetric = @@ -415,8 +412,7 @@ void testMetrics_clientTimeout_grpc() throws Exception { Exception.class, () -> client.echo(EchoRequest.newBuilder().setContent("metrics-test").build())); - Thread.sleep(100); - Collection metrics = metricReader.collectAllMetrics(); + Collection metrics = waitAndCollectMetrics(); assertThat(metrics).isNotEmpty(); MetricData durationMetric = @@ -458,8 +454,7 @@ void testMetrics_clientTimeout_httpjson() throws Exception { Exception.class, () -> client.echo(EchoRequest.newBuilder().setContent("metrics-test").build())); - Thread.sleep(100); - Collection metrics = metricReader.collectAllMetrics(); + Collection metrics = waitAndCollectMetrics(); assertThat(metrics).isNotEmpty(); MetricData durationMetric = @@ -538,8 +533,7 @@ public void sendMessage(ReqT message) {} assertThat(attemptCount.get()).isEqualTo(3); - Thread.sleep(100); - Collection metrics = metricReader.collectAllMetrics(); + Collection metrics = waitAndCollectMetrics(); assertThat(metrics).hasSize(1); MetricData durationMetric = @@ -709,8 +703,7 @@ public String getHeaderValue(int index) { assertThat(requestCount.get()).isEqualTo(3); - Thread.sleep(100); - Collection metrics = metricReader.collectAllMetrics(); + Collection metrics = waitAndCollectMetrics(); assertThat(metrics).hasSize(1); MetricData durationMetric = @@ -730,4 +723,11 @@ public String getHeaderValue(int index) { .isEqualTo("OK"); } } + + private Collection waitAndCollectMetrics() { + Awaitility.await() + .atMost(Duration.ofSeconds(5)) + .until(() -> !metricReader.collectAllMetrics().isEmpty()); + return metricReader.collectAllMetrics(); + } } diff --git a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelMetrics.java b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelMetrics.java index ad973e4137b2..7bfbb47f7d41 100644 --- a/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelMetrics.java +++ b/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelMetrics.java @@ -83,6 +83,7 @@ import java.util.concurrent.TimeUnit; import java.util.function.Predicate; import java.util.stream.Collectors; +import org.awaitility.Awaitility; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; @@ -290,24 +291,29 @@ private List getMetricDataList() throws InterruptedException { } /** - * Attempts to retrieve the metrics from a custom InMemoryMetricsReader. Sleep every second for at - * most 10s to try and retrieve all the metrics available. If it is unable to retrieve all the - * metrics, fail the test. + * Attempts to retrieve the metrics from a custom InMemoryMetricsReader. Polls for at most 10s to + * try and retrieve all the metrics available. If it is unable to retrieve all the metrics, fail + * the test. */ private List getMetricDataList(InMemoryMetricReader metricReader) throws InterruptedException { - for (int i = 0; i < NUM_DEFAULT_FLUSH_ATTEMPTS; i++) { - Thread.sleep(1000L); - List metricData = new ArrayList<>(metricReader.collectAllMetrics()); - // Depending on the OpenTelemetry instance (i.e. OpenTelemetry, GrpcOpenTelemetry, etc.) - // there may be additional metrics recorded. Only check to ensure the Gax Metrics - // are recorded properly. Any additional metrics are fine to be passed. - if (metricData.size() >= NUM_GAX_OTEL_METRICS && areAllGaxMetricsRecorded(metricData)) { - return metricData; - } + try { + Awaitility.await() + .atMost(java.time.Duration.ofSeconds(NUM_DEFAULT_FLUSH_ATTEMPTS)) + .until( + () -> { + List metricData = new ArrayList<>(metricReader.collectAllMetrics()); + // Depending on the OpenTelemetry instance (i.e. OpenTelemetry, GrpcOpenTelemetry, + // etc.) + // there may be additional metrics recorded. Only check to ensure the Gax Metrics + // are recorded properly. Any additional metrics are fine to be passed. + return metricData.size() >= NUM_GAX_OTEL_METRICS + && areAllGaxMetricsRecorded(metricData); + }); + } catch (org.awaitility.core.ConditionTimeoutException e) { + Assertions.fail("Unable to collect all the GAX metrics required for the test"); } - Assertions.fail("Unable to collect all the GAX metrics required for the test"); - return new ArrayList<>(); + return new ArrayList<>(metricReader.collectAllMetrics()); } private boolean areAllGaxMetricsRecorded(List metricData) { @@ -370,7 +376,7 @@ void testGrpc_operationCancelled_recordsMetrics() throws Exception { UnaryCallable blockCallable = grpcClient.blockCallable(); ApiFuture blockResponseApiFuture = blockCallable.futureCall(blockRequest); // Sleep 1s before cancelling to let the request go through - Thread.sleep(1000); + Awaitility.await().pollDelay(java.time.Duration.ofSeconds(1)).until(() -> true); blockResponseApiFuture.cancel(true); List actualMetricDataList = getMetricDataList(); @@ -397,7 +403,7 @@ void testHttpJson_operationCancelled_recordsMetrics() throws Exception { UnaryCallable blockCallable = httpClient.blockCallable(); ApiFuture blockResponseApiFuture = blockCallable.futureCall(blockRequest); // Sleep 1s before cancelling to let the request go through - Thread.sleep(1000); + Awaitility.await().pollDelay(java.time.Duration.ofSeconds(1)).until(() -> true); blockResponseApiFuture.cancel(true); List actualMetricDataList = getMetricDataList(); From d9b0c5cd28ffc8fa0401e7680dcd1805afabce7c Mon Sep 17 00:00:00 2001 From: blakeli Date: Fri, 10 Jul 2026 16:58:55 -0400 Subject: [PATCH 2/3] chore(showcase): remove explicit awaitility version --- java-showcase/gapic-showcase/pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/java-showcase/gapic-showcase/pom.xml b/java-showcase/gapic-showcase/pom.xml index 361cafd71360..c5bda748cf2e 100644 --- a/java-showcase/gapic-showcase/pom.xml +++ b/java-showcase/gapic-showcase/pom.xml @@ -260,7 +260,6 @@ org.awaitility awaitility - 4.3.0 test From 2ecd810f15692e51cd2dd2bbf4645918b51ed853 Mon Sep 17 00:00:00 2001 From: blakeli Date: Fri, 10 Jul 2026 17:27:39 -0400 Subject: [PATCH 3/3] chore(ci): exclude java-showcase from bulk unit tests --- .github/workflows/ci.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 51f8ba78129b..90c49bbf66f6 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -51,8 +51,8 @@ jobs: workflows: - '.github/workflows/**' src: - - '!(google-auth-library-java|grpc-gcp-java|java-bigquery|java-bigquery-jdbc|java-bigquerystorage|java-bigtable|java-cloud-bom|java-datastore|java-firestore|java-logging|java-logging-logback|java-pubsub|java-shared-config|java-spanner|java-storage)/**/*.java' - - '!(google-auth-library-java|grpc-gcp-java|java-bigquery|java-bigquery-jdbc|java-bigquerystorage|java-bigtable|java-cloud-bom|java-datastore|java-firestore|java-logging|java-logging-logback|java-pubsub|java-shared-config|java-spanner|java-storage)/**/pom.xml' + - '!(google-auth-library-java|grpc-gcp-java|java-bigquery|java-bigquery-jdbc|java-bigquerystorage|java-bigtable|java-cloud-bom|java-datastore|java-firestore|java-logging|java-logging-logback|java-pubsub|java-shared-config|java-showcase|java-spanner|java-storage)/**/*.java' + - '!(google-auth-library-java|grpc-gcp-java|java-bigquery|java-bigquery-jdbc|java-bigquerystorage|java-bigtable|java-cloud-bom|java-datastore|java-firestore|java-logging|java-logging-logback|java-pubsub|java-shared-config|java-showcase|java-spanner|java-storage)/**/pom.xml' - 'pom.xml' ci: - '.github/workflows/ci.yaml'