fix(infrared): add relearn use case for ready keys and clean up interrupted learning in onCleared and init
This commit is contained in:
@@ -106,7 +106,88 @@ class RetryInfraredKeyLearning(
|
||||
ref = ref,
|
||||
expectedStatuses = setOf(
|
||||
InfraredKeyStatus.FAILED,
|
||||
),
|
||||
targetStatus = InfraredKeyStatus.LEARNING,
|
||||
lastErrorCode = null,
|
||||
lastErrorDetail = null,
|
||||
updatedAtEpochMillis = clock.now(),
|
||||
)
|
||||
) {
|
||||
is DomainResult.Success -> Unit
|
||||
is DomainResult.Failure -> return result
|
||||
}
|
||||
|
||||
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),
|
||||
targetStatus = InfraredKeyStatus.READY,
|
||||
lastErrorCode = null,
|
||||
lastErrorDetail = null,
|
||||
updatedAtEpochMillis = clock.now(),
|
||||
)
|
||||
|
||||
is DomainResult.Failure -> {
|
||||
repository.transitionStatus(
|
||||
ref = ref,
|
||||
expectedStatuses = setOf(InfraredKeyStatus.LEARNING),
|
||||
targetStatus = InfraredKeyStatus.FAILED,
|
||||
lastErrorCode = result.error.externalCode,
|
||||
lastErrorDetail = null,
|
||||
updatedAtEpochMillis = clock.now(),
|
||||
)
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RelearnInfraredKey(
|
||||
private val repository: InfraredKeyRepository,
|
||||
private val gateway: InfraredGateway,
|
||||
private val clock: EpochMillisClock,
|
||||
) {
|
||||
suspend operator fun invoke(ref: InfraredKeyRef): DomainResult<Unit> {
|
||||
val key = when (val result = repository.getKey(ref)) {
|
||||
is DomainResult.Success -> result.value
|
||||
?: return DomainResult.Failure(
|
||||
DomainError.InvalidRequest(detail = "Infrared key not found"),
|
||||
)
|
||||
|
||||
is DomainResult.Failure -> return result
|
||||
}
|
||||
if (key.status == InfraredKeyStatus.LEARNING) {
|
||||
return DomainResult.Failure(
|
||||
DomainError.InvalidRequest(detail = "Infrared key is already learning"),
|
||||
)
|
||||
}
|
||||
|
||||
when (
|
||||
val result = repository.transitionStatus(
|
||||
ref = ref,
|
||||
expectedStatuses = setOf(
|
||||
InfraredKeyStatus.READY,
|
||||
InfraredKeyStatus.FAILED,
|
||||
),
|
||||
targetStatus = InfraredKeyStatus.LEARNING,
|
||||
lastErrorCode = null,
|
||||
|
||||
+29
-1
@@ -22,6 +22,7 @@ class LearnInfraredKeyTest {
|
||||
private val gateway = RecordingInfraredGateway()
|
||||
private val learn = LearnInfraredKey(repository, gateway, factory, clock)
|
||||
private val retry = RetryInfraredKeyLearning(repository, gateway, clock)
|
||||
private val relearn = RelearnInfraredKey(repository, gateway, clock)
|
||||
|
||||
@Test
|
||||
fun persistsLearningBeforeCallingHardwareThenMarksReady() = runTest {
|
||||
@@ -131,7 +132,34 @@ class LearnInfraredKeyTest {
|
||||
assertEquals(0, repository.insertedKeys.size)
|
||||
assertEquals(2, repository.transitionCalls.size)
|
||||
assertEquals(
|
||||
setOf(InfraredKeyStatus.FAILED, InfraredKeyStatus.READY),
|
||||
setOf(InfraredKeyStatus.FAILED),
|
||||
repository.transitionCalls.first().expectedStatuses,
|
||||
)
|
||||
assertEquals(
|
||||
setOf(InfraredKeyStatus.LEARNING),
|
||||
repository.transitionCalls.last().expectedStatuses,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun relearnReusesStableIdAndSdkKeyForReadyKey() = runTest {
|
||||
val original = failedKey(id = InfraredKeyId("key1"), sdkKey = "app_ir_key1").copy(
|
||||
status = InfraredKeyStatus.READY,
|
||||
lastErrorCode = null,
|
||||
lastErrorDetail = null,
|
||||
)
|
||||
repository.seed(original)
|
||||
|
||||
val result = relearn(original.ref())
|
||||
|
||||
assertEquals(DomainResult.Success(Unit), result)
|
||||
assertEquals("app_ir_key1", gateway.learnedKeys.single().key)
|
||||
assertEquals(InfraredKeyId("key1"), repository.onlyKey().id)
|
||||
assertEquals(InfraredKeyStatus.READY, repository.onlyKey().status)
|
||||
assertEquals(0, repository.insertedKeys.size)
|
||||
assertEquals(2, repository.transitionCalls.size)
|
||||
assertEquals(
|
||||
setOf(InfraredKeyStatus.READY, InfraredKeyStatus.FAILED),
|
||||
repository.transitionCalls.first().expectedStatuses,
|
||||
)
|
||||
assertEquals(
|
||||
|
||||
Reference in New Issue
Block a user