Skip to content

Commit 27f5ebb

Browse files
committed
Address Manny's feedback
1 parent c7c34e0 commit 27f5ebb

File tree

4 files changed

+28
-33
lines changed

4 files changed

+28
-33
lines changed

firebase-appdistribution/src/main/java/com/google/firebase/appdistribution/AabUpdater.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,11 @@ UpdateTaskImpl updateAab(@NonNull AppDistributionReleaseInternal newRelease) {
9797

9898
// On a background thread, fetch the redirect URL and open it in the Play app
9999
runAsyncInTask(executor, () -> fetchDownloadRedirectUrl(newRelease.getDownloadUrl()))
100-
.onSuccessTask(
101-
executor,
102-
combineWithResultOf(executor, () -> lifecycleNotifier.getForegroundActivity()))
100+
.onSuccessTask(combineWithResultOf(() -> lifecycleNotifier.getForegroundActivity()))
103101
.addOnSuccessListener(
104-
executor,
105102
urlAndActivity ->
106103
openRedirectUrlInPlay(urlAndActivity.first(), urlAndActivity.second()))
107-
.addOnFailureListener(executor, this::setUpdateTaskCompletionError);
104+
.addOnFailureListener(this::setUpdateTaskCompletionError);
108105

109106
return cachedUpdateTask;
110107
}
@@ -159,8 +156,8 @@ private void openRedirectUrlInPlay(String redirectUrl, Activity hostActivity) {
159156
updateIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
160157
LogWrapper.getInstance().v(TAG + "Redirecting to play");
161158

162-
// Launch the intent outside of the synchronized block because we don't want to risk the
163-
// activity leaving the foreground while we wait for the lock.
159+
// Launch the intent before the synchronized block to avoid failing to update in the rare
160+
// scenario where the activity moves to the background while we're awaiting the lock.
164161
hostActivity.startActivity(updateIntent);
165162

166163
synchronized (updateAabLock) {

firebase-appdistribution/src/main/java/com/google/firebase/appdistribution/TaskUtils.java

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -122,35 +122,18 @@ static <T1, T2> CombinedTaskResults<T1, T2> create(T1 first, T2 second) {
122122
*
123123
* <pre>{@code
124124
* runFirstAsyncTask()
125-
* .onSuccessTask(executor, combineWithResultOf(executor, () -> startSecondAsyncTask())
125+
* .onSuccessTask(combineWithResultOf(executor, () -> startSecondAsyncTask())
126126
* .addOnSuccessListener(
127-
* executor,
128127
* results ->
129128
* doSomethingWithBothResults(results.result1(), results.result2()));
130129
* }</pre>
131130
*
132-
* @param executor The {@link Executor} to use to call the listener that combines the results
133131
* @param secondTaskSource A {@link TaskSource} providing the next task to run
134132
* @param <T1> The result type of the first task
135133
* @param <T2> The result type of the second task
136134
* @return A {@link SuccessContinuation} that will return a new task with result type {@link
137135
* CombinedTaskResults}, combining the results of both tasks
138136
*/
139-
static <T1, T2> SuccessContinuation<T1, CombinedTaskResults<T1, T2>> combineWithResultOf(
140-
Executor executor, TaskSource<T2> secondTaskSource) {
141-
return firstResult ->
142-
secondTaskSource
143-
.get()
144-
.onSuccessTask(
145-
executor,
146-
secondResult ->
147-
Tasks.forResult(CombinedTaskResults.create(firstResult, secondResult)));
148-
}
149-
150-
/**
151-
* A version of #combineWithResultsOf that runs the listener that combines the results on the main
152-
* thread.
153-
*/
154137
static <T1, T2> SuccessContinuation<T1, CombinedTaskResults<T1, T2>> combineWithResultOf(
155138
TaskSource<T2> secondTaskSource) {
156139
return firstResult ->

firebase-appdistribution/src/test/java/com/google/firebase/appdistribution/AabUpdaterTest.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515

1616
import static com.google.common.truth.Truth.assertThat;
1717
import static com.google.firebase.appdistribution.TestUtils.assertTaskFailure;
18+
import static com.google.firebase.appdistribution.TestUtils.awaitAsyncOperations;
1819
import static org.junit.Assert.assertEquals;
1920
import static org.mockito.Mockito.when;
2021
import static org.robolectric.Shadows.shadowOf;
22+
import static org.robolectric.annotation.LooperMode.Mode.PAUSED;
2123

2224
import android.app.Activity;
2325
import android.net.Uri;
@@ -31,7 +33,6 @@
3133
import java.util.List;
3234
import java.util.concurrent.ExecutorService;
3335
import java.util.concurrent.Executors;
34-
import java.util.concurrent.TimeUnit;
3536
import javax.net.ssl.HttpsURLConnection;
3637
import org.junit.Before;
3738
import org.junit.Test;
@@ -41,9 +42,11 @@
4142
import org.mockito.MockitoAnnotations;
4243
import org.robolectric.Robolectric;
4344
import org.robolectric.RobolectricTestRunner;
45+
import org.robolectric.annotation.LooperMode;
4446
import org.robolectric.shadows.ShadowActivity;
4547

4648
@RunWith(RobolectricTestRunner.class)
49+
@LooperMode(PAUSED)
4750
public class AabUpdaterTest {
4851
private static final String TEST_URL = "https://test-url";
4952
private static final String REDIRECT_TO_PLAY = "https://redirect-to-play-url";
@@ -95,7 +98,7 @@ public void updateAppTask_whenOpenConnectionFails_setsNetworkFailure()
9598
when(mockHttpsUrlConnectionFactory.openConnection(TEST_URL)).thenThrow(caughtException);
9699

97100
UpdateTask updateTask = aabUpdater.updateAab(TEST_RELEASE_NEWER_AAB_INTERNAL);
98-
testExecutor.awaitTermination(100, TimeUnit.MILLISECONDS);
101+
awaitAsyncOperations(testExecutor);
99102

100103
assertTaskFailure(
101104
updateTask, Status.NETWORK_FAILURE, "Failed to open connection", caughtException);
@@ -107,7 +110,7 @@ public void updateAppTask_isNotRedirectResponse_setsDownloadFailure()
107110
when(mockHttpsUrlConnection.getResponseCode()).thenReturn(200);
108111

109112
UpdateTask updateTask = aabUpdater.updateAab(TEST_RELEASE_NEWER_AAB_INTERNAL);
110-
testExecutor.awaitTermination(100, TimeUnit.MILLISECONDS);
113+
awaitAsyncOperations(testExecutor);
111114

112115
assertTaskFailure(updateTask, Status.DOWNLOAD_FAILURE, "Expected redirect");
113116
}
@@ -118,7 +121,7 @@ public void updateAppTask_missingLocationHeader_setsDownloadFailure()
118121
when(mockHttpsUrlConnection.getHeaderField("Location")).thenReturn(null);
119122

120123
UpdateTask updateTask = aabUpdater.updateAab(TEST_RELEASE_NEWER_AAB_INTERNAL);
121-
testExecutor.awaitTermination(100, TimeUnit.MILLISECONDS);
124+
awaitAsyncOperations(testExecutor);
122125

123126
assertTaskFailure(updateTask, Status.DOWNLOAD_FAILURE, "No Location header");
124127
}
@@ -128,7 +131,7 @@ public void updateAppTask_emptyLocationHeader_setsDownloadFailure() throws Inter
128131
when(mockHttpsUrlConnection.getHeaderField("Location")).thenReturn("");
129132

130133
UpdateTask updateTask = aabUpdater.updateAab(TEST_RELEASE_NEWER_AAB_INTERNAL);
131-
testExecutor.awaitTermination(100, TimeUnit.MILLISECONDS);
134+
awaitAsyncOperations(testExecutor);
132135

133136
assertTaskFailure(updateTask, Status.DOWNLOAD_FAILURE, "Empty Location header");
134137
}
@@ -139,7 +142,7 @@ public void updateAppTask_whenAabReleaseAvailable_redirectsToPlay() throws Excep
139142

140143
UpdateTask updateTask = aabUpdater.updateAab(TEST_RELEASE_NEWER_AAB_INTERNAL);
141144
updateTask.addOnProgressListener(testExecutor, progressEvents::add);
142-
testExecutor.awaitTermination(100, TimeUnit.MILLISECONDS);
145+
awaitAsyncOperations(testExecutor);
143146

144147
assertThat(shadowActivity.getNextStartedActivity().getData())
145148
.isEqualTo(Uri.parse(REDIRECT_TO_PLAY));
@@ -156,12 +159,11 @@ public void updateAppTask_whenAabReleaseAvailable_redirectsToPlay() throws Excep
156159
@Test
157160
public void updateAppTask_onAppResume_setsUpdateCancelled() throws InterruptedException {
158161
UpdateTask updateTask = aabUpdater.updateAab(TEST_RELEASE_NEWER_AAB_INTERNAL);
159-
testExecutor.awaitTermination(100, TimeUnit.MILLISECONDS);
162+
awaitAsyncOperations(testExecutor);
160163
aabUpdater.onActivityStarted(activity);
161164

162165
FirebaseAppDistributionException exception =
163166
assertTaskFailure(updateTask, Status.INSTALLATION_CANCELED, ErrorMessages.UPDATE_CANCELED);
164-
165167
assertEquals(
166168
ReleaseUtils.convertToAppDistributionRelease(TEST_RELEASE_NEWER_AAB_INTERNAL),
167169
exception.getRelease());

firebase-appdistribution/src/test/java/com/google/firebase/appdistribution/TestUtils.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@
1414

1515
package com.google.firebase.appdistribution;
1616

17+
import static android.os.Looper.getMainLooper;
1718
import static com.google.common.truth.Truth.assertThat;
19+
import static org.robolectric.Shadows.shadowOf;
1820

1921
import com.google.android.gms.tasks.Task;
2022
import com.google.firebase.appdistribution.FirebaseAppDistributionException.Status;
23+
import java.util.concurrent.ExecutorService;
24+
import java.util.concurrent.TimeUnit;
2125

2226
final class TestUtils {
2327
private TestUtils() {}
@@ -37,4 +41,13 @@ static void assertTaskFailure(
3741
assertTaskFailure(task, status, messageSubstring);
3842
assertThat(task.getException()).hasCauseThat().isEqualTo(cause);
3943
}
44+
45+
static void awaitAsyncOperations(ExecutorService executorService) throws InterruptedException {
46+
// Await anything enqueued to the executor
47+
executorService.awaitTermination(100, TimeUnit.MILLISECONDS);
48+
49+
// Idle the main looper, which is also running these tests, so any Task or lifecycle callbacks
50+
// can be handled. See http://robolectric.org/blog/2019/06/04/paused-looper/ for more info.
51+
shadowOf(getMainLooper()).idle();
52+
}
4053
}

0 commit comments

Comments
 (0)