diff --git a/src/main/java/com/google/firebase/FirebaseOptions.java b/src/main/java/com/google/firebase/FirebaseOptions.java index 03f1b34a..5ea071b6 100644 --- a/src/main/java/com/google/firebase/FirebaseOptions.java +++ b/src/main/java/com/google/firebase/FirebaseOptions.java @@ -86,6 +86,7 @@ public GoogleCredentials get() { private final JsonFactory jsonFactory; private final ThreadManager threadManager; private final FirestoreOptions firestoreOptions; + private final boolean retryEnabled; private FirebaseOptions(@NonNull final FirebaseOptions.Builder builder) { this.databaseUrl = builder.databaseUrl; @@ -116,6 +117,7 @@ private FirebaseOptions(@NonNull final FirebaseOptions.Builder builder) { checkArgument(builder.writeTimeout >= 0); this.writeTimeout = builder.writeTimeout; this.firestoreOptions = builder.firestoreOptions; + this.retryEnabled = builder.retryEnabled; } /** @@ -227,6 +229,15 @@ FirestoreOptions getFirestoreOptions() { return firestoreOptions; } + /** + * Returns whether automatic retries are enabled for HTTP requests. + * + * @return true if retries are enabled, and false otherwise. + */ + public boolean isRetryEnabled() { + return retryEnabled; + } + /** * Creates an empty builder. * @@ -272,6 +283,7 @@ public static final class Builder { private int connectTimeout; private int readTimeout; private int writeTimeout; + private boolean retryEnabled = true; /** * Constructs an empty builder. @@ -521,6 +533,17 @@ public Builder setWriteTimeout(int writeTimeout) { return this; } + /** + * Enables or disables automatic retries for HTTP requests. By default, retries are enabled. + * + * @param retryEnabled Whether to enable automatic retries (default: true). + * @return This {@code Builder} instance is returned so subsequent calls can be chained. + */ + public Builder setRetryEnabled(boolean retryEnabled) { + this.retryEnabled = retryEnabled; + return this; + } + /** * Builds the {@link FirebaseOptions} instance from the previously set options. * diff --git a/src/main/java/com/google/firebase/internal/ApiClientUtils.java b/src/main/java/com/google/firebase/internal/ApiClientUtils.java index 9d501fae..144afee8 100644 --- a/src/main/java/com/google/firebase/internal/ApiClientUtils.java +++ b/src/main/java/com/google/firebase/internal/ApiClientUtils.java @@ -41,14 +41,17 @@ public class ApiClientUtils { private ApiClientUtils() { } /** - * Creates a new {@code HttpRequestFactory} which provides authorization (OAuth2), timeouts and - * automatic retries. + * Creates a new {@code HttpRequestFactory} which provides authorization (OAuth2) and timeouts. + * Automatic retries are enabled or disabled based on the application's configuration. * * @param app {@link FirebaseApp} from which to obtain authorization credentials. * @return A new {@code HttpRequestFactory} instance. */ public static HttpRequestFactory newAuthorizedRequestFactory(FirebaseApp app) { - return newAuthorizedRequestFactory(app, DEFAULT_RETRY_CONFIG); + if (app.getOptions().isRetryEnabled()) { + return newAuthorizedRequestFactory(app, DEFAULT_RETRY_CONFIG); + } + return newAuthorizedRequestFactory(app, /*retryConfig*/ null); } /** diff --git a/src/test/java/com/google/firebase/FirebaseOptionsTest.java b/src/test/java/com/google/firebase/FirebaseOptionsTest.java index 05613e98..731a9d1d 100644 --- a/src/test/java/com/google/firebase/FirebaseOptionsTest.java +++ b/src/test/java/com/google/firebase/FirebaseOptionsTest.java @@ -23,6 +23,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; import com.google.api.client.json.gson.GsonFactory; import com.google.auth.oauth2.AccessToken; @@ -38,6 +39,7 @@ import org.junit.Test; + /** * Tests for {@link FirebaseOptions}. */ @@ -89,6 +91,7 @@ public void createOptionsWithAllValuesSet() throws IOException { .setReadTimeout(60000) .setWriteTimeout(90000) .setFirestoreOptions(firestoreOptions) + .setRetryEnabled(false) .build(); assertEquals(FIREBASE_DB_URL, firebaseOptions.getDatabaseUrl()); assertEquals(FIREBASE_STORAGE_BUCKET, firebaseOptions.getStorageBucket()); @@ -100,6 +103,7 @@ public void createOptionsWithAllValuesSet() throws IOException { assertEquals(60000, firebaseOptions.getReadTimeout()); assertEquals(90000, firebaseOptions.getWriteTimeout()); assertSame(firestoreOptions, firebaseOptions.getFirestoreOptions()); + assertFalse(firebaseOptions.isRetryEnabled()); GoogleCredentials credentials = firebaseOptions.getCredentials(); assertNotNull(credentials); @@ -193,6 +197,7 @@ public void checkToBuilderCreatesNewEquivalentInstance() { assertEquals(ALL_VALUES_OPTIONS.getReadTimeout(), allValuesOptionsCopy.getReadTimeout()); assertSame(ALL_VALUES_OPTIONS.getFirestoreOptions(), allValuesOptionsCopy.getFirestoreOptions()); + assertEquals(ALL_VALUES_OPTIONS.isRetryEnabled(), allValuesOptionsCopy.isRetryEnabled()); } @Test(expected = IllegalArgumentException.class) diff --git a/src/test/java/com/google/firebase/internal/ApiClientUtilsTest.java b/src/test/java/com/google/firebase/internal/ApiClientUtilsTest.java index e0e619f3..c63957f7 100644 --- a/src/test/java/com/google/firebase/internal/ApiClientUtilsTest.java +++ b/src/test/java/com/google/firebase/internal/ApiClientUtilsTest.java @@ -71,7 +71,7 @@ public void testAuthorizedHttpClient() throws IOException { } @Test - public void testAuthorizedHttpClientWithoutRetry() throws IOException { + public void testAuthorizedHttpClientNoRetryConfigured() throws IOException { FirebaseApp app = FirebaseApp.initializeApp(TEST_OPTIONS); HttpRequestFactory requestFactory = ApiClientUtils.newAuthorizedRequestFactory(app, null); @@ -83,6 +83,24 @@ public void testAuthorizedHttpClientWithoutRetry() throws IOException { assertFalse(retryHandler instanceof RetryHandlerDecorator); } + @Test + public void testAuthorizedHttpClientWithRetryDisabled() throws IOException { + FirebaseOptions options = FirebaseOptions.builder() + .setCredentials(new MockGoogleCredentials("test-token")) + .setRetryEnabled(false) + .build(); + + FirebaseApp app = FirebaseApp.initializeApp(options); + + HttpRequestFactory requestFactory = ApiClientUtils.newAuthorizedRequestFactory(app); + + assertTrue(requestFactory.getInitializer() instanceof FirebaseRequestInitializer); + HttpRequest request = requestFactory.buildGetRequest(TEST_URL); + assertEquals("Bearer test-token", request.getHeaders().getAuthorization()); + HttpUnsuccessfulResponseHandler retryHandler = request.getUnsuccessfulResponseHandler(); + assertFalse(retryHandler instanceof RetryHandlerDecorator); + } + @Test public void testUnauthorizedHttpClient() throws IOException { FirebaseApp app = FirebaseApp.initializeApp(TEST_OPTIONS);