feat(infrared): add infrared control, learning, and virtual remote module #9
+9
-7
@@ -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) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+69
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user