Skip to content

Commit 433c431

Browse files
committed
Add retry metrics tests to ITOtelGoldenMetrics
1 parent 6675310 commit 433c431

2 files changed

Lines changed: 387 additions & 0 deletions

File tree

sdk-platform-java/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITOtelGoldenMetrics.java

Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,4 +379,305 @@ public String getHeaderValue(int index) {
379379
.isEqualTo("503");
380380
}
381381
}
382+
383+
@Test
384+
void testMetrics_zeroDeadline_grpc() throws Exception {
385+
GoldenSignalsMetricsTracerFactory tracerFactory =
386+
new GoldenSignalsMetricsTracerFactory(openTelemetrySdk);
387+
388+
// Using 1ms as 0ms might be rejected by some validation or trigger immediate failure before
389+
// metrics
390+
RetrySettings zeroRetrySettings =
391+
RetrySettings.newBuilder()
392+
.setInitialRpcTimeout(org.threeten.bp.Duration.ofMillis(1))
393+
.setMaxRpcTimeout(org.threeten.bp.Duration.ofMillis(1))
394+
.setTotalTimeout(org.threeten.bp.Duration.ofMillis(1))
395+
.setMaxAttempts(1)
396+
.build();
397+
398+
try (EchoClient client =
399+
TestClientInitializer.createGrpcEchoClientOpentelemetryWithRetrySettings(
400+
tracerFactory, zeroRetrySettings)) {
401+
402+
assertThrows(
403+
Exception.class,
404+
() -> client.echo(EchoRequest.newBuilder().setContent("metrics-test").build()));
405+
406+
Thread.sleep(100);
407+
Collection<MetricData> metrics = metricReader.collectAllMetrics();
408+
assertThat(metrics).isNotEmpty();
409+
410+
MetricData durationMetric =
411+
metrics.stream()
412+
.filter(m -> m.getName().equals("gcp.client.request.duration"))
413+
.findFirst()
414+
.orElseThrow(() -> new AssertionError("Duration metric not found"));
415+
416+
io.opentelemetry.api.common.Attributes attributes =
417+
durationMetric.getHistogramData().getPoints().iterator().next().getAttributes();
418+
419+
assertThat(
420+
attributes.get(
421+
AttributeKey.stringKey(ObservabilityAttributes.RPC_RESPONSE_STATUS_ATTRIBUTE)))
422+
.isEqualTo("DEADLINE_EXCEEDED");
423+
assertThat(
424+
attributes.get(AttributeKey.stringKey(ObservabilityAttributes.ERROR_TYPE_ATTRIBUTE)))
425+
.isEqualTo("DEADLINE_EXCEEDED");
426+
}
427+
}
428+
429+
@Test
430+
void testMetrics_zeroDeadline_httpjson() throws Exception {
431+
GoldenSignalsMetricsTracerFactory tracerFactory =
432+
new GoldenSignalsMetricsTracerFactory(openTelemetrySdk);
433+
434+
RetrySettings zeroRetrySettings =
435+
RetrySettings.newBuilder()
436+
.setInitialRpcTimeout(org.threeten.bp.Duration.ofMillis(1))
437+
.setMaxRpcTimeout(org.threeten.bp.Duration.ofMillis(1))
438+
.setTotalTimeout(org.threeten.bp.Duration.ofMillis(1))
439+
.setMaxAttempts(1)
440+
.build();
441+
442+
try (EchoClient client =
443+
TestClientInitializer.createHttpJsonEchoClientOpentelemetryWithRetrySettings(
444+
tracerFactory, zeroRetrySettings)) {
445+
446+
assertThrows(
447+
Exception.class,
448+
() -> client.echo(EchoRequest.newBuilder().setContent("metrics-test").build()));
449+
450+
Thread.sleep(100);
451+
Collection<MetricData> metrics = metricReader.collectAllMetrics();
452+
assertThat(metrics).isNotEmpty();
453+
454+
MetricData durationMetric =
455+
metrics.stream()
456+
.filter(m -> m.getName().equals("gcp.client.request.duration"))
457+
.findFirst()
458+
.orElseThrow(() -> new AssertionError("Duration metric not found"));
459+
460+
io.opentelemetry.api.common.Attributes attributes =
461+
durationMetric.getHistogramData().getPoints().iterator().next().getAttributes();
462+
463+
assertThat(
464+
attributes.get(
465+
AttributeKey.stringKey(ObservabilityAttributes.RPC_RESPONSE_STATUS_ATTRIBUTE)))
466+
.isEqualTo("DEADLINE_EXCEEDED");
467+
assertThat(
468+
attributes.get(AttributeKey.stringKey(ObservabilityAttributes.ERROR_TYPE_ATTRIBUTE)))
469+
.isEqualTo("504");
470+
}
471+
}
472+
473+
@Test
474+
void testMetrics_retryAndSucceed_grpc() throws Exception {
475+
GoldenSignalsMetricsTracerFactory tracerFactory =
476+
new GoldenSignalsMetricsTracerFactory(openTelemetrySdk);
477+
478+
RetrySettings retrySettings =
479+
RetrySettings.newBuilder()
480+
.setInitialRpcTimeout(org.threeten.bp.Duration.ofMillis(5000L))
481+
.setMaxRpcTimeout(org.threeten.bp.Duration.ofMillis(5000L))
482+
.setTotalTimeout(org.threeten.bp.Duration.ofMillis(5000L))
483+
.setMaxAttempts(3)
484+
.build();
485+
486+
java.util.concurrent.atomic.AtomicInteger attemptCount = new java.util.concurrent.atomic.AtomicInteger(0);
487+
488+
ClientInterceptor interceptor =
489+
new ClientInterceptor() {
490+
@Override
491+
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
492+
MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
493+
int attempt = attemptCount.incrementAndGet();
494+
if (attempt <= 2) {
495+
return new ClientCall<ReqT, RespT>() {
496+
@Override
497+
public void start(Listener<RespT> responseListener, Metadata headers) {
498+
responseListener.onClose(io.grpc.Status.UNAVAILABLE, new Metadata());
499+
}
500+
501+
@Override
502+
public void request(int numMessages) {}
503+
504+
@Override
505+
public void cancel(String message, Throwable cause) {}
506+
507+
@Override
508+
public void halfClose() {}
509+
510+
@Override
511+
public void sendMessage(ReqT message) {}
512+
};
513+
} else {
514+
return next.interceptCall(method, callOptions);
515+
}
516+
}
517+
};
518+
519+
java.util.Set<StatusCode.Code> retryableCodes = java.util.Collections.singleton(StatusCode.Code.UNAVAILABLE);
520+
521+
try (EchoClient client =
522+
TestClientInitializer.createGrpcEchoClientOpentelemetry(
523+
tracerFactory, retrySettings, retryableCodes, ImmutableList.of(interceptor))) {
524+
525+
client.echo(EchoRequest.newBuilder().setContent("metrics-test").build());
526+
527+
assertThat(attemptCount.get()).isEqualTo(3);
528+
529+
Thread.sleep(100);
530+
Collection<MetricData> metrics = metricReader.collectAllMetrics();
531+
assertThat(metrics).hasSize(1);
532+
533+
MetricData durationMetric =
534+
metrics.stream()
535+
.filter(m -> m.getName().equals("gcp.client.request.duration"))
536+
.findFirst()
537+
.orElseThrow(() -> new AssertionError("Duration metric not found"));
538+
539+
assertThat(durationMetric.getHistogramData().getPoints()).hasSize(1);
540+
541+
io.opentelemetry.api.common.Attributes attributes =
542+
durationMetric.getHistogramData().getPoints().iterator().next().getAttributes();
543+
544+
assertThat(
545+
attributes.get(
546+
AttributeKey.stringKey(ObservabilityAttributes.RPC_RESPONSE_STATUS_ATTRIBUTE)))
547+
.isEqualTo("OK");
548+
}
549+
}
550+
551+
@Test
552+
void testMetrics_retryAndSucceed_httpjson() throws Exception {
553+
GoldenSignalsMetricsTracerFactory tracerFactory =
554+
new GoldenSignalsMetricsTracerFactory(openTelemetrySdk);
555+
556+
RetrySettings retrySettings =
557+
RetrySettings.newBuilder()
558+
.setInitialRpcTimeout(org.threeten.bp.Duration.ofMillis(5000L))
559+
.setMaxRpcTimeout(org.threeten.bp.Duration.ofMillis(5000L))
560+
.setTotalTimeout(org.threeten.bp.Duration.ofMillis(5000L))
561+
.setMaxAttempts(3)
562+
.build();
563+
564+
java.util.concurrent.atomic.AtomicInteger requestCount = new java.util.concurrent.atomic.AtomicInteger(0);
565+
566+
HttpTransport mockTransport =
567+
new HttpTransport() {
568+
@Override
569+
protected com.google.api.client.http.LowLevelHttpRequest buildRequest(
570+
String method, String url) {
571+
int currentCount = requestCount.incrementAndGet();
572+
return new com.google.api.client.http.LowLevelHttpRequest() {
573+
@Override
574+
public void addHeader(String name, String value) {}
575+
576+
@Override
577+
public com.google.api.client.http.LowLevelHttpResponse execute() {
578+
if (currentCount <= 2) {
579+
return new com.google.api.client.http.LowLevelHttpResponse() {
580+
@Override
581+
public InputStream getContent() {
582+
return new ByteArrayInputStream("{}".getBytes());
583+
}
584+
585+
@Override
586+
public String getContentEncoding() { return null; }
587+
588+
@Override
589+
public long getContentLength() { return 2; }
590+
591+
@Override
592+
public String getContentType() { return "application/json"; }
593+
594+
@Override
595+
public String getStatusLine() { return "HTTP/1.1 503 Service Unavailable"; }
596+
597+
@Override
598+
public int getStatusCode() { return 503; }
599+
600+
@Override
601+
public String getReasonPhrase() { return "Service Unavailable"; }
602+
603+
@Override
604+
public int getHeaderCount() { return 0; }
605+
606+
@Override
607+
public String getHeaderName(int index) { return null; }
608+
609+
@Override
610+
public String getHeaderValue(int index) { return null; }
611+
};
612+
} else {
613+
return new com.google.api.client.http.LowLevelHttpResponse() {
614+
@Override
615+
public InputStream getContent() {
616+
return new ByteArrayInputStream("{\"content\":\"metrics-test\"}".getBytes());
617+
}
618+
619+
@Override
620+
public String getContentEncoding() { return null; }
621+
622+
@Override
623+
public long getContentLength() { return 24; }
624+
625+
@Override
626+
public String getContentType() { return "application/json"; }
627+
628+
@Override
629+
public String getStatusLine() { return "HTTP/1.1 200 OK"; }
630+
631+
@Override
632+
public int getStatusCode() { return 200; }
633+
634+
@Override
635+
public String getReasonPhrase() { return "OK"; }
636+
637+
@Override
638+
public int getHeaderCount() { return 0; }
639+
640+
@Override
641+
public String getHeaderName(int index) { return null; }
642+
643+
@Override
644+
public String getHeaderValue(int index) { return null; }
645+
};
646+
}
647+
}
648+
};
649+
}
650+
};
651+
652+
java.util.Set<StatusCode.Code> retryableCodes = java.util.Collections.singleton(StatusCode.Code.UNAVAILABLE);
653+
654+
try (EchoClient client =
655+
TestClientInitializer.createHttpJsonEchoClientOpentelemetry(
656+
tracerFactory, retrySettings, retryableCodes, mockTransport)) {
657+
658+
client.echo(EchoRequest.newBuilder().setContent("metrics-test").build());
659+
660+
assertThat(requestCount.get()).isEqualTo(3);
661+
662+
Thread.sleep(100);
663+
Collection<MetricData> metrics = metricReader.collectAllMetrics();
664+
assertThat(metrics).hasSize(1);
665+
666+
MetricData durationMetric =
667+
metrics.stream()
668+
.filter(m -> m.getName().equals("gcp.client.request.duration"))
669+
.findFirst()
670+
.orElseThrow(() -> new AssertionError("Duration metric not found"));
671+
672+
assertThat(durationMetric.getHistogramData().getPoints()).hasSize(1);
673+
674+
io.opentelemetry.api.common.Attributes attributes =
675+
durationMetric.getHistogramData().getPoints().iterator().next().getAttributes();
676+
677+
assertThat(
678+
attributes.get(
679+
AttributeKey.stringKey(ObservabilityAttributes.RPC_RESPONSE_STATUS_ATTRIBUTE)))
680+
.isEqualTo("OK");
681+
}
682+
}
382683
}

