From b5e8c80db1d3edfe1a1d1ef8ce93bfe3e718affe Mon Sep 17 00:00:00 2001 From: Sunik Kupfer Date: Mon, 1 Dec 2025 14:40:52 +0100 Subject: [PATCH] Try to fix pending sync state test failures by using a hot flow (#1839) * Remove the ignore annotation * Turn inPendingState in to a hot state flow for the test duration Signed-off-by: Sunik Kupfer * Rename methods registering the sync state observer Signed-off-by: Sunik Kupfer --------- Signed-off-by: Sunik Kupfer --- .../AccountSettingsMigration21Test.kt | 38 +++++++++++-------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/app/src/androidTest/kotlin/at/bitfire/davdroid/settings/migration/AccountSettingsMigration21Test.kt b/app/src/androidTest/kotlin/at/bitfire/davdroid/settings/migration/AccountSettingsMigration21Test.kt index f135b5cb3..456548fb7 100644 --- a/app/src/androidTest/kotlin/at/bitfire/davdroid/settings/migration/AccountSettingsMigration21Test.kt +++ b/app/src/androidTest/kotlin/at/bitfire/davdroid/settings/migration/AccountSettingsMigration21Test.kt @@ -15,8 +15,7 @@ import at.bitfire.davdroid.sync.account.TestAccount import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.testing.HiltAndroidRule import dagger.hilt.android.testing.HiltAndroidTest -import kotlinx.coroutines.channels.awaitClose -import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.first import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withTimeout @@ -26,7 +25,6 @@ import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Before import org.junit.BeforeClass -import org.junit.Ignore import org.junit.Rule import org.junit.Test import java.util.logging.Logger @@ -51,17 +49,8 @@ class AccountSettingsMigration21Test { lateinit var account: Account val authority = CalendarContract.AUTHORITY - private val inPendingState = callbackFlow { - val stateChangeListener = ContentResolver.addStatusChangeListener( - ContentResolver.SYNC_OBSERVER_TYPE_PENDING or ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE - ) { - trySend(ContentResolver.isSyncPending(account, authority)) - } - trySend(ContentResolver.isSyncPending(account, authority)) - awaitClose { - ContentResolver.removeStatusChangeListener(stateChangeListener) - } - } + private val inPendingState = MutableStateFlow(false) + private var statusChangeListener: Any? = null @Before fun setUp() { @@ -71,15 +60,18 @@ class AccountSettingsMigration21Test { // Enable sync globally and for the test account ContentResolver.setIsSyncable(account, authority, 1) + + // Start hot flow + registerSyncStateObserver() } @After fun tearDown() { + unregisterSyncStateObserver() TestAccount.remove(account) } - @Ignore("Sometimes failing, see https://github.com/bitfireAT/davx5-ose/issues/1835") @SdkSuppress(minSdkVersion = 34) @Test fun testCancelsSyncAndClearsPendingState() = runBlocking { @@ -117,6 +109,22 @@ class AccountSettingsMigration21Test { .setManual(true) // equivalent of setting both SYNC_EXTRAS_IGNORE_SETTINGS and SYNC_EXTRAS_IGNORE_BACKOFF .build() + private fun registerSyncStateObserver() { + // listener pushes updates immediately when sync status changes + statusChangeListener = ContentResolver.addStatusChangeListener( + ContentResolver.SYNC_OBSERVER_TYPE_PENDING or ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE + ) { + inPendingState.tryEmit(ContentResolver.isSyncPending(account, authority)) + } + + // Emit initial state + inPendingState.tryEmit(ContentResolver.isSyncPending(account, authority)) + } + + private fun unregisterSyncStateObserver() { + statusChangeListener?.let { ContentResolver.removeStatusChangeListener(it) } + } + companion object { var globalAutoSyncBeforeTest = false