From 69a8705cf415fc39fd657887ca60446cc5719cfb Mon Sep 17 00:00:00 2001 From: eldhosembabu Date: Tue, 18 Aug 2026 12:49:45 -0700 Subject: [PATCH 1/4] Updating Github code to make it compatible for Google 3 importing. --- .../messaging/TopicSubscriptionClient.java | 27 +++++++++++++-- .../TopicSubscriptionClientRoboTest.java | 33 ++++++++++++++----- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/firebase-messaging/src/main/java/com/google/firebase/messaging/TopicSubscriptionClient.java b/firebase-messaging/src/main/java/com/google/firebase/messaging/TopicSubscriptionClient.java index e1c9ba6eac3..9b73774b5ec 100644 --- a/firebase-messaging/src/main/java/com/google/firebase/messaging/TopicSubscriptionClient.java +++ b/firebase-messaging/src/main/java/com/google/firebase/messaging/TopicSubscriptionClient.java @@ -17,6 +17,8 @@ import android.os.Build; import android.util.Log; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.annotation.WorkerThread; import com.google.android.gms.tasks.Task; @@ -32,7 +34,8 @@ import java.util.concurrent.TimeoutException; /** A client for complying with the FCM topic subscription and unsubscription. */ -class TopicSubscriptionClient { +@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) +public class TopicSubscriptionClient { static final String ERROR_INTERNAL_SERVER_ERROR = "INTERNAL_SERVER_ERROR"; static final String ERROR_SERVICE_NOT_AVAILABLE = "SERVICE_NOT_AVAILABLE"; @@ -43,6 +46,23 @@ class TopicSubscriptionClient { private final FirebaseApp firebaseApp; private final FirebaseMessaging firebaseMessaging; + @VisibleForTesting + public interface HttpConnectionFactory { + @NonNull + HttpURLConnection createConnection(@NonNull URL url) throws IOException; + } + + private static HttpConnectionFactory connectionFactory = + url -> (HttpURLConnection) url.openConnection(); + + /** + * This method will be used inside G3 for Hermetic tests. + */ + @VisibleForTesting + public static void setConnectionFactoryForTesting(@Nullable HttpConnectionFactory factory) { + connectionFactory = factory != null ? factory : url -> (HttpURLConnection) url.openConnection(); + } + TopicSubscriptionClient( FirebaseApp firebaseApp, FirebaseMessaging firebaseMessaging, @@ -154,9 +174,10 @@ private static void closeQuietly(HttpURLConnection connection) { } } + @NonNull @VisibleForTesting - protected HttpURLConnection createConnection(URL url) throws IOException { - return (HttpURLConnection) url.openConnection(); + protected HttpURLConnection createConnection(@NonNull URL url) throws IOException { + return connectionFactory.createConnection(url); } /** Awaits an RPC task, rethrowing any IOExceptions or RuntimeExceptions. */ diff --git a/firebase-messaging/src/test/java/com/google/firebase/messaging/TopicSubscriptionClientRoboTest.java b/firebase-messaging/src/test/java/com/google/firebase/messaging/TopicSubscriptionClientRoboTest.java index 502bcf803ae..29468e850df 100644 --- a/firebase-messaging/src/test/java/com/google/firebase/messaging/TopicSubscriptionClientRoboTest.java +++ b/firebase-messaging/src/test/java/com/google/firebase/messaging/TopicSubscriptionClientRoboTest.java @@ -17,7 +17,6 @@ import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -29,8 +28,8 @@ import com.google.firebase.FirebaseOptions; import com.google.firebase.installations.FirebaseInstallationsApi; import com.google.firebase.installations.InstallationTokenResult; +import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.concurrent.ExecutionException; @@ -164,30 +163,48 @@ public void testUnsubscribe_failure503_throwsUnknownStatus() throws Exception { @Test public void testSubscribe_success_closesInputStreamAndDisconnects() throws Exception { - InputStream mockInputStream = mock(InputStream.class); + CloseTrackingInputStream inputStream = new CloseTrackingInputStream(); when(mockConnection.getResponseCode()).thenReturn(200); - when(mockConnection.getInputStream()).thenReturn(mockInputStream); + when(mockConnection.getInputStream()).thenReturn(inputStream); runOnBackground(() -> client.subscribe(TEST_TOPIC)); - verify(mockInputStream).close(); + assertThat(inputStream.isClosed()).isTrue(); verify(mockConnection).disconnect(); } @Test public void testSubscribe_failure404_closesErrorStreamAndDisconnects() throws Exception { - InputStream mockErrorStream = mock(InputStream.class); + CloseTrackingInputStream errorStream = new CloseTrackingInputStream(); when(mockConnection.getResponseCode()).thenReturn(404); when(mockConnection.getResponseMessage()).thenReturn("Not Found"); when(mockConnection.getInputStream()).thenThrow(new IOException("Error")); - when(mockConnection.getErrorStream()).thenReturn(mockErrorStream); + when(mockConnection.getErrorStream()).thenReturn(errorStream); assertThrows(IOException.class, () -> runOnBackground(() -> client.subscribe(TEST_TOPIC))); - verify(mockErrorStream).close(); + assertThat(errorStream.isClosed()).isTrue(); verify(mockConnection).disconnect(); } + private static class CloseTrackingInputStream extends ByteArrayInputStream { + private boolean isClosed = false; + + CloseTrackingInputStream() { + super(new byte[0]); + } + + @Override + public void close() throws IOException { + isClosed = true; + super.close(); + } + + boolean isClosed() { + return isClosed; + } + } + private void runOnBackground(ThrowingRunnable runnable) throws Exception { Future future = Executors.newSingleThreadExecutor() From 0b5ee1e0c5a8b675719322ba43187a0d89f1781f Mon Sep 17 00:00:00 2001 From: eldhosembabu Date: Tue, 18 Aug 2026 12:59:59 -0700 Subject: [PATCH 2/4] Updating SDK version for tests --- .../firebase/messaging/DisplayNotificationRoboTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/firebase-messaging/src/test/java/com/google/firebase/messaging/DisplayNotificationRoboTest.java b/firebase-messaging/src/test/java/com/google/firebase/messaging/DisplayNotificationRoboTest.java index 0f4eed1a5dd..fb90c50b01d 100644 --- a/firebase-messaging/src/test/java/com/google/firebase/messaging/DisplayNotificationRoboTest.java +++ b/firebase-messaging/src/test/java/com/google/firebase/messaging/DisplayNotificationRoboTest.java @@ -475,7 +475,7 @@ public void testClickActionAndLink() { /** Test that a valid notification with color is displayed. */ @Test - @Config(sdk = Config.OLDEST_SDK) + @Config(sdk = Build.VERSION_CODES.N) public void testColor() { final String color = "#123456"; Bundle data = new Bundle(); @@ -489,7 +489,7 @@ public void testColor() { } @Test - @Config(sdk = Config.OLDEST_SDK) + @Config(sdk = Build.VERSION_CODES.N) public void testNoColor() { Bundle data = new Bundle(); data.putString(KEY_TITLE, "title 123"); @@ -503,7 +503,7 @@ public void testNoColor() { /** Test that the user can choose the default color via AndroidManifest metadata. */ @Test - @Config(sdk = Config.OLDEST_SDK) + @Config(sdk = Build.VERSION_CODES.N) public void testColorFromMetadata() { Bundle metadata = new Bundle(); metadata.putInt( From 32ea2088b7853b65cb62cbd1cbe973bffef588e4 Mon Sep 17 00:00:00 2001 From: eldhosembabu Date: Tue, 18 Aug 2026 15:21:03 -0700 Subject: [PATCH 3/4] Adding @hide in java docs for TopicSubscriptionClient --- .../google/firebase/messaging/TopicSubscriptionClient.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/firebase-messaging/src/main/java/com/google/firebase/messaging/TopicSubscriptionClient.java b/firebase-messaging/src/main/java/com/google/firebase/messaging/TopicSubscriptionClient.java index 9b73774b5ec..83ad3f859bc 100644 --- a/firebase-messaging/src/main/java/com/google/firebase/messaging/TopicSubscriptionClient.java +++ b/firebase-messaging/src/main/java/com/google/firebase/messaging/TopicSubscriptionClient.java @@ -33,7 +33,10 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -/** A client for complying with the FCM topic subscription and unsubscription. */ +/** A client for complying with the FCM topic subscription and unsubscription. + * + * @hide + * */ @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) public class TopicSubscriptionClient { From 8d26ddc3764227d3f9c8768b32a55145b3c07372 Mon Sep 17 00:00:00 2001 From: eldhosembabu Date: Wed, 19 Aug 2026 10:13:48 -0700 Subject: [PATCH 4/4] Removing extra * as per review comments. --- .../com/google/firebase/messaging/TopicSubscriptionClient.java | 1 - 1 file changed, 1 deletion(-) diff --git a/firebase-messaging/src/main/java/com/google/firebase/messaging/TopicSubscriptionClient.java b/firebase-messaging/src/main/java/com/google/firebase/messaging/TopicSubscriptionClient.java index 83ad3f859bc..e2c989c59ab 100644 --- a/firebase-messaging/src/main/java/com/google/firebase/messaging/TopicSubscriptionClient.java +++ b/firebase-messaging/src/main/java/com/google/firebase/messaging/TopicSubscriptionClient.java @@ -34,7 +34,6 @@ import java.util.concurrent.TimeoutException; /** A client for complying with the FCM topic subscription and unsubscription. - * * @hide * */ @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)