Update state in runUpdatingState when CancellationException occurs (#5243)
This commit is contained in:
parent
307596d5a3
commit
fbca1b3dfe
3 changed files with 50 additions and 8 deletions
|
|
@ -10,6 +10,7 @@ package io.element.android.libraries.architecture
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
import io.element.android.libraries.core.extensions.runCatchingExceptions
|
import io.element.android.libraries.core.extensions.runCatchingExceptions
|
||||||
|
import kotlinx.coroutines.TimeoutCancellationException
|
||||||
import kotlin.contracts.ExperimentalContracts
|
import kotlin.contracts.ExperimentalContracts
|
||||||
import kotlin.contracts.InvocationKind
|
import kotlin.contracts.InvocationKind
|
||||||
import kotlin.contracts.contract
|
import kotlin.contracts.contract
|
||||||
|
|
@ -159,16 +160,19 @@ suspend inline fun <T> runUpdatingState(
|
||||||
callsInPlace(resultBlock, InvocationKind.EXACTLY_ONCE)
|
callsInPlace(resultBlock, InvocationKind.EXACTLY_ONCE)
|
||||||
}
|
}
|
||||||
state.value = AsyncAction.Loading
|
state.value = AsyncAction.Loading
|
||||||
return resultBlock().fold(
|
return try {
|
||||||
|
resultBlock()
|
||||||
|
} catch (e: TimeoutCancellationException) {
|
||||||
|
state.value = AsyncAction.Failure(errorTransform(e))
|
||||||
|
throw e
|
||||||
|
}.fold(
|
||||||
onSuccess = {
|
onSuccess = {
|
||||||
state.value = AsyncAction.Success(it)
|
state.value = AsyncAction.Success(it)
|
||||||
Result.success(it)
|
Result.success(it)
|
||||||
},
|
},
|
||||||
onFailure = {
|
onFailure = {
|
||||||
val error = errorTransform(it)
|
val error = errorTransform(it)
|
||||||
state.value = AsyncAction.Failure(
|
state.value = AsyncAction.Failure(error)
|
||||||
error = error,
|
|
||||||
)
|
|
||||||
Result.failure(error)
|
Result.failure(error)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.architecture
|
||||||
|
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import kotlinx.coroutines.TimeoutCancellationException
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import kotlinx.coroutines.withTimeout
|
||||||
|
import org.junit.Assert.assertSame
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Assert.fail
|
||||||
|
import org.junit.Test
|
||||||
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
|
||||||
|
class AsyncActionTest {
|
||||||
|
@Test
|
||||||
|
fun `updates state on timeout`() = runTest {
|
||||||
|
val state: MutableState<AsyncAction<Int>> = mutableStateOf(AsyncAction.Uninitialized)
|
||||||
|
val timeoutMillis = 500L
|
||||||
|
val operationTimeMillis = 1000L
|
||||||
|
|
||||||
|
try {
|
||||||
|
runUpdatingState(state = state) {
|
||||||
|
withTimeout(timeoutMillis.milliseconds) {
|
||||||
|
delay(operationTimeMillis)
|
||||||
|
}
|
||||||
|
Result.success(0)
|
||||||
|
}
|
||||||
|
fail("Expected TimeoutCancellationException, but nothing was thrown")
|
||||||
|
} catch (e: TimeoutCancellationException) {
|
||||||
|
assertTrue(state.value.isFailure())
|
||||||
|
assertSame(e, state.value.errorOrNull())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -14,7 +14,6 @@ import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.room.ForwardEventException
|
import io.element.android.libraries.matrix.api.room.ForwardEventException
|
||||||
import io.element.android.libraries.matrix.impl.roomlist.roomOrNull
|
import io.element.android.libraries.matrix.impl.roomlist.roomOrNull
|
||||||
import io.element.android.libraries.matrix.impl.timeline.runWithTimelineListenerRegistered
|
import io.element.android.libraries.matrix.impl.timeline.runWithTimelineListenerRegistered
|
||||||
import kotlinx.coroutines.CancellationException
|
|
||||||
import kotlinx.coroutines.withTimeout
|
import kotlinx.coroutines.withTimeout
|
||||||
import org.matrix.rustcomponents.sdk.MsgLikeKind
|
import org.matrix.rustcomponents.sdk.MsgLikeKind
|
||||||
import org.matrix.rustcomponents.sdk.RoomListService
|
import org.matrix.rustcomponents.sdk.RoomListService
|
||||||
|
|
@ -63,9 +62,6 @@ class RoomContentForwarder(
|
||||||
}
|
}
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
failedForwardingTo.add(RoomId(room.id()))
|
failedForwardingTo.add(RoomId(room.id()))
|
||||||
if (it is CancellationException) {
|
|
||||||
throw it
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue