fix(infrared): unify atomic config state snapshot, avoid message race, and rollback cancelled learning status
This commit is contained in:
+37
-6
@@ -5,6 +5,9 @@ import com.flagship.abox.manager.domain.DomainError
|
||||
import com.flagship.abox.manager.domain.DomainResult
|
||||
import com.flagship.abox.manager.domain.InfraredGateway
|
||||
import com.flagship.abox.manager.domain.ProviderProfileId
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.NonCancellable
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class LearnInfraredKey(
|
||||
private val repository: InfraredKeyRepository,
|
||||
@@ -28,13 +31,27 @@ class LearnInfraredKey(
|
||||
is DomainResult.Failure -> return result
|
||||
}
|
||||
|
||||
return when (
|
||||
val result = gateway.learnKey(
|
||||
val result = try {
|
||||
gateway.learnKey(
|
||||
profileId = key.profileId,
|
||||
deviceName = key.deviceName,
|
||||
key = key.sdkKey,
|
||||
)
|
||||
) {
|
||||
} catch (e: CancellationException) {
|
||||
withContext(NonCancellable) {
|
||||
repository.transitionStatus(
|
||||
ref = key.ref(),
|
||||
expectedStatuses = setOf(InfraredKeyStatus.LEARNING),
|
||||
targetStatus = InfraredKeyStatus.FAILED,
|
||||
lastErrorCode = null,
|
||||
lastErrorDetail = "Cancelled",
|
||||
updatedAtEpochMillis = clock.now(),
|
||||
)
|
||||
}
|
||||
throw e
|
||||
}
|
||||
|
||||
return when (result) {
|
||||
is DomainResult.Success -> when (
|
||||
val transition = repository.transitionStatus(
|
||||
ref = key.ref(),
|
||||
@@ -101,13 +118,27 @@ class RetryInfraredKeyLearning(
|
||||
is DomainResult.Failure -> return result
|
||||
}
|
||||
|
||||
return when (
|
||||
val result = gateway.learnKey(
|
||||
val result = try {
|
||||
gateway.learnKey(
|
||||
profileId = key.profileId,
|
||||
deviceName = key.deviceName,
|
||||
key = key.sdkKey,
|
||||
)
|
||||
) {
|
||||
} catch (e: CancellationException) {
|
||||
withContext(NonCancellable) {
|
||||
repository.transitionStatus(
|
||||
ref = ref,
|
||||
expectedStatuses = setOf(InfraredKeyStatus.LEARNING),
|
||||
targetStatus = InfraredKeyStatus.FAILED,
|
||||
lastErrorCode = null,
|
||||
lastErrorDetail = "Cancelled",
|
||||
updatedAtEpochMillis = clock.now(),
|
||||
)
|
||||
}
|
||||
throw e
|
||||
}
|
||||
|
||||
return when (result) {
|
||||
is DomainResult.Success -> repository.transitionStatus(
|
||||
ref = ref,
|
||||
expectedStatuses = setOf(InfraredKeyStatus.LEARNING),
|
||||
|
||||
+16
@@ -269,6 +269,22 @@ class LearnInfraredKeyTest {
|
||||
assertEquals(1, gateway.learnedKeys.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun learningCancellationTransitionsStatusToFailed() = runTest {
|
||||
gateway.onLearn = { _, _, _ ->
|
||||
throw kotlinx.coroutines.CancellationException("User cancelled")
|
||||
}
|
||||
|
||||
try {
|
||||
learn(profile, device, "Power")
|
||||
} catch (_: kotlinx.coroutines.CancellationException) {
|
||||
// expected
|
||||
}
|
||||
|
||||
assertEquals(InfraredKeyStatus.FAILED, repository.onlyKey().status)
|
||||
assertEquals("Cancelled", repository.onlyKey().lastErrorDetail)
|
||||
}
|
||||
|
||||
private fun failedKey(
|
||||
id: InfraredKeyId = keyId,
|
||||
sdkKey: String = "app_ir_key1",
|
||||
|
||||
Reference in New Issue
Block a user