Repository: firebase/firebase-admin-java
Pull request #900 (2024-01-10 12:51:24)

fix: Make writeTimeout configurable (similar to readTimeout)
Solves #850 

google-cla[bot]: Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this [failed invocation](https://github.com/firebase/firebase-admin-java/pull/900/checks?check_run_id=20342794657) of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

Patch:
diff --git a/src/main/java/com/google/firebase/FirebaseOptions.java b/src/main/java/com/google/firebase/FirebaseOptions.java
index 8e7a29c..849b38b 100644
--- a/src/main/java/com/google/firebase/FirebaseOptions.java
+++ b/src/main/java/com/google/firebase/FirebaseOptions.java
@@ -82,6 +82,7 @@ public final class FirebaseOptions {
   private final HttpTransport httpTransport;
   private final int connectTimeout;
   private final int readTimeout;
+  private final int writeTimeout;
   private final JsonFactory jsonFactory;
   private final ThreadManager threadManager;
   private final FirestoreOptions firestoreOptions;
@@ -112,6 +113,8 @@ public final class FirebaseOptions {
     this.connectTimeout = builder.connectTimeout;
     checkArgument(builder.readTimeout >= 0);
     this.readTimeout = builder.readTimeout;
+    checkArgument(builder.writeTimeout >= 0);
+    this.writeTimeout = builder.writeTimeout;
     this.firestoreOptions = builder.firestoreOptions;
   }
 
@@ -207,6 +210,16 @@ public final class FirebaseOptions {
     return readTimeout;
   }
 
+  /**
+   * Returns the write timeout in milliseconds, which is applied to outgoing REST calls
+   * made by the SDK.
+   *
+   * @return Write timeout in milliseconds. 0 indicates an infinite timeout.
+   */
+  public int getWriteTimeout() {
+    return writeTimeout;
+  }
+
   @NonNull
   ThreadManager getThreadManager() {
     return threadManager;
@@ -260,6 +273,7 @@ public final class FirebaseOptions {
     private ThreadManager threadManager;
     private int connectTimeout;
     private int readTimeout;
+    private int writeTimeout;
 
     /**
      * Constructs an empty builder.
@@ -289,6 +303,7 @@ public final class FirebaseOptions {
       threadManager = options.threadManager;
       connectTimeout = options.connectTimeout;
       readTimeout = options.readTimeout;
+      writeTimeout = options.writeTimeout;
       firestoreOptions = options.firestoreOptions;
     }
 
@@ -495,6 +510,19 @@ public final class FirebaseOptions {
       return this;
     }
 
+    /**
+     * Sets the write timeout for outgoing HTTP (REST) calls made by the SDK. This does not affect
+     * the {@link com.google.firebase.database.FirebaseDatabase} and
+     * {@link com.google.firebase.cloud.FirestoreClient} APIs.
+     *
+     * @param writeTimeout Write timeout in milliseconds. Must not be negative.
+     * @return This <code>Builder</code> instance is returned so subsequent calls can be chained.
+     */
+    public Builder setWriteTimeout(int writeTimeout) {
+      this.writeTimeout = writeTimeout;
+      return this;
+    }
+
     /**
      * Builds the {@link FirebaseOptions} instance from the previously set options.
      *
diff --git a/src/main/java/com/google/firebase/internal/FirebaseRequestInitializer.java b/src/main/java/com/google/firebase/internal/FirebaseRequestInitializer.java
index e73f939..e126906 100644
--- a/src/main/java/com/google/firebase/internal/FirebaseRequestInitializer.java
+++ b/src/main/java/com/google/firebase/internal/FirebaseRequestInitializer.java
@@ -60,16 +60,19 @@ public final class FirebaseRequestInitializer implements HttpRequestInitializer
 
     private final int connectTimeoutMillis;
     private final int readTimeoutMillis;
+    private final int writeTimeoutMillis;
 
     TimeoutInitializer(FirebaseOptions options) {
       this.connectTimeoutMillis = options.getConnectTimeout();
       this.readTimeoutMillis = options.getReadTimeout();
+      this.writeTimeoutMillis = options.getWriteTimeout();
     }
 
     @Override
     public void initialize(HttpRequest request) {
       request.setConnectTimeout(connectTimeoutMillis);
       request.setReadTimeout(readTimeoutMillis);
+      request.setWriteTimeout(writeTimeoutMillis);
     }
   }
 }


Test patch:
diff --git a/src/test/java/com/google/firebase/FirebaseOptionsTest.java b/src/test/java/com/google/firebase/FirebaseOptionsTest.java
index c74215b..0a4e9e8 100644
--- a/src/test/java/com/google/firebase/FirebaseOptionsTest.java
+++ b/src/test/java/com/google/firebase/FirebaseOptionsTest.java
@@ -38,7 +38,7 @@ import java.util.concurrent.ThreadFactory;
 
 import org.junit.Test;
 
-/** 
+/**
  * Tests for {@link FirebaseOptions}.
  */
 public class FirebaseOptionsTest {
@@ -87,6 +87,7 @@ public class FirebaseOptionsTest {
             .setThreadManager(MOCK_THREAD_MANAGER)
             .setConnectTimeout(30000)
             .setReadTimeout(60000)
+            .setWriteTimeout(90000)
             .setFirestoreOptions(firestoreOptions)
             .build();
     assertEquals(FIREBASE_DB_URL, firebaseOptions.getDatabaseUrl());
@@ -97,6 +98,7 @@ public class FirebaseOptionsTest {
     assertSame(MOCK_THREAD_MANAGER, firebaseOptions.getThreadManager());
     assertEquals(30000, firebaseOptions.getConnectTimeout());
     assertEquals(60000, firebaseOptions.getReadTimeout());
+    assertEquals(90000, firebaseOptions.getWriteTimeout());
     assertSame(firestoreOptions, firebaseOptions.getFirestoreOptions());
 
     GoogleCredentials credentials = firebaseOptions.getCredentials();
@@ -209,6 +211,14 @@ public class FirebaseOptionsTest {
         .build();
   }
 
+  @Test(expected = IllegalArgumentException.class)
+  public void createOptionsWithInvalidWriteTimeout() {
+    FirebaseOptions.builder()
+            .setCredentials(TestUtils.getCertCredential(ServiceAccount.EDITOR.asStream()))
+            .setWriteTimeout(-1)
+            .build();
+  }
+
   @Test
   public void testNotEquals() throws IOException {
     GoogleCredentials credentials = GoogleCredentials.fromStream(ServiceAccount.EDITOR.asStream());
diff --git a/src/test/java/com/google/firebase/auth/FirebaseUserManagerTest.java b/src/test/java/com/google/firebase/auth/FirebaseUserManagerTest.java
index f83c5f5..41085d1 100644
--- a/src/test/java/com/google/firebase/auth/FirebaseUserManagerTest.java
+++ b/src/test/java/com/google/firebase/auth/FirebaseUserManagerTest.java
@@ -979,6 +979,7 @@ public class FirebaseUserManagerTest {
         .setHttpTransport(transport)
         .setConnectTimeout(30000)
         .setReadTimeout(60000)
+        .setWriteTimeout(90000)
         .build());
     FirebaseAuth auth = FirebaseAuth.getInstance();
     FirebaseUserManager userManager = auth.getUserManager();
@@ -989,6 +990,7 @@ public class FirebaseUserManagerTest {
     HttpRequest request = interceptor.getResponse().getRequest();
     assertEquals(30000, request.getConnectTimeout());
     assertEquals(60000, request.getReadTimeout());
+    assertEquals(90000, request.getWriteTimeout());
   }
 
   @Test
diff --git a/src/test/java/com/google/firebase/internal/FirebaseRequestInitializerTest.java b/src/test/java/com/google/firebase/internal/FirebaseRequestInitializerTest.java
index fde2f91..49805d3 100644
--- a/src/test/java/com/google/firebase/internal/FirebaseRequestInitializerTest.java
+++ b/src/test/java/com/google/firebase/internal/FirebaseRequestInitializerTest.java
@@ -38,6 +38,7 @@ public class FirebaseRequestInitializerTest {
   private static final int MAX_RETRIES = 5;
   private static final int CONNECT_TIMEOUT_MILLIS = 30000;
   private static final int READ_TIMEOUT_MILLIS = 60000;
+  private static final int WRITE_TIMEOUT_MILLIS = 90000;
 
   @After
   public void tearDown() {
@@ -69,6 +70,7 @@ public class FirebaseRequestInitializerTest {
         .setCredentials(new MockGoogleCredentials("token"))
         .setConnectTimeout(CONNECT_TIMEOUT_MILLIS)
         .setReadTimeout(READ_TIMEOUT_MILLIS)
+        .setWriteTimeout(WRITE_TIMEOUT_MILLIS)
         .build());
     HttpRequest request = TestUtils.createRequest();
 
@@ -77,6 +79,7 @@ public class FirebaseRequestInitializerTest {
 
     assertEquals(CONNECT_TIMEOUT_MILLIS, request.getConnectTimeout());
     assertEquals(READ_TIMEOUT_MILLIS, request.getReadTimeout());
+    assertEquals(WRITE_TIMEOUT_MILLIS, request.getWriteTimeout());
     assertEquals("Bearer token", request.getHeaders().getAuthorization());
     assertEquals(HttpRequest.DEFAULT_NUMBER_OF_RETRIES, request.getNumberOfRetries());
     assertNull(request.getIOExceptionHandler());