Commit 6a3e15db authored by Hazem Ashmawy's avatar Hazem Ashmawy Committed by Commit Bot

[AW][Dev-UI] Add espresso tests for crash consent error

Add tests for crash collection consent error message. This also handles
a silent bug where calling assertNoUnverifiedIntents in the teardown of
a skipped test, will cause a crash, by checking that the activity is
launched.

Fixed: 1106315
Test: run_webview_instrumentation_test_apk -f "*android_webview.devui*"
Change-Id: Ie0252d898f848f69dee90a6f526691dfab495289
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2411943
Commit-Queue: Hazem Ashmawy <hazems@chromium.org>
Reviewed-by: default avatarNate Fischer <ntfschr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#807493}
parent 9da479a7
...@@ -35,6 +35,7 @@ import android.content.Context; ...@@ -35,6 +35,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Canvas; import android.graphics.Canvas;
...@@ -49,6 +50,7 @@ import androidx.test.espresso.intent.Intents; ...@@ -49,6 +50,7 @@ import androidx.test.espresso.intent.Intents;
import androidx.test.espresso.intent.matcher.IntentMatchers; import androidx.test.espresso.intent.matcher.IntentMatchers;
import androidx.test.espresso.intent.rule.IntentsTestRule; import androidx.test.espresso.intent.rule.IntentsTestRule;
import androidx.test.filters.LargeTest; import androidx.test.filters.LargeTest;
import androidx.test.filters.MediumTest;
import org.hamcrest.Description; import org.hamcrest.Description;
import org.hamcrest.Matcher; import org.hamcrest.Matcher;
...@@ -59,6 +61,7 @@ import org.junit.Rule; ...@@ -59,6 +61,7 @@ import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.chromium.android_webview.common.PlatformServiceBridge;
import org.chromium.android_webview.common.crash.CrashInfo; import org.chromium.android_webview.common.crash.CrashInfo;
import org.chromium.android_webview.common.crash.CrashInfo.UploadState; import org.chromium.android_webview.common.crash.CrashInfo.UploadState;
import org.chromium.android_webview.common.crash.CrashUploadUtil; import org.chromium.android_webview.common.crash.CrashUploadUtil;
...@@ -67,8 +70,11 @@ import org.chromium.android_webview.common.crash.SystemWideCrashDirectories; ...@@ -67,8 +70,11 @@ import org.chromium.android_webview.common.crash.SystemWideCrashDirectories;
import org.chromium.android_webview.devui.CrashesListFragment; import org.chromium.android_webview.devui.CrashesListFragment;
import org.chromium.android_webview.devui.MainActivity; import org.chromium.android_webview.devui.MainActivity;
import org.chromium.android_webview.devui.R; import org.chromium.android_webview.devui.R;
import org.chromium.android_webview.devui.WebViewPackageError;
import org.chromium.android_webview.devui.util.CrashBugUrlFactory; import org.chromium.android_webview.devui.util.CrashBugUrlFactory;
import org.chromium.android_webview.devui.util.WebViewPackageHelper;
import org.chromium.android_webview.test.AwJUnit4ClassRunner; import org.chromium.android_webview.test.AwJUnit4ClassRunner;
import org.chromium.base.Callback;
import org.chromium.base.FileUtils; import org.chromium.base.FileUtils;
import org.chromium.base.test.util.CallbackHelper; import org.chromium.base.test.util.CallbackHelper;
import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Feature;
...@@ -79,6 +85,8 @@ import java.io.File; ...@@ -79,6 +85,8 @@ import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
...@@ -100,8 +108,11 @@ public class CrashesListFragmentTest { ...@@ -100,8 +108,11 @@ public class CrashesListFragmentTest {
public void tearDown() { public void tearDown() {
FileUtils.recursivelyDeleteFile(SystemWideCrashDirectories.getWebViewCrashDir(), null); FileUtils.recursivelyDeleteFile(SystemWideCrashDirectories.getWebViewCrashDir(), null);
FileUtils.recursivelyDeleteFile(SystemWideCrashDirectories.getWebViewCrashLogDir(), null); FileUtils.recursivelyDeleteFile(SystemWideCrashDirectories.getWebViewCrashLogDir(), null);
// Tests are responsible for verifying every Intent they trigger. // Activity is launched, i.e the test is not skipped.
assertNoUnverifiedIntents(); if (mRule.getActivity() != null) {
// Tests are responsible for verifying every Intent they trigger.
assertNoUnverifiedIntents();
}
} }
private void launchCrashesFragment() { private void launchCrashesFragment() {
...@@ -293,6 +304,26 @@ public class CrashesListFragmentTest { ...@@ -293,6 +304,26 @@ public class CrashesListFragmentTest {
return bodyDataInteraction; return bodyDataInteraction;
} }
private static class TestPlatformServiceBridge extends PlatformServiceBridge {
private boolean mCanUseGms;
private boolean mUserConsent;
TestPlatformServiceBridge(boolean canUseGms, boolean userConsent) {
mCanUseGms = canUseGms;
mUserConsent = userConsent;
}
@Override
public boolean canUseGms() {
return mCanUseGms;
}
@Override
public void queryMetricsSetting(Callback<Boolean> callback) {
callback.onResult(mUserConsent);
}
}
@Test @Test
@Feature({"AndroidWebView"}) @Feature({"AndroidWebView"})
public void testShowingSingleCrashReport_uploaded() throws Throwable { public void testShowingSingleCrashReport_uploaded() throws Throwable {
...@@ -859,4 +890,120 @@ public class CrashesListFragmentTest { ...@@ -859,4 +890,120 @@ public class CrashesListFragmentTest {
// This a pending upload, nothing should be copied // This a pending upload, nothing should be copied
assertThat(getClipBoardTextOnUiThread(context), is("")); assertThat(getClipBoardTextOnUiThread(context), is(""));
} }
@Test
@MediumTest
@Feature({"AndroidWebView"})
public void testConsentErrorMessage_notShown_differentWebViewPackageIsShown() throws Throwable {
Context context = InstrumentationRegistry.getTargetContext();
// Inject a dummy PackageInfo as the current WebView package to make sure it will always be
// different from the test's app package.
WebViewPackageHelper.setCurrentWebViewPackageForTesting(
HomeFragmentTest.FAKE_WEBVIEW_PACKAGE);
PlatformServiceBridge.injectInstance(
new TestPlatformServiceBridge(/*canUseGms=*/true, /*userConsent=*/false));
launchCrashesFragment();
String expectedErrorMessage = String.format(Locale.US,
WebViewPackageError.DIFFERENT_WEBVIEW_PROVIDER_ERROR_MESSAGE,
WebViewPackageHelper.loadLabel(context));
onView(withId(R.id.main_error_view)).check(matches(isDisplayed()));
onView(withId(R.id.error_text)).check(matches(withText(expectedErrorMessage)));
}
@Test
@MediumTest
@Feature({"AndroidWebView"})
public void testConsentErrorMessage_notShown_userConsented() throws Throwable {
Context context = InstrumentationRegistry.getTargetContext();
// Inject test app package as the current WebView package.
WebViewPackageHelper.setCurrentWebViewPackageForTesting(
WebViewPackageHelper.getContextPackageInfo(context));
PlatformServiceBridge.injectInstance(
new TestPlatformServiceBridge(/*canUseGms=*/true, /*userConsent=*/true));
launchCrashesFragment();
onView(withId(R.id.main_error_view)).check(matches(not(isDisplayed())));
}
@Test
@MediumTest
@Feature({"AndroidWebView"})
public void testConsentErrorMessage_shown_canUseGms() throws Throwable {
Context context = InstrumentationRegistry.getTargetContext();
Intent settingsIntent =
new Intent(CrashesListFragment.USAGE_AND_DIAGONSTICS_ACTIVITY_INTENT_ACTION);
List<ResolveInfo> intentResolveInfo =
context.getPackageManager().queryIntentActivities(settingsIntent, 0);
Assume.assumeTrue(
"This test assumes \"usage& diagonstics\" settings can be found on the device",
intentResolveInfo.size() > 0);
// Inject test app package as the current WebView package.
WebViewPackageHelper.setCurrentWebViewPackageForTesting(
WebViewPackageHelper.getContextPackageInfo(context));
PlatformServiceBridge.injectInstance(
new TestPlatformServiceBridge(/*canUseGms=*/true, /*userConsent=*/false));
launchCrashesFragment();
onView(withId(R.id.main_error_view)).check(matches(isDisplayed()));
onView(withId(R.id.error_text))
.check(matches(
withText(CrashesListFragment.CRASH_COLLECTION_DISABLED_ERROR_MESSAGE)));
onView(withId(R.id.action_button))
.check(matches(withText("Open Settings")))
.perform(click());
intended(IntentMatchers.hasAction(
CrashesListFragment.USAGE_AND_DIAGONSTICS_ACTIVITY_INTENT_ACTION));
}
@Test
@MediumTest
@Feature({"AndroidWebView"})
public void testConsentErrorMessage_shown_onlyInCrashFragment() throws Throwable {
Context context = InstrumentationRegistry.getTargetContext();
// Inject test app package as the current WebView package.
WebViewPackageHelper.setCurrentWebViewPackageForTesting(
WebViewPackageHelper.getContextPackageInfo(context));
PlatformServiceBridge.injectInstance(
new TestPlatformServiceBridge(/*canUseGms=*/true, /*userConsent=*/false));
launchCrashesFragment();
onView(withId(R.id.main_error_view)).check(matches(isDisplayed()));
onView(withId(R.id.error_text))
.check(matches(
withText(CrashesListFragment.CRASH_COLLECTION_DISABLED_ERROR_MESSAGE)));
// CrashesListFragment -> FlagsFragment (Not shown)
onView(withId(R.id.navigation_flags_ui)).perform(click());
onView(withId(R.id.main_error_view)).check(matches(not(isDisplayed())));
// FlagsFragment -> HomeFragment (Not shown)
onView(withId(R.id.navigation_home)).perform(click());
onView(withId(R.id.main_error_view)).check(matches(not(isDisplayed())));
// HomeFragment -> CrashesListFragment (shown again)
onView(withId(R.id.navigation_crash_ui)).perform(click());
onView(withId(R.id.main_error_view)).check(matches(isDisplayed()));
onView(withId(R.id.error_text))
.check(matches(
withText(CrashesListFragment.CRASH_COLLECTION_DISABLED_ERROR_MESSAGE)));
}
@Test
@MediumTest
@Feature({"AndroidWebView"})
public void testConsentErrorMessage_shown_cannotUseGms() throws Throwable {
Context context = InstrumentationRegistry.getTargetContext();
// Inject test app package as the current WebView package.
WebViewPackageHelper.setCurrentWebViewPackageForTesting(
WebViewPackageHelper.getContextPackageInfo(context));
PlatformServiceBridge.injectInstance(
new TestPlatformServiceBridge(/*canUseGms=*/false, /*userConsent=*/false));
launchCrashesFragment();
onView(withId(R.id.main_error_view)).check(matches(isDisplayed()));
onView(withId(R.id.error_text))
.check(matches(withText(CrashesListFragment.NO_GMS_ERROR_MESSAGE)));
onView(withId(R.id.action_button)).check(matches(not(isDisplayed())));
}
} }
...@@ -68,6 +68,14 @@ public class CrashesListFragment extends DevUiBaseFragment { ...@@ -68,6 +68,14 @@ public class CrashesListFragment extends DevUiBaseFragment {
public static final String NO_WIFI_DIALOG_MESSAGE = public static final String NO_WIFI_DIALOG_MESSAGE =
"You are connected to a metered network or cellular data." "You are connected to a metered network or cellular data."
+ " Do you want to proceed?"; + " Do you want to proceed?";
public static final String CRASH_COLLECTION_DISABLED_ERROR_MESSAGE =
"Crash collection is disabled. Please turn on 'Usage & diagnostics' "
+ "from the three-dotted menu in Google settings.";
public static final String NO_GMS_ERROR_MESSAGE =
"Crash collection is not supported at the moment.";
public static final String USAGE_AND_DIAGONSTICS_ACTIVITY_INTENT_ACTION =
"com.android.settings.action.EXTRA_SETTINGS";
// Max number of crashes to show in the crashes list. // Max number of crashes to show in the crashes list.
public static final int MAX_CRASHES_NUMBER = 20; public static final int MAX_CRASHES_NUMBER = 20;
...@@ -484,11 +492,10 @@ public class CrashesListFragment extends DevUiBaseFragment { ...@@ -484,11 +492,10 @@ public class CrashesListFragment extends DevUiBaseFragment {
private void buildCrashConsentError(PersistentErrorView errorView) { private void buildCrashConsentError(PersistentErrorView errorView) {
if (PlatformServiceBridge.getInstance().canUseGms()) { if (PlatformServiceBridge.getInstance().canUseGms()) {
errorView.setText("Crash collection is disabled. Please turn on 'Usage & diagnostics' " errorView.setText(CRASH_COLLECTION_DISABLED_ERROR_MESSAGE);
+ "from the three-dotted menu in Google settings.");
// Open Google Settings activity, "Usage & diagnostics" activity is not exported and // Open Google Settings activity, "Usage & diagnostics" activity is not exported and
// cannot be opened directly. // cannot be opened directly.
Intent settingsIntent = new Intent("com.android.settings.action.EXTRA_SETTINGS"); Intent settingsIntent = new Intent(USAGE_AND_DIAGONSTICS_ACTIVITY_INTENT_ACTION);
List<ResolveInfo> intentResolveInfo = List<ResolveInfo> intentResolveInfo =
mContext.getPackageManager().queryIntentActivities(settingsIntent, 0); mContext.getPackageManager().queryIntentActivities(settingsIntent, 0);
// Show a button to open GMS settings activity only if it exists. // Show a button to open GMS settings activity only if it exists.
...@@ -502,7 +509,7 @@ public class CrashesListFragment extends DevUiBaseFragment { ...@@ -502,7 +509,7 @@ public class CrashesListFragment extends DevUiBaseFragment {
} }
} else { } else {
logCrashCollectionState(CollectionState.DISABLED_CANNOT_USE_GMS); logCrashCollectionState(CollectionState.DISABLED_CANNOT_USE_GMS);
errorView.setText("Crash collection is not supported at the moment."); errorView.setText(NO_GMS_ERROR_MESSAGE);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment