diff options
Diffstat (limited to 'tests')
7 files changed, 95 insertions, 67 deletions
diff --git a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt index 6cd24f800..298d7643c 100644 --- a/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt +++ b/tests/cts/safetycenter/src/android/safetycenter/cts/SafetyCenterManagerTest.kt @@ -1111,11 +1111,11 @@ class SafetyCenterManagerTest { ) // Because wrong ID, refresh hasn't finished. Wait for timeout. - listener.receiveSafetyCenterErrorDetails() + listener.waitForSafetyCenterRefresh(withErrorEntry = true) SafetyCenterFlags.setAllRefreshTimeoutsTo(TIMEOUT_LONG) SafetySourceReceiver.setResponse( - Request.Rescan(SINGLE_SOURCE_ID), + Request.Refresh(SINGLE_SOURCE_ID), Response.SetData(safetySourceTestData.information) ) safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( @@ -1185,7 +1185,7 @@ class SafetyCenterManagerTest { safetyCenterManager.getSafetySourceDataWithPermission(SINGLE_SOURCE_ID) assertThat(apiSafetySourceData1).isNull() // Wait for the ongoing refresh to timeout. - listener.receiveSafetyCenterErrorDetails() + listener.waitForSafetyCenterRefresh(withErrorEntry = true) SafetyCenterFlags.setAllRefreshTimeoutsTo(TIMEOUT_LONG) SafetySourceReceiver.setResponse( Request.Refresh(SINGLE_SOURCE_ID), @@ -1237,18 +1237,11 @@ class SafetyCenterManagerTest { REFRESH_REASON_RESCAN_BUTTON_CLICK ) - val safetyCenterErrorDetailsFromListener = listener.receiveSafetyCenterErrorDetails() - assertThat(safetyCenterErrorDetailsFromListener) - .isEqualTo( - SafetyCenterErrorDetails( - safetyCenterResourcesApk.getStringByName("refresh_timeout") - ) - ) + listener.waitForSafetyCenterRefresh(withErrorEntry = true) } @Test fun refreshSafetySources_withUntrackedSourceThatTimesOut_doesNotTimeOut() { - SafetyCenterFlags.setAllRefreshTimeoutsTo(TIMEOUT_SHORT) SafetyCenterFlags.untrackedSources = setOf(SOURCE_ID_1) safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig) // SOURCE_ID_1 will timeout @@ -1264,14 +1257,11 @@ class SafetyCenterManagerTest { REFRESH_REASON_RESCAN_BUTTON_CLICK ) - assertFailsWith(TimeoutCancellationException::class) { - listener.receiveSafetyCenterErrorDetails(TIMEOUT_SHORT) - } + listener.waitForSafetyCenterRefresh(withErrorEntry = false) } @Test fun refreshSafetySources_withMultipleUntrackedSourcesThatTimeOut_doesNotTimeOut() { - SafetyCenterFlags.setAllRefreshTimeoutsTo(TIMEOUT_SHORT) SafetyCenterFlags.untrackedSources = setOf(SOURCE_ID_1, SOURCE_ID_2) safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.multipleSourcesConfig) // SOURCE_ID_1 and SOURCE_ID_2 will timeout @@ -1285,9 +1275,7 @@ class SafetyCenterManagerTest { REFRESH_REASON_RESCAN_BUTTON_CLICK ) - assertFailsWith(TimeoutCancellationException::class) { - listener.receiveSafetyCenterErrorDetails(TIMEOUT_SHORT) - } + listener.waitForSafetyCenterRefresh(withErrorEntry = false) } @Test @@ -1301,25 +1289,20 @@ class SafetyCenterManagerTest { REFRESH_REASON_RESCAN_BUTTON_CLICK ) - val safetyCenterErrorDetailsFromListener = listener.receiveSafetyCenterErrorDetails() - assertThat(safetyCenterErrorDetailsFromListener) - .isEqualTo( - SafetyCenterErrorDetails( - safetyCenterResourcesApk.getStringByName("refresh_timeout") - ) - ) + listener.waitForSafetyCenterRefresh(withErrorEntry = true) } @Test fun refreshSafetySources_withTrackedSourceThatHasNoReceiver_doesNotTimeOut() { - SafetyCenterFlags.setAllRefreshTimeoutsTo(TIMEOUT_SHORT) safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceOtherPackageConfig) val listener = safetyCenterTestHelper.addListener() safetyCenterManager.refreshSafetySourcesWithPermission(REFRESH_REASON_RESCAN_BUTTON_CLICK) assertFailsWith(TimeoutCancellationException::class) { - listener.receiveSafetyCenterErrorDetails(TIMEOUT_SHORT) + // In this case a refresh isn't even started because there is only a single source + // without a receiver. + listener.receiveSafetyCenterData(TIMEOUT_SHORT) } } diff --git a/tests/functional/safetycenter/multiusers/src/android/safetycenter/functional/multiusers/SafetyCenterMultiUsersTest.kt b/tests/functional/safetycenter/multiusers/src/android/safetycenter/functional/multiusers/SafetyCenterMultiUsersTest.kt index de7a18c0e..9534b597a 100644 --- a/tests/functional/safetycenter/multiusers/src/android/safetycenter/functional/multiusers/SafetyCenterMultiUsersTest.kt +++ b/tests/functional/safetycenter/multiusers/src/android/safetycenter/functional/multiusers/SafetyCenterMultiUsersTest.kt @@ -35,8 +35,6 @@ import android.safetycenter.SafetyCenterIssue import android.safetycenter.SafetyCenterManager import android.safetycenter.SafetyCenterStaticEntry import android.safetycenter.SafetyCenterStaticEntryGroup -import android.safetycenter.SafetyCenterStatus.REFRESH_STATUS_DATA_FETCH_IN_PROGRESS -import android.safetycenter.SafetyCenterStatus.REFRESH_STATUS_NONE import android.safetycenter.SafetyEvent import android.safetycenter.SafetySourceData import androidx.test.core.app.ApplicationProvider @@ -1279,10 +1277,7 @@ class SafetyCenterMultiUsersTest { private fun disableQuietModeAndWaitForRefreshToComplete() { val listener = safetyCenterTestHelper.addListener() deviceState.workProfile().setQuietMode(false) - listener.receiveSafetyCenterData { - it.status.refreshStatus == REFRESH_STATUS_DATA_FETCH_IN_PROGRESS - } - listener.receiveSafetyCenterData { it.status.refreshStatus == REFRESH_STATUS_NONE } + listener.waitForSafetyCenterRefresh() } private fun safetyCenterEntryOkForWork(sourceId: String, managedUserId: Int) = diff --git a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterManagerTest.kt b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterManagerTest.kt index 0c952ede2..e2a7802b3 100644 --- a/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterManagerTest.kt +++ b/tests/functional/safetycenter/singleuser/src/android/safetycenter/functional/SafetyCenterManagerTest.kt @@ -766,9 +766,8 @@ class SafetyCenterManagerTest { @get:Rule(order = 2) val safetyCenterTestRule = SafetyCenterTestRule(safetyCenterTestHelper) @Test - fun refreshSafetySources_withShowEntriesOnTimeout_marksSafetySourceAsError() { + fun refreshSafetySources_timeout_marksSafetySourceAsError() { SafetyCenterFlags.setAllRefreshTimeoutsTo(TIMEOUT_SHORT) - SafetyCenterFlags.showErrorEntriesOnTimeout = true safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) val listener = safetyCenterTestHelper.addListener() @@ -786,9 +785,8 @@ class SafetyCenterManagerTest { } @Test - fun refreshSafetySources_withShowEntriesOnTimeout_keepsShowingErrorUntilClearedBySource() { + fun refreshSafetySources_timeout_keepsShowingErrorUntilClearedBySource() { SafetyCenterFlags.setAllRefreshTimeoutsTo(TIMEOUT_SHORT) - SafetyCenterFlags.showErrorEntriesOnTimeout = true safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) val listener = safetyCenterTestHelper.addListener() safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait( @@ -816,18 +814,15 @@ class SafetyCenterManagerTest { } @Test - fun refreshSafetySources_withShowEntriesOnTimeout_doesntSetErrorForBackgroundRefreshes() { + fun refreshSafetySources_timeout_doesntSetErrorForBackgroundRefreshes() { SafetyCenterFlags.setAllRefreshTimeoutsTo(TIMEOUT_SHORT) - SafetyCenterFlags.showErrorEntriesOnTimeout = true safetyCenterTestHelper.setConfig(safetyCenterTestConfigs.singleSourceConfig) val listener = safetyCenterTestHelper.addListener() safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(REFRESH_REASON_OTHER) - val safetyCenterBeforeTimeout = listener.receiveSafetyCenterData() - assertThat(safetyCenterBeforeTimeout.status.refreshStatus) - .isEqualTo(REFRESH_STATUS_DATA_FETCH_IN_PROGRESS) - val safetyCenterDataAfterTimeout = listener.receiveSafetyCenterData() + val safetyCenterDataAfterTimeout = + listener.waitForSafetyCenterRefresh(withErrorEntry = false) assertThat(safetyCenterDataAfterTimeout).isEqualTo(safetyCenterDataFromConfig) } diff --git a/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetySourceStateCollectedLoggingHelperTests.kt b/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetySourceStateCollectedLoggingHelperTests.kt index 9e3a33018..d020aac0a 100644 --- a/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetySourceStateCollectedLoggingHelperTests.kt +++ b/tests/hostside/safetycenter/helper-app/src/android/safetycenter/hostside/device/SafetySourceStateCollectedLoggingHelperTests.kt @@ -18,9 +18,6 @@ package android.safetycenter.hostside.device import android.content.Context import android.safetycenter.SafetyCenterManager -import android.safetycenter.SafetyCenterStatus -import android.safetycenter.SafetyCenterStatus.REFRESH_STATUS_DATA_FETCH_IN_PROGRESS -import android.safetycenter.SafetyCenterStatus.REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS import android.safetycenter.SafetyEvent import android.safetycenter.SafetySourceErrorDetails import androidx.test.core.app.ApplicationProvider @@ -168,12 +165,6 @@ class SafetySourceStateCollectedLoggingHelperTests { // things are logged. val listener = safetyCenterTestHelper.addListener() safetyCenterManager.refreshSafetySourcesWithReceiverPermissionAndWait(refreshReason) - listener.receiveSafetyCenterData { - it.status.refreshStatus == REFRESH_STATUS_DATA_FETCH_IN_PROGRESS || - it.status.refreshStatus == REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS - } - listener.receiveSafetyCenterData { - it.status.refreshStatus == SafetyCenterStatus.REFRESH_STATUS_NONE - } + listener.waitForSafetyCenterRefresh() } } diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/Coroutines.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/Coroutines.kt index 6c6336da3..a7009b19e 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/Coroutines.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/Coroutines.kt @@ -30,7 +30,11 @@ import kotlinx.coroutines.withTimeoutOrNull /** A class that facilitates interacting with coroutines. */ object Coroutines { - private val TEST_TIMEOUT: Duration + /** + * The timeout of a test case, typically varies depending on whether the test is running + * locally, on pre-submit or post-submit. + */ + val TEST_TIMEOUT: Duration get() = Duration.ofMillis( InstrumentationRegistry.getArguments().getString("timeout_msec", "60000").toLong() diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterFlags.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterFlags.kt index 28b621d5c..5cc2e3c8e 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterFlags.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterFlags.kt @@ -34,6 +34,7 @@ import android.safetycenter.SafetyCenterManager.REFRESH_REASON_RESCAN_BUTTON_CLI import android.safetycenter.SafetyCenterManager.REFRESH_REASON_SAFETY_CENTER_ENABLED import android.safetycenter.SafetySourceData import com.android.modules.utils.build.SdkLevel +import com.android.safetycenter.testing.Coroutines.TEST_TIMEOUT import com.android.safetycenter.testing.Coroutines.TIMEOUT_LONG import com.android.safetycenter.testing.ShellPermissions.callWithShellPermissionIdentity import java.time.Duration @@ -100,13 +101,6 @@ object SafetyCenterFlags { DurationParser() ) - /** - * Flag that determines whether we should show error entries for sources that timeout when - * refreshing them. - */ - private val showErrorEntriesOnTimeoutFlag = - Flag("safety_center_show_error_entries_on_timeout", defaultValue = false, BooleanParser()) - /** Flag that determines whether we should replace the IconAction of the lock screen source. */ private val replaceLockScreenIconActionFlag = Flag("safety_center_replace_lock_screen_icon_action", defaultValue = true, BooleanParser()) @@ -115,11 +109,16 @@ object SafetyCenterFlags { * Flag that determines the time for which a Safety Center refresh is allowed to wait for a * source to respond to a refresh request before timing out and marking the refresh as finished, * depending on the refresh reason. + * + * Unlike the production code, this flag is set to [TEST_TIMEOUT] for all refresh reasons by + * default for convenience. UI tests typically will set some data manually rather than going + * through a full refresh, and we don't want to timeout the refresh and potentially end up with + * error entries in this case (as it could lead to flakyness). */ private val refreshSourceTimeoutsFlag = Flag( "safety_center_refresh_sources_timeouts_millis", - defaultValue = getAllRefreshTimeoutsMap(TIMEOUT_LONG), + defaultValue = getAllRefreshTimeoutsMap(TEST_TIMEOUT), MapParser(IntParser(), DurationParser()) ) @@ -302,7 +301,6 @@ object SafetyCenterFlags { notificationsMinDelayFlag, immediateNotificationBehaviorIssuesFlag, notificationResurfaceIntervalFlag, - showErrorEntriesOnTimeoutFlag, replaceLockScreenIconActionFlag, refreshSourceTimeoutsFlag, resolveActionTimeoutFlag, @@ -341,14 +339,11 @@ object SafetyCenterFlags { /** A property that allows getting and setting the [notificationResurfaceIntervalFlag]. */ var notificationResurfaceInterval: Duration by notificationResurfaceIntervalFlag - /** A property that allows getting and setting the [showErrorEntriesOnTimeoutFlag]. */ - var showErrorEntriesOnTimeout: Boolean by showErrorEntriesOnTimeoutFlag - /** A property that allows getting and setting the [replaceLockScreenIconActionFlag]. */ var replaceLockScreenIconAction: Boolean by replaceLockScreenIconActionFlag /** A property that allows getting and setting the [refreshSourceTimeoutsFlag]. */ - var refreshTimeouts: Map<Int, Duration> by refreshSourceTimeoutsFlag + private var refreshTimeouts: Map<Int, Duration> by refreshSourceTimeoutsFlag /** A property that allows getting and setting the [resolveActionTimeoutFlag]. */ var resolveActionTimeout: Duration by resolveActionTimeoutFlag diff --git a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestListener.kt b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestListener.kt index 624c32d5f..8ce5c25d4 100644 --- a/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestListener.kt +++ b/tests/utils/safetycenter/java/com/android/safetycenter/testing/SafetyCenterTestListener.kt @@ -18,9 +18,14 @@ package com.android.safetycenter.testing import android.os.Build.VERSION_CODES.TIRAMISU import android.safetycenter.SafetyCenterData +import android.safetycenter.SafetyCenterEntry import android.safetycenter.SafetyCenterErrorDetails import android.safetycenter.SafetyCenterManager.OnSafetyCenterDataChangedListener +import android.safetycenter.SafetyCenterStaticEntry +import android.safetycenter.SafetyCenterStatus +import android.text.TextUtils import androidx.annotation.RequiresApi +import androidx.test.core.app.ApplicationProvider.getApplicationContext import com.android.safetycenter.testing.Coroutines.TIMEOUT_LONG import com.android.safetycenter.testing.Coroutines.runBlockingWithTimeout import java.time.Duration @@ -64,6 +69,47 @@ class SafetyCenterTestListener : OnSafetyCenterDataChangedListener { } /** + * Waits for a full Safety Center refresh to complete, where each change to the underlying + * [SafetyCenterData] must happen within the given [timeout]. + * + * @param withErrorEntry optionally check whether we should expect the [SafetyCenterData] to + * have or not have at least one an error entry after the refresh completes + * @return the [SafetyCenterData] after the refresh completes + */ + fun waitForSafetyCenterRefresh( + timeout: Duration = TIMEOUT_LONG, + withErrorEntry: Boolean? = null + ): SafetyCenterData { + receiveSafetyCenterData(timeout) { + it.status.refreshStatus == SafetyCenterStatus.REFRESH_STATUS_DATA_FETCH_IN_PROGRESS || + it.status.refreshStatus == SafetyCenterStatus.REFRESH_STATUS_FULL_RESCAN_IN_PROGRESS + } + val afterRefresh = + receiveSafetyCenterData(timeout) { + it.status.refreshStatus == SafetyCenterStatus.REFRESH_STATUS_NONE + } + if (withErrorEntry == null) { + return afterRefresh + } + val errorMessage = + SafetyCenterTestData(getApplicationContext()) + .getRefreshErrorString(numberOfErrorEntries = 1) + val containsErrorEntry = afterRefresh.containsAnyEntryWithSummary(errorMessage) + if (withErrorEntry && !containsErrorEntry) { + throw AssertionError( + "No error entry with message: \"$errorMessage\" found in SafetyCenterData" + + " after refresh: $afterRefresh" + ) + } else if (!withErrorEntry && containsErrorEntry) { + throw AssertionError( + "Found an error entry with message: \"$errorMessage\" in SafetyCenterData" + + " after refresh: $afterRefresh" + ) + } + return afterRefresh + } + + /** * Waits for a [SafetyCenterErrorDetails] update from SafetyCenter within the given [timeout]. */ fun receiveSafetyCenterErrorDetails(timeout: Duration = TIMEOUT_LONG) = @@ -74,4 +120,23 @@ class SafetyCenterTestListener : OnSafetyCenterDataChangedListener { dataChannel.cancel() errorChannel.cancel() } + + private companion object { + fun SafetyCenterData.containsAnyEntryWithSummary(summary: CharSequence): Boolean = + entries().any { TextUtils.equals(it.summary, summary) } || + staticEntries().any { TextUtils.equals(it.summary, summary) } + + fun SafetyCenterData.entries(): List<SafetyCenterEntry> = + entriesOrGroups.flatMap { + val entry = it.entry + if (entry != null) { + listOf(entry) + } else { + it.entryGroup!!.entries + } + } + + fun SafetyCenterData.staticEntries(): List<SafetyCenterStaticEntry> = + staticEntryGroups.flatMap { it.staticEntries } + } } |