Repository: firebase/firebase-admin-java
Pull request #1039 (2024-11-19 18:12:41)

chore: Add `X-Goog-Api-Client` metric header to outgoing requests
Includes:
- Auth
- Installations / Instance ID
- Messaging
- Topic Management
- Project Management
- Remote Config

This does not include:
- Firestore
- RTDB
- Storage


Patch:
diff --git a/src/main/java/com/google/firebase/internal/ErrorHandlingHttpClient.java b/src/main/java/com/google/firebase/internal/ErrorHandlingHttpClient.java
index 5efdd0e..cccd0ce 100644
--- a/src/main/java/com/google/firebase/internal/ErrorHandlingHttpClient.java
+++ b/src/main/java/com/google/firebase/internal/ErrorHandlingHttpClient.java
@@ -89,6 +89,7 @@ public final class ErrorHandlingHttpClient<T extends FirebaseException> {
   }
 
   public IncomingHttpResponse send(HttpRequestInfo requestInfo) throws T {
+    requestInfo.addHeader("X-Goog-Api-Client", SdkUtils.getMetricsHeader());
     HttpRequest request = createHttpRequest(requestInfo);
 
     HttpResponse response = null;
diff --git a/src/main/java/com/google/firebase/internal/SdkUtils.java b/src/main/java/com/google/firebase/internal/SdkUtils.java
index 2fa5e57..cd96190 100644
--- a/src/main/java/com/google/firebase/internal/SdkUtils.java
+++ b/src/main/java/com/google/firebase/internal/SdkUtils.java
@@ -39,6 +39,14 @@ public class SdkUtils {
     return SDK_VERSION;
   }
 
+  public static String getJavaVersion() {
+    return System.getProperty("java.version");
+  }
+
+  public static String getMetricsHeader() {
+    return String.format("gl-java/%s fire-admin/%s", getJavaVersion(), getVersion());
+  }
+
   private static String loadSdkVersion() {
     try (InputStream in = SdkUtils.class.getClassLoader()
         .getResourceAsStream(ADMIN_SDK_PROPERTIES)) {


Test patch:
diff --git a/src/test/java/com/google/firebase/auth/FirebaseUserManagerTest.java b/src/test/java/com/google/firebase/auth/FirebaseUserManagerTest.java
index 41085d1..c8c733c 100644
--- a/src/test/java/com/google/firebase/auth/FirebaseUserManagerTest.java
+++ b/src/test/java/com/google/firebase/auth/FirebaseUserManagerTest.java
@@ -3026,6 +3026,8 @@ public class FirebaseUserManagerTest {
 
     String clientVersion = "Java/Admin/" + SdkUtils.getVersion();
     assertEquals(clientVersion, headers.getFirstHeaderStringValue("X-Client-Version"));
+    assertEquals(SdkUtils.getMetricsHeader(), headers.get("X-Goog-Api-Client"));
+
   }
 
   private static void checkUrl(TestResponseInterceptor interceptor, String method, String url) {
diff --git a/src/test/java/com/google/firebase/auth/internal/CryptoSignersTest.java b/src/test/java/com/google/firebase/auth/internal/CryptoSignersTest.java
index 679fe5a..17af1eb 100644
--- a/src/test/java/com/google/firebase/auth/internal/CryptoSignersTest.java
+++ b/src/test/java/com/google/firebase/auth/internal/CryptoSignersTest.java
@@ -39,6 +39,7 @@ import com.google.firebase.TestOnlyImplFirebaseTrampolines;
 import com.google.firebase.auth.FirebaseAuthException;
 import com.google.firebase.auth.MockGoogleCredentials;
 import com.google.firebase.internal.ApiClientUtils;
+import com.google.firebase.internal.SdkUtils;
 import com.google.firebase.testing.MultiRequestMockHttpTransport;
 import com.google.firebase.testing.ServiceAccount;
 import com.google.firebase.testing.TestResponseInterceptor;
@@ -87,6 +88,8 @@ public class CryptoSignersTest {
     final String url = "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/"
         + "test-service-account@iam.gserviceaccount.com:signBlob";
     assertEquals(url, interceptor.getResponse().getRequest().getUrl().toString());
+    HttpRequest request = interceptor.getResponse().getRequest();
+    assertEquals(SdkUtils.getMetricsHeader(), request.getHeaders().get("X-Goog-Api-Client"));
   }
 
   @Test
@@ -173,6 +176,7 @@ public class CryptoSignersTest {
     HttpRequest request = interceptor.getResponse().getRequest();
     assertEquals(url, request.getUrl().toString());
     assertEquals("Bearer test-token", request.getHeaders().getAuthorization());
+    assertEquals(SdkUtils.getMetricsHeader(), request.getHeaders().get("X-Goog-Api-Client"));
   }
 
   @Test
@@ -203,6 +207,7 @@ public class CryptoSignersTest {
     HttpRequest request = interceptor.getResponse().getRequest();
     assertEquals(url, request.getUrl().toString());
     assertEquals("Bearer test-token", request.getHeaders().getAuthorization());
+    assertEquals(SdkUtils.getMetricsHeader(), request.getHeaders().get("X-Goog-Api-Client"));
   }
 
   @Test
diff --git a/src/test/java/com/google/firebase/auth/multitenancy/FirebaseTenantClientTest.java b/src/test/java/com/google/firebase/auth/multitenancy/FirebaseTenantClientTest.java
index eca55ee..cdb5852 100644
--- a/src/test/java/com/google/firebase/auth/multitenancy/FirebaseTenantClientTest.java
+++ b/src/test/java/com/google/firebase/auth/multitenancy/FirebaseTenantClientTest.java
@@ -353,6 +353,7 @@ public class FirebaseTenantClientTest {
 
     String clientVersion = "Java/Admin/" + SdkUtils.getVersion();
     assertEquals(clientVersion, headers.getFirstHeaderStringValue("X-Client-Version"));
+    assertEquals(SdkUtils.getMetricsHeader(), headers.get("X-Goog-Api-Client"));
   }
 
   private static void checkUrl(TestResponseInterceptor interceptor, String method, String url) {
diff --git a/src/test/java/com/google/firebase/auth/multitenancy/TenantAwareFirebaseAuthTest.java b/src/test/java/com/google/firebase/auth/multitenancy/TenantAwareFirebaseAuthTest.java
index 68e3549..4cf36a3 100644
--- a/src/test/java/com/google/firebase/auth/multitenancy/TenantAwareFirebaseAuthTest.java
+++ b/src/test/java/com/google/firebase/auth/multitenancy/TenantAwareFirebaseAuthTest.java
@@ -38,6 +38,7 @@ import com.google.firebase.auth.MockGoogleCredentials;
 import com.google.firebase.auth.MockTokenVerifier;
 import com.google.firebase.auth.SessionCookieOptions;
 import com.google.firebase.internal.ApiClientUtils;
+import com.google.firebase.internal.SdkUtils;
 import com.google.firebase.testing.TestResponseInterceptor;
 import com.google.firebase.testing.TestUtils;
 import java.io.ByteArrayOutputStream;
@@ -85,6 +86,7 @@ public class TenantAwareFirebaseAuthTest {
     assertEquals("testToken", parsed.get("idToken"));
     assertEquals(new BigDecimal(3600), parsed.get("validDuration"));
     checkUrl(interceptor, AUTH_BASE_URL + ":createSessionCookie");
+    checkHeaders(interceptor);
   }
 
   @Test
@@ -121,6 +123,7 @@ public class TenantAwareFirebaseAuthTest {
     assertEquals("testToken", parsed.get("idToken"));
     assertEquals(new BigDecimal(3600), parsed.get("validDuration"));
     checkUrl(interceptor, AUTH_BASE_URL + ":createSessionCookie");
+    checkHeaders(interceptor);
   }
 
   @Test
@@ -212,6 +215,7 @@ public class TenantAwareFirebaseAuthTest {
     assertEquals("uid", token.getUid());
     assertEquals("cookie", tokenVerifier.getLastTokenString());
     checkUrl(interceptor, AUTH_BASE_URL + "/accounts:lookup");
+    checkHeaders(interceptor);
   }
 
   @Test
@@ -290,4 +294,9 @@ public class TenantAwareFirebaseAuthTest {
     assertEquals(HttpMethods.POST, request.getRequestMethod());
     assertEquals(url, request.getUrl().getRawPath());
   }
+
+  private static void checkHeaders(TestResponseInterceptor interceptor) {
+    HttpRequest request = interceptor.getResponse().getRequest();
+    assertEquals(SdkUtils.getMetricsHeader(), request.getHeaders().get("X-Goog-Api-Client"));
+  }
 }
diff --git a/src/test/java/com/google/firebase/iid/FirebaseInstanceIdTest.java b/src/test/java/com/google/firebase/iid/FirebaseInstanceIdTest.java
index 27864d9..f563d87 100644
--- a/src/test/java/com/google/firebase/iid/FirebaseInstanceIdTest.java
+++ b/src/test/java/com/google/firebase/iid/FirebaseInstanceIdTest.java
@@ -38,6 +38,7 @@ import com.google.firebase.IncomingHttpResponse;
 import com.google.firebase.OutgoingHttpRequest;
 import com.google.firebase.TestOnlyImplFirebaseTrampolines;
 import com.google.firebase.auth.MockGoogleCredentials;
+import com.google.firebase.internal.SdkUtils;
 import com.google.firebase.testing.GenericFunction;
 import com.google.firebase.testing.TestResponseInterceptor;
 import com.google.firebase.testing.TestUtils;
@@ -174,6 +175,7 @@ public class FirebaseInstanceIdTest {
       assertEquals(HttpMethods.DELETE, request.getRequestMethod());
       assertEquals(TEST_URL, request.getUrl().toString());
       assertEquals("Bearer test-token", request.getHeaders().getAuthorization());
+      assertEquals(SdkUtils.getMetricsHeader(), request.getHeaders().get("X-Goog-Api-Client"));
     }
   }
 
diff --git a/src/test/java/com/google/firebase/internal/ErrorHandlingHttpClientTest.java b/src/test/java/com/google/firebase/internal/ErrorHandlingHttpClientTest.java
index 8b3e75e..6d7fb2a 100644
--- a/src/test/java/com/google/firebase/internal/ErrorHandlingHttpClientTest.java
+++ b/src/test/java/com/google/firebase/internal/ErrorHandlingHttpClientTest.java
@@ -127,6 +127,7 @@ public class ErrorHandlingHttpClientTest {
     assertEquals("v1", last.getHeaders().get("h1"));
     assertEquals("v2", last.getHeaders().get("h2"));
     assertEquals("v3", last.getHeaders().get("h3"));
+    assertEquals(SdkUtils.getMetricsHeader(), last.getHeaders().get("x-goog-api-client"));
 
     ByteArrayOutputStream out = new ByteArrayOutputStream();
     last.getContent().writeTo(out);
diff --git a/src/test/java/com/google/firebase/messaging/FirebaseMessagingClientImplTest.java b/src/test/java/com/google/firebase/messaging/FirebaseMessagingClientImplTest.java
index b75d9a3..805d409 100644
--- a/src/test/java/com/google/firebase/messaging/FirebaseMessagingClientImplTest.java
+++ b/src/test/java/com/google/firebase/messaging/FirebaseMessagingClientImplTest.java
@@ -389,6 +389,7 @@ public class FirebaseMessagingClientImplTest {
     HttpHeaders headers = request.getHeaders();
     assertEquals("2", headers.get("X-GOOG-API-FORMAT-VERSION"));
     assertEquals("fire-admin-java/" + SdkUtils.getVersion(), headers.get("X-Firebase-Client"));
+    assertEquals(SdkUtils.getMetricsHeader(), headers.get("X-Goog-Api-Client"));
   }
 
   private void checkRequest(
diff --git a/src/test/java/com/google/firebase/messaging/InstanceIdClientImplTest.java b/src/test/java/com/google/firebase/messaging/InstanceIdClientImplTest.java
index 1a14068..d0151bb 100644
--- a/src/test/java/com/google/firebase/messaging/InstanceIdClientImplTest.java
+++ b/src/test/java/com/google/firebase/messaging/InstanceIdClientImplTest.java
@@ -41,6 +41,7 @@ import com.google.firebase.OutgoingHttpRequest;
 import com.google.firebase.TestOnlyImplFirebaseTrampolines;
 import com.google.firebase.auth.MockGoogleCredentials;
 import com.google.firebase.internal.ApiClientUtils;
+import com.google.firebase.internal.SdkUtils;
 import com.google.firebase.testing.TestResponseInterceptor;
 import com.google.firebase.testing.TestUtils;
 import java.io.ByteArrayOutputStream;
@@ -447,6 +448,8 @@ public class InstanceIdClientImplTest {
       HttpRequest request, String expectedUrl) {
     assertEquals("POST", request.getRequestMethod());
     assertEquals(expectedUrl, request.getUrl().toString());
+    assertEquals(SdkUtils.getMetricsHeader(), request.getHeaders().get("X-Goog-Api-Client"));
+
   }
 
   private void checkExceptionFromHttpResponse(
diff --git a/src/test/java/com/google/firebase/projectmanagement/FirebaseProjectManagementServiceImplTest.java b/src/test/java/com/google/firebase/projectmanagement/FirebaseProjectManagementServiceImplTest.java
index 853074e..4221adc 100644
--- a/src/test/java/com/google/firebase/projectmanagement/FirebaseProjectManagementServiceImplTest.java
+++ b/src/test/java/com/google/firebase/projectmanagement/FirebaseProjectManagementServiceImplTest.java
@@ -1124,6 +1124,7 @@ public class FirebaseProjectManagementServiceImplTest {
     assertEquals(expectedUrl, request.getUrl().toString());
     assertEquals("Bearer test-token", request.getHeaders().getAuthorization());
     assertEquals(CLIENT_VERSION, request.getHeaders().get("X-Client-Version"));
+    assertEquals(SdkUtils.getMetricsHeader(), request.getHeaders().get("X-Goog-Api-Client"));
   }
 
   private void checkRequestPayload(Map<String, String> expected) throws IOException {
diff --git a/src/test/java/com/google/firebase/remoteconfig/FirebaseRemoteConfigClientImplTest.java b/src/test/java/com/google/firebase/remoteconfig/FirebaseRemoteConfigClientImplTest.java
index 0a04809..edc52a1 100644
--- a/src/test/java/com/google/firebase/remoteconfig/FirebaseRemoteConfigClientImplTest.java
+++ b/src/test/java/com/google/firebase/remoteconfig/FirebaseRemoteConfigClientImplTest.java
@@ -1185,6 +1185,7 @@ public class FirebaseRemoteConfigClientImplTest {
     assertEquals(TEST_REMOTE_CONFIG_URL + urlSuffix, request.getUrl().toString());
     HttpHeaders headers = request.getHeaders();
     assertEquals("fire-admin-java/" + SdkUtils.getVersion(), headers.get("X-Firebase-Client"));
+    assertEquals(SdkUtils.getMetricsHeader(), request.getHeaders().get("X-Goog-Api-Client"));
     assertEquals("gzip", headers.getAcceptEncoding());
   }
 
@@ -1197,6 +1198,7 @@ public class FirebaseRemoteConfigClientImplTest {
     assertEquals(TEST_REMOTE_CONFIG_URL + urlSuffix, request.getUrl().toString());
     HttpHeaders headers = request.getHeaders();
     assertEquals("fire-admin-java/" + SdkUtils.getVersion(), headers.get("X-Firebase-Client"));
+    assertEquals(SdkUtils.getMetricsHeader(), request.getHeaders().get("X-Goog-Api-Client"));
     assertEquals("gzip", headers.getAcceptEncoding());
     assertEquals(ifMatch, headers.getIfMatch());
   }
@@ -1206,6 +1208,7 @@ public class FirebaseRemoteConfigClientImplTest {
     assertEquals(TEST_REMOTE_CONFIG_URL + urlSuffix, request.getUrl().toString());
     HttpHeaders headers = request.getHeaders();
     assertEquals("fire-admin-java/" + SdkUtils.getVersion(), headers.get("X-Firebase-Client"));
+    assertEquals(SdkUtils.getMetricsHeader(), request.getHeaders().get("X-Goog-Api-Client"));
     assertEquals("gzip", headers.getAcceptEncoding());
   }