Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -31,8 +33,11 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/** A client for complying with the FCM topic subscription and unsubscription. */
class TopicSubscriptionClient {
/** A client for complying with the FCM topic subscription and unsubscription.
* @hide
* */
Comment thread
eldhosembabu marked this conversation as resolved.
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
Comment thread
gsakakihara marked this conversation as resolved.
public class TopicSubscriptionClient {

static final String ERROR_INTERNAL_SERVER_ERROR = "INTERNAL_SERVER_ERROR";
static final String ERROR_SERVICE_NOT_AVAILABLE = "SERVICE_NOT_AVAILABLE";
Expand All @@ -43,6 +48,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,
Expand Down Expand Up @@ -154,9 +176,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. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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");
Expand All @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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()
Expand Down
Loading