Skip to content

Commit

Permalink
feat: add AttemptCount to HttpResponseException (#1505)
Browse files Browse the repository at this point in the history
* feat: add tests for attemptCount

* fix: more renaming

* fix: linter fixes
  • Loading branch information
TimurSadykov committed Nov 23, 2021
1 parent 8b1b8f2 commit ea0f6c0
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 1 deletion.
Expand Up @@ -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();
}
Expand Down
Expand Up @@ -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.
Expand Down Expand Up @@ -73,6 +76,7 @@ protected HttpResponseException(Builder builder) {
statusMessage = builder.statusMessage;
headers = builder.headers;
content = builder.content;
attemptCount = builder.attemptCount;
}

/**
Expand Down Expand Up @@ -121,6 +125,15 @@ public final String getContent() {
return content;
}

/**
* Returns the attempt count
*
* @since 1.41
*/
public final int getAttemptCount() {
return attemptCount;
}

/**
* Builder.
*
Expand All @@ -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}
Expand Down Expand Up @@ -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);
Expand Down
Expand Up @@ -23,13 +23,15 @@
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;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import junit.framework.TestCase;
import org.junit.Assert;
import org.junit.function.ThrowingRunnable;

/**
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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() {
Expand Down

0 comments on commit ea0f6c0

Please sign in to comment.