diff options
| -rw-r--r-- | core/tests/bugreports/Android.bp | 6 | ||||
| -rw-r--r-- | core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java | 128 |
2 files changed, 119 insertions, 15 deletions
diff --git a/core/tests/bugreports/Android.bp b/core/tests/bugreports/Android.bp index 1edd9623ed2d..e42b4b4ae2bf 100644 --- a/core/tests/bugreports/Android.bp +++ b/core/tests/bugreports/Android.bp @@ -20,7 +20,11 @@ android_test { "android.test.runner", "android.test.base", ], - static_libs: ["androidx.test.rules", "truth-prebuilt"], + static_libs: [ + "androidx.test.rules", + "androidx.test.uiautomator_uiautomator", + "truth-prebuilt", + ], test_suites: ["general-tests"], sdk_version: "test_current", platform_apis: true, diff --git a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java index 153337727e96..9246a2335050 100644 --- a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java +++ b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java @@ -18,6 +18,8 @@ package com.android.os.bugreports.tests; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.Manifest; @@ -25,17 +27,27 @@ import android.content.Context; import android.os.BugreportManager; import android.os.BugreportManager.BugreportCallback; import android.os.BugreportParams; +import android.os.FileUtils; import android.os.Handler; import android.os.HandlerThread; import android.os.ParcelFileDescriptor; +import android.os.StrictMode; import android.util.Log; +import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; +import androidx.test.filters.LargeTest; +import androidx.test.uiautomator.By; +import androidx.test.uiautomator.BySelector; +import androidx.test.uiautomator.UiDevice; +import androidx.test.uiautomator.UiObject2; +import androidx.test.uiautomator.Until; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExternalResource; import org.junit.rules.TestName; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -51,9 +63,11 @@ import java.util.concurrent.TimeUnit; @RunWith(JUnit4.class) public class BugreportManagerTest { @Rule public TestName name = new TestName(); + @Rule public ExtendedStrictModeVmPolicy mTemporaryVmPolicy = new ExtendedStrictModeVmPolicy(); private static final String TAG = "BugreportManagerTest"; private static final long BUGREPORT_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(10); + private static final long UIAUTOMATOR_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10); private Handler mHandler; private Executor mExecutor; @@ -86,6 +100,8 @@ public class BugreportManagerTest { @After public void teardown() throws Exception { dropPermissions(); + FileUtils.closeQuietly(mBugreportFd); + FileUtils.closeQuietly(mScreenshotFd); } @@ -95,47 +111,45 @@ public class BugreportManagerTest { // wifi bugreport does not take screenshot mBrm.startBugreport(mBugreportFd, null /*screenshotFd = null*/, wifi(), mExecutor, callback); + shareConsentDialog(ConsentReply.ALLOW); waitTillDoneOrTimeout(callback); assertThat(callback.isDone()).isTrue(); // Wifi bugreports should not receive any progress. assertThat(callback.hasReceivedProgress()).isFalse(); - // TODO: Because of b/130234145, consent dialog is not shown; so we get a timeout error. - // When the bug is fixed, accept consent via UIAutomator and verify contents - // of mBugreportFd. - assertThat(callback.getErrorCode()).isEqualTo( - BugreportCallback.BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT); + assertThat(mBugreportFile.length()).isGreaterThan(0L); assertFdsAreClosed(mBugreportFd); } + @LargeTest @Test public void normalFlow_interactive() throws Exception { BugreportCallbackImpl callback = new BugreportCallbackImpl(); // interactive bugreport does not take screenshot mBrm.startBugreport(mBugreportFd, null /*screenshotFd = null*/, interactive(), mExecutor, callback); - + shareConsentDialog(ConsentReply.ALLOW); waitTillDoneOrTimeout(callback); + assertThat(callback.isDone()).isTrue(); // Interactive bugreports show progress updates. assertThat(callback.hasReceivedProgress()).isTrue(); - assertThat(callback.getErrorCode()).isEqualTo( - BugreportCallback.BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT); + assertThat(mBugreportFile.length()).isGreaterThan(0L); assertFdsAreClosed(mBugreportFd); } + @LargeTest @Test public void normalFlow_full() throws Exception { BugreportCallbackImpl callback = new BugreportCallbackImpl(); mBrm.startBugreport(mBugreportFd, mScreenshotFd, full(), mExecutor, callback); - + shareConsentDialog(ConsentReply.ALLOW); waitTillDoneOrTimeout(callback); + assertThat(callback.isDone()).isTrue(); - assertThat(callback.getErrorCode()).isEqualTo( - BugreportCallback.BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT); - // bugreport and screenshot files should be empty when user consent timed out. - assertThat(mBugreportFile.length()).isEqualTo(0); - assertThat(mScreenshotFile.length()).isEqualTo(0); + // bugreport and screenshot files shouldn't be empty when user consents. + assertThat(mBugreportFile.length()).isGreaterThan(0L); + assertThat(mScreenshotFile.length()).isGreaterThan(0L); assertFdsAreClosed(mBugreportFd, mScreenshotFd); } @@ -144,6 +158,8 @@ public class BugreportManagerTest { // Start bugreport #1 BugreportCallbackImpl callback = new BugreportCallbackImpl(); mBrm.startBugreport(mBugreportFd, mScreenshotFd, wifi(), mExecutor, callback); + // TODO(b/162389762) Make sure the wait time is reasonable + shareConsentDialog(ConsentReply.ALLOW); // Before #1 is done, try to start #2. assertThat(callback.isDone()).isFalse(); @@ -375,4 +391,88 @@ public class BugreportManagerTest { private static BugreportParams full() { return new BugreportParams(BugreportParams.BUGREPORT_MODE_FULL); } + + /* Allow/deny the consent dialog to sharing bugreport data or check existence only. */ + private enum ConsentReply { + ALLOW, + DENY, + TIMEOUT + } + + /* + * Ensure the consent dialog is shown and take action according to <code>consentReply<code/>. + * It will fail if the dialog is not shown when <code>ignoreNotFound<code/> is false. + */ + private void shareConsentDialog(@NonNull ConsentReply consentReply) throws Exception { + mTemporaryVmPolicy.permitIncorrectContextUse(); + final UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + + // Unlock before finding/clicking an object. + device.wakeUp(); + device.executeShellCommand("wm dismiss-keyguard"); + + final BySelector consentTitleObj = By.res("android", "alertTitle"); + if (!device.wait(Until.hasObject(consentTitleObj), UIAUTOMATOR_TIMEOUT_MS)) { + fail("The consent dialog is not found"); + } + if (consentReply.equals(ConsentReply.TIMEOUT)) { + return; + } + final BySelector selector; + if (consentReply.equals(ConsentReply.ALLOW)) { + selector = By.res("android", "button1"); + Log.d(TAG, "Allow the consent dialog"); + } else { // ConsentReply.DENY + selector = By.res("android", "button2"); + Log.d(TAG, "Deny the consent dialog"); + } + final UiObject2 btnObj = device.findObject(selector); + assertNotNull("The button of consent dialog is not found", btnObj); + btnObj.click(); + + Log.d(TAG, "Wait for the dialog to be dismissed"); + assertTrue(device.wait(Until.gone(consentTitleObj), UIAUTOMATOR_TIMEOUT_MS)); + } + + /** + * A rule to change strict mode vm policy temporarily till test method finished. + * + * To permit the non-visual context usage in tests while taking bugreports need user consent, + * or UiAutomator/BugreportManager.DumpstateListener would run into error. + * UiDevice#findObject creates UiObject2, its Gesture object and ViewConfiguration and + * UiObject2#click need to know bounds. Both of them access to WindowManager internally without + * visual context comes from InstrumentationRegistry and violate the policy. + * Also <code>DumpstateListener<code/> violate the policy when onScreenshotTaken is called. + * + * TODO(b/161201609) Remove this class once violations fixed. + */ + static class ExtendedStrictModeVmPolicy extends ExternalResource { + private boolean mWasVmPolicyChanged = false; + private StrictMode.VmPolicy mOldVmPolicy; + + @Override + protected void after() { + restoreVmPolicyIfNeeded(); + } + + public void permitIncorrectContextUse() { + // Allow to call multiple times without losing old policy. + if (mOldVmPolicy == null) { + mOldVmPolicy = StrictMode.getVmPolicy(); + } + StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() + .detectAll() + .permitIncorrectContextUse() + .penaltyLog() + .build()); + mWasVmPolicyChanged = true; + } + + private void restoreVmPolicyIfNeeded() { + if (mWasVmPolicyChanged && mOldVmPolicy != null) { + StrictMode.setVmPolicy(mOldVmPolicy); + mOldVmPolicy = null; + } + } + } } |