From b27c67fbe4b8a3bb023856edcb3d5d1669932edd Mon Sep 17 00:00:00 2001 From: mxhsnd <2049295946@qq.com> Date: Mon, 24 Aug 2026 11:41:36 +0800 Subject: [PATCH] test: verify ABSDK infrared contracts --- .../absdk/bridge/AbsdkDeviceBridgeTest.kt | 65 +++++++++++++++++++ .../absdk/bridge/AbsdkSerializationTest.kt | 34 ++++++++++ 2 files changed, 99 insertions(+) diff --git a/absdk-bridge/src/test/kotlin/com/flagship/abox/manager/absdk/bridge/AbsdkDeviceBridgeTest.kt b/absdk-bridge/src/test/kotlin/com/flagship/abox/manager/absdk/bridge/AbsdkDeviceBridgeTest.kt index 84002ea..55f63e8 100644 --- a/absdk-bridge/src/test/kotlin/com/flagship/abox/manager/absdk/bridge/AbsdkDeviceBridgeTest.kt +++ b/absdk-bridge/src/test/kotlin/com/flagship/abox/manager/absdk/bridge/AbsdkDeviceBridgeTest.kt @@ -17,10 +17,12 @@ import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Test +import kotlin.reflect.KClass class AbsdkDeviceBridgeTest { private val profile = ProviderProfileId("abox") private val socket = DeviceName("socket-1") + private val irDevice = DeviceName("ir-room") @Test fun socketControlReturnsConfirmedStatus() = runTest { @@ -83,6 +85,69 @@ class AbsdkDeviceBridgeTest { assertTrue((offline as DomainResult.Failure).error is DomainError.DeviceOffline) } + @Test + fun infraredSendForwardsDeviceAndStableKey() = runTest { + val client = ScriptedAbsdkClient() + val bridge = authenticatedBridge(client) + assertEquals(DomainResult.Success(Unit), bridge.sendKey(profile, irDevice, "app_ir_power")) + assertEquals(listOf("login:demo", "ir-send:ir-room:app_ir_power"), client.calls) + } + + @Test + fun infraredLearnForwardsDeviceAndStableKey() = runTest { + val client = ScriptedAbsdkClient() + val bridge = authenticatedBridge(client) + assertEquals(DomainResult.Success(Unit), bridge.learnKey(profile, irDevice, "app_ir_power")) + assertEquals(listOf("login:demo", "ir-learn:ir-room:app_ir_power"), client.calls) + } + + @Test + fun infraredErrorCodesAreMappedCorrectlyForSendAndLearn() = runTest { + val errorMappings = mapOf>( + "20201" to DomainError.InvalidRequest::class, + "20202" to DomainError.InvalidRequest::class, + "20203" to DomainError.DeviceNotFound::class, + "20204" to DomainError.OperationFailed::class, + "20205" to DomainError.OperationFailed::class, + "20206" to DomainError.DeviceOffline::class, + ) + + for ((code, expectedClass) in errorMappings) { + val client = ScriptedAbsdkClient().apply { + sendResponse = ScriptedAbsdkClient.failure(code, "message for $code") + learnResponse = ScriptedAbsdkClient.failure(code, "message for $code") + } + val bridge = authenticatedBridge(client) + + val sendResult = bridge.sendKey(profile, irDevice, "key1") + assertTrue("Expected send error class $expectedClass for code $code", sendResult is DomainResult.Failure) + assertEquals(expectedClass, (sendResult as DomainResult.Failure).error::class) + assertEquals(code, sendResult.error.externalCode) + + val learnResult = bridge.learnKey(profile, irDevice, "key1") + assertTrue("Expected learn error class $expectedClass for code $code", learnResult is DomainResult.Failure) + assertEquals(expectedClass, (learnResult as DomainResult.Failure).error::class) + assertEquals(code, learnResult.error.externalCode) + } + } + + @Test + fun infraredNullResponseReturnsUnknownDomainError() = runTest { + val client = ScriptedAbsdkClient().apply { + sendResponse = null + learnResponse = null + } + val bridge = authenticatedBridge(client) + + val sendResult = bridge.sendKey(profile, irDevice, "key1") + assertTrue(sendResult is DomainResult.Failure) + assertTrue((sendResult as DomainResult.Failure).error is DomainError.Unknown) + + val learnResult = bridge.learnKey(profile, irDevice, "key1") + assertTrue(learnResult is DomainResult.Failure) + assertTrue((learnResult as DomainResult.Failure).error is DomainError.Unknown) + } + @Test fun infraredCallsAndPartialDownloadResultsAreMapped() = runTest { val codeOne = InfraredCode(DeviceName("ir-1"), "power", "code-1") diff --git a/absdk-bridge/src/test/kotlin/com/flagship/abox/manager/absdk/bridge/AbsdkSerializationTest.kt b/absdk-bridge/src/test/kotlin/com/flagship/abox/manager/absdk/bridge/AbsdkSerializationTest.kt index fe68163..1663410 100644 --- a/absdk-bridge/src/test/kotlin/com/flagship/abox/manager/absdk/bridge/AbsdkSerializationTest.kt +++ b/absdk-bridge/src/test/kotlin/com/flagship/abox/manager/absdk/bridge/AbsdkSerializationTest.kt @@ -48,4 +48,38 @@ class AbsdkSerializationTest { assertEquals(1, client.maxConcurrentCalls.get()) } } + + @Test + fun concurrentInfraredAndOtherDeviceCallsDoNotOverlap() = runBlocking { + withTimeout(5_000) { + val profile = ProviderProfileId("abox") + val client = ScriptedAbsdkClient().apply { + socketStatusResponses = ArrayDeque( + listOf(ScriptedAbsdkClient.success(mapOf("status" to "1"))), + ) + } + val bridge = AbsdkBridge(client, Dispatchers.IO) + bridge.login(profile, LoginCredentials(Username("demo"), Password("secret"))) + + client.onCall = { + if (client.calls.last().startsWith("ir-learn") || client.calls.last().startsWith("temperature")) { + Thread.sleep(75) + } + } + + val irCall = async { + bridge.learnKey(profile, DeviceName("ir-1"), "app_ir_power") + } + val tempCall = async { + bridge.getReading(profile, DeviceName("th-1")) + } + + delay(10) + + irCall.await() + tempCall.await() + + assertEquals(1, client.maxConcurrentCalls.get()) + } + } }