Skip to content

Commit bdb53b8

Browse files
committed
Add FeedbackSender and tests
1 parent 792e775 commit bdb53b8

File tree

8 files changed

+148
-25
lines changed

8 files changed

+148
-25
lines changed

firebase-appdistribution/src/main/java/com/google/firebase/appdistribution/impl/FeedbackActivity.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public class FeedbackActivity extends AppCompatActivity {
1818
public static final String SCREENSHOT_EXTRA_KEY =
1919
"com.google.firebase.appdistribution.FeedbackActivity.SCREENSHOT";
2020

21-
private FirebaseAppDistributionTesterApiClient testerApiClient;
21+
private FeedbackSender feedbackSender;
2222
private String releaseName;
2323
private Bitmap screenshot;
2424

@@ -27,17 +27,15 @@ protected void onCreate(Bundle savedInstanceState) {
2727
super.onCreate(savedInstanceState);
2828
releaseName = getIntent().getStringExtra(RELEASE_NAME_EXTRA_KEY);
2929
screenshot = getIntent().getParcelableExtra(SCREENSHOT_EXTRA_KEY);
30-
testerApiClient = FirebaseApp.getInstance().get(FirebaseAppDistributionTesterApiClient.class);
30+
feedbackSender = FirebaseApp.getInstance().get(FeedbackSender.class);
3131
setContentView(R.layout.activity_feedback);
3232
}
3333

3434
public void submitFeedback(View view) {
3535
setSubmittingStateEnabled(true);
3636
EditText feedbackText = (EditText) findViewById(R.id.feedbackText);
37-
testerApiClient
38-
.createFeedback(releaseName, feedbackText.getText().toString())
39-
.onSuccessTask(feedbackName -> testerApiClient.attachScreenshot(feedbackName, screenshot))
40-
.onSuccessTask(testerApiClient::commitFeedback)
37+
feedbackSender
38+
.sendFeedback(releaseName, feedbackText.getText().toString(), screenshot)
4139
.addOnSuccessListener(
4240
unused -> {
4341
LogWrapper.getInstance().i(TAG, "Feedback submitted");
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.google.firebase.appdistribution.impl;
2+
3+
import android.graphics.Bitmap;
4+
import com.google.android.gms.tasks.Task;
5+
6+
/** Sends tester feedback to the Tester API. */
7+
class FeedbackSender {
8+
9+
private final FirebaseAppDistributionTesterApiClient testerApiClient;
10+
11+
FeedbackSender(FirebaseAppDistributionTesterApiClient testerApiClient) {
12+
this.testerApiClient = testerApiClient;
13+
}
14+
15+
/** Send feedback text and screenshot to the Tester API for the given release. */
16+
Task<Void> sendFeedback(String releaseName, String feedbackText, Bitmap screenshot) {
17+
return testerApiClient
18+
.createFeedback(releaseName, feedbackText)
19+
.onSuccessTask(feedbackName -> testerApiClient.attachScreenshot(feedbackName, screenshot))
20+
.onSuccessTask(testerApiClient::commitFeedback);
21+
}
22+
}

firebase-appdistribution/src/main/java/com/google/firebase/appdistribution/impl/FirebaseAppDistributionImpl.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,8 @@ public void collectAndSendFeedback() {
313313

314314
@VisibleForTesting
315315
public void collectAndSendFeedback(Executor taskExecutor) {
316-
screenshotTaker.takeScreenshot()
316+
screenshotTaker
317+
.takeScreenshot()
317318
.onSuccessTask(
318319
taskExecutor,
319320
screenshot ->
@@ -325,8 +326,11 @@ public void collectAndSendFeedback(Executor taskExecutor) {
325326
LogWrapper.getInstance()
326327
.e("Failed to sign in tester. Could not collect feedback.", e))
327328
.onSuccessTask(taskExecutor, unused -> releaseIdentifier.identifyRelease())
328-
.onSuccessTask(taskExecutor, releaseName -> launchFeedbackActivity(releaseName, screenshot)))
329-
.addOnFailureListener(taskExecutor, e -> LogWrapper.getInstance().e("Failed to launch feedback flow", e));
329+
.onSuccessTask(
330+
taskExecutor,
331+
releaseName -> launchFeedbackActivity(releaseName, screenshot)))
332+
.addOnFailureListener(
333+
taskExecutor, e -> LogWrapper.getInstance().e("Failed to launch feedback flow", e));
330334
}
331335

332336
private Task<Void> launchFeedbackActivity(String releaseName, Bitmap screenshot) {

firebase-appdistribution/src/main/java/com/google/firebase/appdistribution/impl/FirebaseAppDistributionRegistrar.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,36 +46,38 @@ public class FirebaseAppDistributionRegistrar implements ComponentRegistrar {
4646
Component.builder(FirebaseAppDistribution.class)
4747
.add(Dependency.required(FirebaseApp.class))
4848
.add(Dependency.requiredProvider(FirebaseInstallationsApi.class))
49-
.add(Dependency.required(FirebaseAppDistributionTesterApiClient.class))
49+
.add(Dependency.required(FeedbackSender.class))
5050
.factory(this::buildFirebaseAppDistribution)
5151
// construct FirebaseAppDistribution instance on startup so we can register for
5252
// activity lifecycle callbacks before the API is called
5353
.alwaysEager()
5454
.build(),
55-
Component.builder(FirebaseAppDistributionTesterApiClient.class)
55+
Component.builder(FeedbackSender.class)
5656
.add(Dependency.required(FirebaseApp.class))
5757
.add(Dependency.requiredProvider(FirebaseInstallationsApi.class))
58-
.factory(this::buildFirebaseAppDistributionTesterApiClient)
58+
.factory(this::buildFeedbackSender)
5959
.build(),
6060
LibraryVersionComponent.create("fire-appdistribution", BuildConfig.VERSION_NAME));
6161
}
6262

63-
private FirebaseAppDistributionTesterApiClient buildFirebaseAppDistributionTesterApiClient(
64-
ComponentContainer container) {
63+
private FeedbackSender buildFeedbackSender(ComponentContainer container) {
6564
FirebaseApp firebaseApp = container.get(FirebaseApp.class);
6665
Provider<FirebaseInstallationsApi> firebaseInstallationsApiProvider =
6766
container.getProvider(FirebaseInstallationsApi.class);
68-
return new FirebaseAppDistributionTesterApiClient(
69-
firebaseApp, firebaseInstallationsApiProvider, new TesterApiHttpClient(firebaseApp));
67+
FirebaseAppDistributionTesterApiClient testerApiClient =
68+
new FirebaseAppDistributionTesterApiClient(
69+
firebaseApp, firebaseInstallationsApiProvider, new TesterApiHttpClient(firebaseApp));
70+
return new FeedbackSender(testerApiClient);
7071
}
7172

7273
private FirebaseAppDistribution buildFirebaseAppDistribution(ComponentContainer container) {
7374
FirebaseApp firebaseApp = container.get(FirebaseApp.class);
74-
FirebaseAppDistributionTesterApiClient testerApiClient =
75-
container.get(FirebaseAppDistributionTesterApiClient.class);
7675
Context context = firebaseApp.getApplicationContext();
7776
Provider<FirebaseInstallationsApi> firebaseInstallationsApiProvider =
7877
container.getProvider(FirebaseInstallationsApi.class);
78+
FirebaseAppDistributionTesterApiClient testerApiClient =
79+
new FirebaseAppDistributionTesterApiClient(
80+
firebaseApp, firebaseInstallationsApiProvider, new TesterApiHttpClient(firebaseApp));
7981
SignInStorage signInStorage = new SignInStorage(context);
8082
FirebaseAppDistributionLifecycleNotifier lifecycleNotifier =
8183
FirebaseAppDistributionLifecycleNotifier.getInstance();

firebase-appdistribution/src/main/java/com/google/firebase/appdistribution/impl/FirebaseAppDistributionTesterApiClient.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import com.google.firebase.inject.Provider;
2929
import com.google.firebase.installations.FirebaseInstallationsApi;
3030
import com.google.firebase.installations.InstallationTokenResult;
31-
import java.io.ByteArrayOutputStream;
3231
import java.util.concurrent.Executor;
3332
import java.util.concurrent.Executors;
3433
import org.json.JSONArray;

firebase-appdistribution/src/main/java/com/google/firebase/appdistribution/impl/ScreenshotTaker.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88
/** A class that takes screenshots of the host app. */
99
class ScreenshotTaker {
1010

11-
private static final Bitmap TEMP_FIXED_BITMAP =
12-
Bitmap.createBitmap(400, 400, Config.RGB_565);
11+
private static final Bitmap TEMP_FIXED_BITMAP = Bitmap.createBitmap(400, 400, Config.RGB_565);
1312

1413
/** Take a screenshot of the running host app. */
1514
Task<Bitmap> takeScreenshot() {
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package com.google.firebase.appdistribution.impl;
2+
3+
import static org.mockito.Mockito.verify;
4+
import static org.mockito.Mockito.when;
5+
6+
import android.graphics.Bitmap;
7+
import android.graphics.Bitmap.Config;
8+
import com.google.android.gms.tasks.Task;
9+
import com.google.android.gms.tasks.Tasks;
10+
import com.google.firebase.appdistribution.FirebaseAppDistributionException;
11+
import com.google.firebase.appdistribution.FirebaseAppDistributionException.Status;
12+
import org.junit.Before;
13+
import org.junit.Test;
14+
import org.junit.runner.RunWith;
15+
import org.mockito.Mock;
16+
import org.mockito.MockitoAnnotations;
17+
import org.robolectric.RobolectricTestRunner;
18+
19+
@RunWith(RobolectricTestRunner.class)
20+
public class FeedbackSenderTest {
21+
private static final String TEST_RELEASE_NAME = "release-name";
22+
private static final String TEST_FEEDBACK_NAME = "feedback-name";
23+
private static final String TEST_FEEDBACK_TEXT = "Feedback text";
24+
private static final Bitmap TEST_SCREENSHOT = Bitmap.createBitmap(400, 400, Config.RGB_565);
25+
26+
@Mock private FirebaseAppDistributionTesterApiClient mockTesterApiClient;
27+
28+
private FeedbackSender feedbackSender;
29+
30+
@Before
31+
public void setup() {
32+
MockitoAnnotations.initMocks(this);
33+
feedbackSender = new FeedbackSender(mockTesterApiClient);
34+
}
35+
36+
@Test
37+
public void sendFeedback_success() throws Exception {
38+
when(mockTesterApiClient.createFeedback(TEST_RELEASE_NAME, TEST_FEEDBACK_TEXT))
39+
.thenReturn(Tasks.forResult(TEST_FEEDBACK_NAME));
40+
when(mockTesterApiClient.attachScreenshot(TEST_FEEDBACK_NAME, TEST_SCREENSHOT))
41+
.thenReturn(Tasks.forResult(TEST_FEEDBACK_NAME));
42+
when(mockTesterApiClient.commitFeedback(TEST_FEEDBACK_NAME)).thenReturn(Tasks.forResult(null));
43+
44+
Task<Void> task =
45+
feedbackSender.sendFeedback(TEST_RELEASE_NAME, TEST_FEEDBACK_TEXT, TEST_SCREENSHOT);
46+
TestUtils.awaitTask(task);
47+
48+
verify(mockTesterApiClient).createFeedback(TEST_RELEASE_NAME, TEST_FEEDBACK_TEXT);
49+
verify(mockTesterApiClient).attachScreenshot(TEST_FEEDBACK_NAME, TEST_SCREENSHOT);
50+
verify(mockTesterApiClient).commitFeedback(TEST_FEEDBACK_NAME);
51+
}
52+
53+
@Test
54+
public void sendFeedback_createFeedbackFails_failsTask() {
55+
FirebaseAppDistributionException cause =
56+
new FirebaseAppDistributionException("test ex", Status.AUTHENTICATION_FAILURE);
57+
when(mockTesterApiClient.createFeedback(TEST_RELEASE_NAME, TEST_FEEDBACK_TEXT))
58+
.thenReturn(Tasks.forException(cause));
59+
60+
Task<Void> task =
61+
feedbackSender.sendFeedback(TEST_RELEASE_NAME, TEST_FEEDBACK_TEXT, TEST_SCREENSHOT);
62+
63+
TestUtils.awaitTaskFailure(task, Status.AUTHENTICATION_FAILURE, "test ex");
64+
}
65+
66+
@Test
67+
public void sendFeedback_attachScreenshotFails_failsTask() {
68+
when(mockTesterApiClient.createFeedback(TEST_RELEASE_NAME, TEST_FEEDBACK_TEXT))
69+
.thenReturn(Tasks.forResult(TEST_FEEDBACK_NAME));
70+
FirebaseAppDistributionException cause =
71+
new FirebaseAppDistributionException("test ex", Status.AUTHENTICATION_FAILURE);
72+
when(mockTesterApiClient.attachScreenshot(TEST_FEEDBACK_NAME, TEST_SCREENSHOT))
73+
.thenReturn(Tasks.forException(cause));
74+
75+
Task<Void> task =
76+
feedbackSender.sendFeedback(TEST_RELEASE_NAME, TEST_FEEDBACK_TEXT, TEST_SCREENSHOT);
77+
78+
TestUtils.awaitTaskFailure(task, Status.AUTHENTICATION_FAILURE, "test ex");
79+
}
80+
81+
@Test
82+
public void sendFeedback_commitFeedbackFails_failsTask() {
83+
when(mockTesterApiClient.createFeedback(TEST_RELEASE_NAME, TEST_FEEDBACK_TEXT))
84+
.thenReturn(Tasks.forResult(TEST_FEEDBACK_NAME));
85+
when(mockTesterApiClient.attachScreenshot(TEST_FEEDBACK_NAME, TEST_SCREENSHOT))
86+
.thenReturn(Tasks.forResult(TEST_FEEDBACK_NAME));
87+
FirebaseAppDistributionException cause =
88+
new FirebaseAppDistributionException("test ex", Status.AUTHENTICATION_FAILURE);
89+
when(mockTesterApiClient.commitFeedback(TEST_FEEDBACK_NAME))
90+
.thenReturn(Tasks.forException(cause));
91+
92+
Task<Void> task =
93+
feedbackSender.sendFeedback(TEST_RELEASE_NAME, TEST_FEEDBACK_TEXT, TEST_SCREENSHOT);
94+
95+
TestUtils.awaitTaskFailure(task, Status.AUTHENTICATION_FAILURE, "test ex");
96+
}
97+
}

firebase-appdistribution/src/test/java/com/google/firebase/appdistribution/impl/FirebaseAppDistributionServiceImplTest.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -605,17 +605,19 @@ public void updateApp_withApkReleaseAvailable_returnsSameApkTask() {
605605
}
606606

607607
@Test
608-
public void collectAndSendFeedback_startsFeedbackActivity() throws InterruptedException {
608+
public void collectAndSendFeedback_signsInTesterAndStartsActivity() throws InterruptedException {
609609
ExecutorService testExecutor = Executors.newSingleThreadExecutor();
610-
when(mockSignInStorage.getSignInStatus()).thenReturn(true);
611610
when(mockReleaseIdentifier.identifyRelease()).thenReturn(Tasks.forResult("release-name"));
612611

613612
firebaseAppDistribution.collectAndSendFeedback(testExecutor);
614613
TestUtils.awaitAsyncOperations(testExecutor);
615614

616615
ArgumentCaptor<Intent> argument = ArgumentCaptor.forClass(Intent.class);
617616
verify(activity).startActivity(argument.capture());
618-
assertThat(argument.getValue().getStringExtra(RELEASE_NAME_EXTRA_KEY)).isEqualTo("release-name");
619-
assertThat(argument.getValue().<Bitmap>getParcelableExtra(SCREENSHOT_EXTRA_KEY)).isEqualTo(TEST_SCREENSHOT);
617+
verify(mockTesterSignInManager).signInTester();
618+
assertThat(argument.getValue().getStringExtra(RELEASE_NAME_EXTRA_KEY))
619+
.isEqualTo("release-name");
620+
assertThat(argument.getValue().<Bitmap>getParcelableExtra(SCREENSHOT_EXTRA_KEY))
621+
.isEqualTo(TEST_SCREENSHOT);
620622
}
621623
}

0 commit comments

Comments
 (0)