From ea0f6c0f58e8abffae1362feb344a9309d6d814e Mon Sep 17 00:00:00 2001 From: Timur Sadykov Date: Mon, 22 Nov 2021 16:25:57 -0800 Subject: [PATCH] feat: add AttemptCount to HttpResponseException (#1505) * feat: add tests for attemptCount * fix: more renaming * fix: linter fixes --- .../google/api/client/http/HttpRequest.java | 4 +- .../client/http/HttpResponseException.java | 28 +++++++++++ .../http/HttpResponseExceptionTest.java | 48 +++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) diff --git a/google-http-client/src/main/java/com/google/api/client/http/HttpRequest.java b/google-http-client/src/main/java/com/google/api/client/http/HttpRequest.java index 312702b9a..78f15d868 100644 --- a/google-http-client/src/main/java/com/google/api/client/http/HttpRequest.java +++ b/google-http-client/src/main/java/com/google/api/client/http/HttpRequest.java @@ -1113,7 +1113,9 @@ public HttpResponse execute() throws IOException { // throw an exception if unsuccessful response if (throwExceptionOnExecuteError && !response.isSuccessStatusCode()) { try { - throw new HttpResponseException(response); + throw new HttpResponseException.Builder(response) + .setAttemptCount(numRetries - retriesRemaining) + .build(); } finally { response.disconnect(); } diff --git a/google-http-client/src/main/java/com/google/api/client/http/HttpResponseException.java b/google-http-client/src/main/java/com/google/api/client/http/HttpResponseException.java index a9d80a4f5..63bf6fe4c 100644 --- a/google-http-client/src/main/java/com/google/api/client/http/HttpResponseException.java +++ b/google-http-client/src/main/java/com/google/api/client/http/HttpResponseException.java @@ -42,6 +42,9 @@ public class HttpResponseException extends IOException { /** HTTP response content or {@code null} for none. */ private final String content; + /** Number of attempts performed */ + private final int attemptCount; + /** * Constructor that constructs a detail message from the given HTTP response that includes the * status code, status message and HTTP response content. @@ -73,6 +76,7 @@ protected HttpResponseException(Builder builder) { statusMessage = builder.statusMessage; headers = builder.headers; content = builder.content; + attemptCount = builder.attemptCount; } /** @@ -121,6 +125,15 @@ public final String getContent() { return content; } + /** + * Returns the attempt count + * + * @since 1.41 + */ + public final int getAttemptCount() { + return attemptCount; + } + /** * Builder. * @@ -145,6 +158,9 @@ public static class Builder { /** Detail message to use or {@code null} for none. */ String message; + /** Number of attempts performed */ + int attemptCount; + /** * @param statusCode HTTP status code * @param statusMessage status message or {@code null} @@ -260,6 +276,18 @@ public Builder setContent(String content) { return this; } + /** Returns the request attempt count */ + public final int getAttemptCount() { + return attemptCount; + } + + /** Sets the attempt count for the related HTTP request execution. */ + public Builder setAttemptCount(int attemptCount) { + Preconditions.checkArgument(attemptCount >= 0); + this.attemptCount = attemptCount; + return this; + } + /** Returns a new instance of {@link HttpResponseException} based on this builder. */ public HttpResponseException build() { return new HttpResponseException(this); diff --git a/google-http-client/src/test/java/com/google/api/client/http/HttpResponseExceptionTest.java b/google-http-client/src/test/java/com/google/api/client/http/HttpResponseExceptionTest.java index 9066e9d70..cbe6e6a0d 100644 --- a/google-http-client/src/test/java/com/google/api/client/http/HttpResponseExceptionTest.java +++ b/google-http-client/src/test/java/com/google/api/client/http/HttpResponseExceptionTest.java @@ -23,6 +23,7 @@ import com.google.api.client.testing.http.MockHttpTransport; import com.google.api.client.testing.http.MockLowLevelHttpRequest; import com.google.api.client.testing.http.MockLowLevelHttpResponse; +import com.google.api.client.util.ExponentialBackOff; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -30,6 +31,7 @@ import java.io.ObjectOutput; import java.io.ObjectOutputStream; import junit.framework.TestCase; +import org.junit.Assert; import org.junit.function.ThrowingRunnable; /** @@ -208,6 +210,8 @@ public void run() throws Throwable { + SIMPLE_GENERIC_URL + LINE_SEPARATOR + "Unable to find resource"); + // no retries expected + assertEquals(1, responseException.getAttemptCount()); } public void testInvalidCharset() throws Exception { @@ -245,6 +249,50 @@ public void run() throws Throwable { .isEqualTo("404 Not Found\nGET " + SIMPLE_GENERIC_URL); } + public void testAttemptCountWithBackOff() throws Exception { + HttpTransport fakeTransport = + new MockHttpTransport() { + @Override + public LowLevelHttpRequest buildRequest(String method, String url) throws IOException { + return new MockLowLevelHttpRequest() { + @Override + public LowLevelHttpResponse execute() throws IOException { + MockLowLevelHttpResponse result = new MockLowLevelHttpResponse(); + result.setStatusCode(HttpStatusCodes.STATUS_CODE_SERVER_ERROR); + result.setReasonPhrase("Error"); + result.setContent("Unknown Error"); + return result; + } + }; + } + }; + ExponentialBackOff backoff = new ExponentialBackOff.Builder().build(); + final HttpRequest request = + fakeTransport.createRequestFactory().buildGetRequest(new GenericUrl("http://not/used")); + request.setUnsuccessfulResponseHandler( + new HttpBackOffUnsuccessfulResponseHandler(backoff) + .setBackOffRequired( + new HttpBackOffUnsuccessfulResponseHandler.BackOffRequired() { + public boolean isRequired(HttpResponse response) { + return true; + } + })); + request.setNumberOfRetries(1); + HttpResponseException responseException = + assertThrows( + HttpResponseException.class, + new ThrowingRunnable() { + @Override + public void run() throws Throwable { + request.execute(); + } + }); + + Assert.assertEquals(500, responseException.getStatusCode()); + // original request and 1 retry - total 2 + assertEquals(2, responseException.getAttemptCount()); + } + public void testUnsupportedCharset() throws Exception { HttpTransport transport = new MockHttpTransport() {