Fix timing issue for flaky tests

Inject SystemClock so that we can mock it in tests and ensure the clock
will always advance. Also switched to using elapsedRealtime, which is
guaranteed to be monotonic

Fixes: 182813365
Test: atest MediaDataManagerTest
Change-Id: I133fb48e8242dc7f8e75bfa5c585c8b6142963aa
This commit is contained in:
Beth Thibodeau
2021-04-26 14:01:16 -04:00
parent 4a225373ec
commit ced62779fb
4 changed files with 38 additions and 24 deletions

View File

@@ -25,6 +25,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.settings.CurrentUserTracker
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.util.time.SystemClock
import java.util.concurrent.Executor
import java.util.concurrent.TimeUnit
import javax.inject.Inject
@@ -36,7 +37,8 @@ private const val DEBUG = true
* Maximum age of a media control to re-activate on smartspace signal. If there is no media control
* available within this time window, smartspace recommendations will be shown instead.
*/
private val SMARTSPACE_MAX_AGE = SystemProperties
@VisibleForTesting
internal val SMARTSPACE_MAX_AGE = SystemProperties
.getLong("debug.sysui.smartspace_max_age", TimeUnit.HOURS.toMillis(3))
/**
@@ -51,7 +53,8 @@ class MediaDataFilter @Inject constructor(
private val broadcastDispatcher: BroadcastDispatcher,
private val mediaResumeListener: MediaResumeListener,
private val lockscreenUserManager: NotificationLockscreenUserManager,
@Main private val executor: Executor
@Main private val executor: Executor,
private val systemClock: SystemClock
) : MediaDataManager.Listener {
private val userTracker: CurrentUserTracker
private val _listeners: MutableSet<MediaDataManager.Listener> = mutableSetOf()
@@ -100,7 +103,7 @@ class MediaDataFilter @Inject constructor(
hasSmartspace = true
// Before forwarding the smartspace target, first check if we have recently inactive media
val now = System.currentTimeMillis()
val now = systemClock.elapsedRealtime()
val sorted = userEntries.toSortedMap(compareBy {
userEntries.get(it)?.lastActive ?: -1
})

View File

@@ -56,6 +56,7 @@ import com.android.systemui.statusbar.notification.row.HybridGroupManager
import com.android.systemui.util.Assert
import com.android.systemui.util.Utils
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.time.SystemClock
import java.io.FileDescriptor
import java.io.IOException
import java.io.PrintWriter
@@ -108,7 +109,8 @@ class MediaDataManager(
private val activityStarter: ActivityStarter,
private val smartspaceMediaDataProvider: SmartspaceMediaDataProvider,
private var useMediaResumption: Boolean,
private val useQsMediaPlayer: Boolean
private val useQsMediaPlayer: Boolean,
private val systemClock: SystemClock
) : Dumpable, BcSmartspaceDataPlugin.SmartspaceTargetListener {
companion object {
@@ -164,12 +166,13 @@ class MediaDataManager(
mediaDataCombineLatest: MediaDataCombineLatest,
mediaDataFilter: MediaDataFilter,
activityStarter: ActivityStarter,
smartspaceMediaDataProvider: SmartspaceMediaDataProvider
smartspaceMediaDataProvider: SmartspaceMediaDataProvider,
clock: SystemClock
) : this(context, backgroundExecutor, foregroundExecutor, mediaControllerFactory,
broadcastDispatcher, dumpManager, mediaTimeoutListener, mediaResumeListener,
mediaSessionBasedFilter, mediaDeviceManager, mediaDataCombineLatest, mediaDataFilter,
activityStarter, smartspaceMediaDataProvider, Utils.useMediaResumption(context),
Utils.useQsMediaPlayer(context))
Utils.useQsMediaPlayer(context), clock)
private val appChangeReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
@@ -474,7 +477,7 @@ class MediaDataManager(
}
val mediaAction = getResumeMediaAction(resumeAction)
val lastActive = System.currentTimeMillis()
val lastActive = systemClock.elapsedRealtime()
foregroundExecutor.execute {
onMediaDataLoaded(packageName, null, MediaData(userId, true, bgColor, appName,
null, desc.subtitle, desc.title, artworkIcon, listOf(mediaAction), listOf(0),
@@ -597,7 +600,7 @@ class MediaDataManager(
val isLocalSession = mediaController.playbackInfo?.playbackType ==
MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL
val isPlaying = mediaController.playbackState?.let { isPlayingState(it.state) } ?: null
val lastActive = System.currentTimeMillis()
val lastActive = systemClock.elapsedRealtime()
foregroundExecutor.execute {
val resumeAction: Runnable? = mediaEntries[key]?.resumeAction
val hasCheckedForResume = mediaEntries[key]?.hasCheckedForResume == true

View File

@@ -25,6 +25,7 @@ import android.testing.TestableLooper
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@@ -80,12 +81,13 @@ class MediaDataFilterTest : SysuiTestCase() {
private lateinit var dataMain: MediaData
private lateinit var dataGuest: MediaData
private val device = MediaDeviceData(true, null, DEVICE_NAME)
private val clock = FakeSystemClock()
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
mediaDataFilter = MediaDataFilter(broadcastDispatcher, mediaResumeListener,
lockscreenUserManager, executor)
lockscreenUserManager, executor, clock)
mediaDataFilter.mediaDataManager = mediaDataManager
mediaDataFilter.addListener(listener)
@@ -246,8 +248,9 @@ class MediaDataFilterTest : SysuiTestCase() {
@Test
fun testOnSmartspaceMediaDataLoaded_noRecentMedia_nonEmptyRecommendation_usesSmartspace() {
val dataOld = dataMain.copy(active = false, lastActive = 0L)
val dataOld = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
mediaDataFilter.onMediaDataLoaded(KEY, null, dataOld)
clock.advanceTime(SMARTSPACE_MAX_AGE + 100)
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
verify(listener).onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData))
@@ -258,8 +261,9 @@ class MediaDataFilterTest : SysuiTestCase() {
fun testOnSmartspaceMediaDataLoaded_noRecentMedia_emptyRecommendation_showsNothing() {
`when`(smartspaceData.iconGrid).thenReturn(listOf())
val dataOld = dataMain.copy(active = false, lastActive = 0L)
val dataOld = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
mediaDataFilter.onMediaDataLoaded(KEY, null, dataOld)
clock.advanceTime(SMARTSPACE_MAX_AGE + 100)
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
verify(listener, never())
@@ -270,7 +274,7 @@ class MediaDataFilterTest : SysuiTestCase() {
@Test
fun testOnSmartspaceMediaDataLoaded_hasRecentMedia_usesMedia() {
// WHEN we have media that was recently played, but not currently active
val dataCurrent = dataMain.copy(active = false, lastActive = System.currentTimeMillis())
val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent))
@@ -294,7 +298,7 @@ class MediaDataFilterTest : SysuiTestCase() {
@Test
fun testOnSmartspaceMediaDataRemoved_usedMedia_clearsMedia() {
val dataCurrent = dataMain.copy(active = false, lastActive = System.currentTimeMillis())
val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)

View File

@@ -81,11 +81,12 @@ class MediaDataManagerTest : SysuiTestCase() {
lateinit var mediaDataManager: MediaDataManager
lateinit var mediaNotification: StatusBarNotification
@Captor lateinit var mediaDataCaptor: ArgumentCaptor<MediaData>
private val clock = FakeSystemClock()
@Before
fun setup() {
foregroundExecutor = FakeExecutor(FakeSystemClock())
backgroundExecutor = FakeExecutor(FakeSystemClock())
foregroundExecutor = FakeExecutor(clock)
backgroundExecutor = FakeExecutor(clock)
smartspaceMediaDataProvider = SmartspaceMediaDataProvider()
mediaDataManager = MediaDataManager(
context = context,
@@ -103,7 +104,8 @@ class MediaDataManagerTest : SysuiTestCase() {
activityStarter = activityStarter,
smartspaceMediaDataProvider = smartspaceMediaDataProvider,
useMediaResumption = true,
useQsMediaPlayer = true
useQsMediaPlayer = true,
systemClock = clock
)
session = MediaSession(context, "MediaDataManagerTestSession")
mediaNotification = SbnBuilder().run {
@@ -310,7 +312,7 @@ class MediaDataManagerTest : SysuiTestCase() {
setTitle(SESSION_TITLE)
build()
}
val currentTimeMillis = System.currentTimeMillis()
val currentTime = clock.elapsedRealtime()
mediaDataManager.addResumptionControls(USER_ID, desc, Runnable {}, session.sessionToken,
APP_NAME, pendingIntent, PACKAGE_NAME)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
@@ -322,7 +324,7 @@ class MediaDataManagerTest : SysuiTestCase() {
assertThat(data.song).isEqualTo(SESSION_TITLE)
assertThat(data.app).isEqualTo(APP_NAME)
assertThat(data.actions).hasSize(1)
assertThat(data.lastActive).isAtLeast(currentTimeMillis)
assertThat(data.lastActive).isAtLeast(currentTime)
}
@Test
@@ -380,12 +382,12 @@ class MediaDataManagerTest : SysuiTestCase() {
@Test
fun testOnMediaDataChanged_updatesLastActiveTime() {
val currentTimeMillis = System.currentTimeMillis()
val currentTime = clock.elapsedRealtime()
mediaDataManager.onNotificationAdded(KEY, mediaNotification)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor))
assertThat(mediaDataCaptor.value!!.lastActive).isAtLeast(currentTimeMillis)
assertThat(mediaDataCaptor.value!!.lastActive).isAtLeast(currentTime)
}
@Test
@@ -396,12 +398,13 @@ class MediaDataManagerTest : SysuiTestCase() {
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
// WHEN the notification times out
val currentTimeMillis = System.currentTimeMillis()
clock.advanceTime(100)
val currentTime = clock.elapsedRealtime()
mediaDataManager.setTimedOut(KEY, true, true)
// THEN the last active time is not changed
verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), capture(mediaDataCaptor))
assertThat(mediaDataCaptor.value.lastActive).isLessThan(currentTimeMillis)
assertThat(mediaDataCaptor.value.lastActive).isLessThan(currentTime)
}
@Test
@@ -417,13 +420,14 @@ class MediaDataManagerTest : SysuiTestCase() {
mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
// WHEN the notification is removed
val currentTimeMillis = System.currentTimeMillis()
clock.advanceTime(100)
val currentTime = clock.elapsedRealtime()
mediaDataManager.onNotificationRemoved(KEY)
// THEN the last active time is not changed
verify(listener).onMediaDataLoaded(eq(PACKAGE_NAME), eq(KEY), capture(mediaDataCaptor))
assertThat(mediaDataCaptor.value.resumption).isTrue()
assertThat(mediaDataCaptor.value.lastActive).isLessThan(currentTimeMillis)
assertThat(mediaDataCaptor.value.lastActive).isLessThan(currentTime)
}
@Test