Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ced62779 authored by Beth Thibodeau's avatar Beth Thibodeau
Browse files

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
parent 4a225373
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -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
        })
+8 −5
Original line number Diff line number Diff line
@@ -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
+9 −5
Original line number Diff line number Diff line
@@ -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)

+15 −11
Original line number Diff line number Diff line
@@ -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