fix: snapshot infrared fake calls

This commit is contained in:
2026-08-24 02:44:05 +08:00
parent c21ae4e0d9
commit bdd3779899
2 changed files with 78 additions and 7 deletions
@@ -12,8 +12,8 @@ import com.flagship.abox.manager.domain.SocketPowerState
import com.flagship.abox.manager.domain.SocketStatus
import com.flagship.abox.manager.domain.TemperatureHumidityGateway
import com.flagship.abox.manager.domain.TemperatureHumidityReading
import java.util.Collections
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CopyOnWriteArrayList
class FakeSocketGateway : SocketGateway {
private val states = ConcurrentHashMap<DeviceKey, SocketPowerState>()
@@ -78,10 +78,9 @@ class FakeTemperatureHumidityGateway : TemperatureHumidityGateway {
}
class FakeInfraredGateway : InfraredGateway {
val sentKeys: MutableList<InfraredCall> = Collections.synchronizedList(mutableListOf())
val learnedKeys: MutableList<InfraredCall> = Collections.synchronizedList(mutableListOf())
val downloadCalls: MutableList<InfraredDownloadCall> =
Collections.synchronizedList(mutableListOf())
val sentKeys = CopyOnWriteArrayList<InfraredCall>()
val learnedKeys = CopyOnWriteArrayList<InfraredCall>()
val downloadCalls = CopyOnWriteArrayList<InfraredDownloadCall>()
private val sendResults = ConcurrentHashMap<InfraredOperationKey, DomainResult<Unit>>()
private val learnResults = ConcurrentHashMap<InfraredOperationKey, DomainResult<Unit>>()
@@ -134,9 +133,12 @@ class FakeInfraredGateway : InfraredGateway {
profileId: ProviderProfileId,
codes: List<InfraredCode>,
): DomainResult<List<InfraredCodeDownloadResult>> {
val codesSnapshot = codes.toList()
downloadError?.let { return DomainResult.Failure(it) }
downloadCalls += InfraredDownloadCall(profileId, codes)
return DomainResult.Success(codes.map { InfraredCodeDownloadResult(it, successful = true) })
downloadCalls += InfraredDownloadCall(profileId, codesSnapshot)
return DomainResult.Success(
codesSnapshot.map { InfraredCodeDownloadResult(it, successful = true) },
)
}
}
@@ -4,8 +4,14 @@ import com.flagship.abox.manager.domain.DeviceName
import com.flagship.abox.manager.domain.DomainError
import com.flagship.abox.manager.domain.DomainResult
import com.flagship.abox.manager.domain.InfraredCode
import com.flagship.abox.manager.domain.InfraredCodeDownloadResult
import com.flagship.abox.manager.domain.ProviderProfileId
import com.flagship.abox.manager.domain.SocketPowerState
import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.CountDownLatch
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
@@ -55,6 +61,69 @@ class FakeDeviceGatewaysTest {
assertTrue(download is DomainResult.Success)
}
@Test
fun infraredDownloadRecordsAndReturnsAnInputSnapshot() = runTest {
val gateway = FakeInfraredGateway()
val code = InfraredCode(DeviceName("ir-1"), "power", "code-value")
val mutableCodes = mutableListOf(code)
val result = gateway.downloadCodes(profileOne, mutableCodes)
mutableCodes.clear()
assertEquals(
InfraredDownloadCall(profileOne, listOf(code)),
gateway.downloadCalls.single(),
)
assertEquals(
DomainResult.Success(listOf(InfraredCodeDownloadResult(code, successful = true))),
result,
)
}
@Test
fun infraredCallLogCanBeIteratedSafelyAroundConcurrentWrites() = runTest {
val gateway = FakeInfraredGateway()
val deviceName = DeviceName("ir-1")
gateway.sendKey(profileOne, deviceName, "initial")
val staleIterators = List(10) { gateway.sentKeys.iterator() }
val start = CountDownLatch(1)
val failures = ConcurrentLinkedQueue<Throwable>()
val writerCount = 4
val callsPerWriter = 100
val writers = List(writerCount) { writerIndex ->
launch(Dispatchers.Default) {
start.await()
repeat(callsPerWriter) { callIndex ->
gateway.sendKey(profileOne, deviceName, "$writerIndex-$callIndex")
}
}
}
val reader = launch(Dispatchers.Default) {
start.await()
repeat(100) {
try {
gateway.sentKeys.forEach { call -> call.key.length }
} catch (failure: Throwable) {
failures += failure
}
}
}
start.countDown()
(writers + reader).joinAll()
staleIterators.forEach { iterator ->
try {
iterator.forEachRemaining { call -> call.key.length }
} catch (failure: Throwable) {
failures += failure
}
}
assertTrue(failures.toList().joinToString(), failures.isEmpty())
assertEquals(1 + writerCount * callsPerWriter, gateway.sentKeys.size)
}
@Test
fun infraredLearnResultsCanDifferByProfileDeviceAndKey() = runTest {
val gateway = FakeInfraredGateway()