From 7eae3a16aec9c70690404d18ef079827d7689980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Mart=C3=ADn?= Date: Fri, 5 Dec 2025 17:07:54 +0100 Subject: [PATCH] Use `SessionObserver` instead of `SessionStore` to observe sessions --- .../impl/DefaultWorkManagerScheduler.kt | 28 ++++++------------ .../impl/DefaultWorkManagerSchedulerTest.kt | 29 +++++-------------- 2 files changed, 16 insertions(+), 41 deletions(-) diff --git a/libraries/workmanager/impl/src/main/kotlin/io/element/android/libraries/workmanager/impl/DefaultWorkManagerScheduler.kt b/libraries/workmanager/impl/src/main/kotlin/io/element/android/libraries/workmanager/impl/DefaultWorkManagerScheduler.kt index c80735c675..345604390b 100644 --- a/libraries/workmanager/impl/src/main/kotlin/io/element/android/libraries/workmanager/impl/DefaultWorkManagerScheduler.kt +++ b/libraries/workmanager/impl/src/main/kotlin/io/element/android/libraries/workmanager/impl/DefaultWorkManagerScheduler.kt @@ -11,41 +11,31 @@ package io.element.android.libraries.workmanager.impl import androidx.work.WorkManager import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesBinding -import io.element.android.libraries.core.coroutine.withPreviousValue -import io.element.android.libraries.di.annotations.AppCoroutineScope import io.element.android.libraries.matrix.api.core.SessionId -import io.element.android.libraries.sessionstorage.api.SessionStore +import io.element.android.libraries.sessionstorage.api.observer.SessionListener +import io.element.android.libraries.sessionstorage.api.observer.SessionObserver import io.element.android.libraries.workmanager.api.WorkManagerRequest import io.element.android.libraries.workmanager.api.WorkManagerRequestType import io.element.android.libraries.workmanager.api.WorkManagerScheduler import io.element.android.libraries.workmanager.api.workManagerTag -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.onEach import timber.log.Timber @ContributesBinding(AppScope::class) class DefaultWorkManagerScheduler( lazyWorkManager: Lazy, - @AppCoroutineScope private val appCoroutineScope: CoroutineScope, - sessionStore: SessionStore, + sessionObserver: SessionObserver, ) : WorkManagerScheduler { private val workManager by lazyWorkManager init { // Observe session removals to cancel associated work automatically - sessionStore.sessionsFlow() - .map { sessions -> sessions.map { SessionId(it.userId) } } - .withPreviousValue() - .map { (prev, new) -> prev.orEmpty() - new.toSet() } - .onEach { removedSessions -> - for (sessionId in removedSessions) { - Timber.d("Session removed for userId: $sessionId, cancelling associated workmanager requests") - cancel(sessionId) - } + sessionObserver.addListener(object : SessionListener { + override suspend fun onSessionDeleted(userId: String, wasLastSession: Boolean) { + val sessionId = SessionId(userId) + Timber.d("Session deleted for userId: $userId, cancelling associated workmanager requests") + cancel(sessionId) } - .launchIn(appCoroutineScope) + }) } override fun submit(workManagerRequest: WorkManagerRequest) { diff --git a/libraries/workmanager/impl/src/test/kotlin/io/element/android/libraries/workmanager/impl/DefaultWorkManagerSchedulerTest.kt b/libraries/workmanager/impl/src/test/kotlin/io/element/android/libraries/workmanager/impl/DefaultWorkManagerSchedulerTest.kt index 5ecf0c4a1f..b4f964ed12 100644 --- a/libraries/workmanager/impl/src/test/kotlin/io/element/android/libraries/workmanager/impl/DefaultWorkManagerSchedulerTest.kt +++ b/libraries/workmanager/impl/src/test/kotlin/io/element/android/libraries/workmanager/impl/DefaultWorkManagerSchedulerTest.kt @@ -9,10 +9,8 @@ package io.element.android.libraries.workmanager.impl import androidx.work.WorkManager import androidx.work.WorkRequest -import com.google.common.truth.Truth.assertThat import io.element.android.libraries.matrix.api.core.SessionId -import io.element.android.libraries.sessionstorage.test.InMemorySessionStore -import io.element.android.libraries.sessionstorage.test.aSessionData +import io.element.android.libraries.sessionstorage.test.observer.FakeSessionObserver import io.element.android.libraries.workmanager.api.WorkManagerRequest import io.element.android.libraries.workmanager.api.WorkManagerRequestType import io.element.android.libraries.workmanager.api.workManagerTag @@ -30,40 +28,31 @@ class DefaultWorkManagerSchedulerTest { @Test fun `starts observing sessions on init to remove work for logged out sessions`() = runTest { val sessionId = "@session1:matrix.org" - val sessionStore = InMemorySessionStore(initialList = listOf(aSessionData(sessionId = sessionId))) + val sessionObserver = FakeSessionObserver() val workManager = spyk() DefaultWorkManagerScheduler( lazyWorkManager = lazy { workManager }, - appCoroutineScope = backgroundScope, - sessionStore = sessionStore, + sessionObserver = sessionObserver, ) - // We have a single initial session - assertThat(sessionStore.numberOfSessions()).isEqualTo(1) - - runCurrent() - // We remove the session - sessionStore.removeSession(sessionId) + sessionObserver.onSessionDeleted(sessionId) runCurrent() // The session is now gone and work associated with the session is cancelled - assertThat(sessionStore.numberOfSessions()).isEqualTo(0) verify { workManager.cancelAllWorkByTag("notifications-$sessionId") } } @Test fun `submit builds the request and enqueues it`() = runTest { - val sessionStore = InMemorySessionStore() val workManager = spyk() val scheduler = DefaultWorkManagerScheduler( lazyWorkManager = lazy { workManager }, - appCoroutineScope = backgroundScope, - sessionStore = sessionStore, + sessionObserver = FakeSessionObserver(), ) scheduler.submit(FakeWorkManagerRequest()) @@ -73,13 +62,11 @@ class DefaultWorkManagerSchedulerTest { @Test fun `submit won't do anything if building the work request fails`() = runTest { - val sessionStore = InMemorySessionStore() val workManager = spyk() val scheduler = DefaultWorkManagerScheduler( lazyWorkManager = lazy { workManager }, - appCoroutineScope = backgroundScope, - sessionStore = sessionStore, + sessionObserver = FakeSessionObserver(), ) scheduler.submit(FakeWorkManagerRequest(result = Result.failure(IllegalStateException("Test error")))) @@ -89,13 +76,11 @@ class DefaultWorkManagerSchedulerTest { @Test fun `cancel will cancel all pending work for a session id`() = runTest { - val sessionStore = InMemorySessionStore() val workManager = spyk() val scheduler = DefaultWorkManagerScheduler( lazyWorkManager = lazy { workManager }, - appCoroutineScope = backgroundScope, - sessionStore = sessionStore, + sessionObserver = FakeSessionObserver(), ) val sessionId = SessionId("@alice:matrix.org")