sdk-platform-java/java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/util/TestClientInitializer.java

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,92 @@ public static EchoClient createHttpJsonEchoClientOpentelemetry(
329329
return EchoClient.create(createStubWithServiceName(httpJsonEchoSettings, metricsTracerFactory));
330330
}
331331

332+
public static EchoClient createGrpcEchoClientOpentelemetryWithRetrySettings(
333+
ApiTracerFactory metricsTracerFactory, RetrySettings retrySettings) throws Exception {
334+
EchoStubSettings.Builder grpcEchoSettingsBuilder = EchoStubSettings.newBuilder();
335+
grpcEchoSettingsBuilder.echoSettings().setRetrySettings(retrySettings);
336+
EchoSettings grpcEchoSettings = EchoSettings.create(grpcEchoSettingsBuilder.build());
337+
grpcEchoSettings =
338+
grpcEchoSettings.toBuilder()
339+
.setCredentialsProvider(NoCredentialsProvider.create())
340+
.setTransportChannelProvider(
341+
EchoSettings.defaultGrpcTransportProviderBuilder()
342+
.setChannelConfigurator(ManagedChannelBuilder::usePlaintext)
343+
.build())
344+
.setEndpoint(DEFAULT_GRPC_ENDPOINT)
345+
.build();
346+
347+
return EchoClient.create(createStubWithServiceName(grpcEchoSettings, metricsTracerFactory));
348+
}
349+
350+
public static EchoClient createHttpJsonEchoClientOpentelemetryWithRetrySettings(
351+
ApiTracerFactory metricsTracerFactory, RetrySettings retrySettings) throws Exception {
352+
EchoStubSettings.Builder httpJsonEchoSettingsBuilder = EchoStubSettings.newHttpJsonBuilder();
353+
httpJsonEchoSettingsBuilder.echoSettings().setRetrySettings(retrySettings);
354+
EchoSettings httpJsonEchoSettings = EchoSettings.create(httpJsonEchoSettingsBuilder.build());
355+
httpJsonEchoSettings =
356+
httpJsonEchoSettings.toBuilder()
357+
.setCredentialsProvider(NoCredentialsProvider.create())
358+
.setTransportChannelProvider(
359+
EchoSettings.defaultHttpJsonTransportProviderBuilder()
360+
.setHttpTransport(
361+
new NetHttpTransport.Builder().doNotValidateCertificate().build())
362+
.setEndpoint(DEFAULT_HTTPJSON_ENDPOINT)
363+
.build())
364+
.build();
365+
366+
return EchoClient.create(createStubWithServiceName(httpJsonEchoSettings, metricsTracerFactory));
367+
}
368+
369+
public static EchoClient createGrpcEchoClientOpentelemetry(
370+
ApiTracerFactory metricsTracerFactory,
371+
RetrySettings retrySettings,
372+
Set<StatusCode.Code> retryableCodes,
373+
List<ClientInterceptor> interceptorList) throws Exception {
374+
EchoStubSettings.Builder grpcEchoSettingsBuilder = EchoStubSettings.newBuilder();
375+
grpcEchoSettingsBuilder
376+
.echoSettings()
377+
.setRetrySettings(retrySettings)
378+
.setRetryableCodes(retryableCodes);
379+
EchoSettings grpcEchoSettings = EchoSettings.create(grpcEchoSettingsBuilder.build());
380+
grpcEchoSettings =
381+
grpcEchoSettings.toBuilder()
382+
.setCredentialsProvider(NoCredentialsProvider.create())
383+
.setTransportChannelProvider(
384+
EchoSettings.defaultGrpcTransportProviderBuilder()
385+
.setChannelConfigurator(ManagedChannelBuilder::usePlaintext)
386+
.setInterceptorProvider(() -> interceptorList)
387+
.build())
388+
.setEndpoint(DEFAULT_GRPC_ENDPOINT)
389+
.build();
390+
391+
return EchoClient.create(createStubWithServiceName(grpcEchoSettings, metricsTracerFactory));
392+
}
393+
394+
public static EchoClient createHttpJsonEchoClientOpentelemetry(
395+
ApiTracerFactory metricsTracerFactory,
396+
RetrySettings retrySettings,
397+
Set<StatusCode.Code> retryableCodes,
398+
com.google.api.client.http.HttpTransport transport) throws Exception {
399+
EchoStubSettings.Builder httpJsonEchoSettingsBuilder = EchoStubSettings.newHttpJsonBuilder();
400+
httpJsonEchoSettingsBuilder
401+
.echoSettings()
402+
.setRetrySettings(retrySettings)
403+
.setRetryableCodes(retryableCodes);
404+
EchoSettings httpJsonEchoSettings = EchoSettings.create(httpJsonEchoSettingsBuilder.build());
405+
httpJsonEchoSettings =
406+
httpJsonEchoSettings.toBuilder()
407+
.setCredentialsProvider(NoCredentialsProvider.create())
408+
.setTransportChannelProvider(
409+
EchoSettings.defaultHttpJsonTransportProviderBuilder()
410+
.setHttpTransport(transport)
411+
.setEndpoint(DEFAULT_HTTPJSON_ENDPOINT)
412+
.build())
413+
.build();
414+
415+
return EchoClient.create(createStubWithServiceName(httpJsonEchoSettings, metricsTracerFactory));
416+
}
417+
332418
public static IdentityClient createGrpcIdentityClientOpentelemetry(ApiTracerFactory tracerFactory)
333419
throws Exception {
334420
IdentitySettings grpcIdentitySettings =

0 commit comments

Comments
 (0)