Carry numeric priorities through encrypted RPC and adapter writers with bounded admission. Correct push semantics and socket lifecycle cleanup, expose dispatch gating, and add opt-in connection health. Preserve the WebSocket setup API while allowing applications to override keepalive settings. Enable Android socket publication and document the 0.7.2-SNAPSHOT release workflow.
66 lines
2.9 KiB
Kotlin
66 lines
2.9 KiB
Kotlin
@file:OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class, ExperimentalUnsignedTypes::class)
|
|
|
|
import kotlinx.coroutines.*
|
|
import kotlinx.coroutines.test.*
|
|
import net.sergeych.crypto2.initCrypto
|
|
import net.sergeych.kiloparsec.*
|
|
import kotlin.test.*
|
|
import kotlin.time.Duration.Companion.seconds
|
|
|
|
class TransportAdmissionTest {
|
|
@Test fun readyCallsDoNotAddPollingDelay() = runTest(timeout = 10.seconds) {
|
|
val ping by command<Int, Int>()
|
|
val (a, b) = createTestDevice()
|
|
val local = LocalInterface<Unit>().apply { on(ping) { it } }
|
|
val client = Transport(a, local, Unit)
|
|
val server = Transport(b, local, Unit)
|
|
val jobs = listOf(launch { client.run() }, launch { server.run() })
|
|
try {
|
|
val start = currentTime
|
|
repeat(20) { assertEquals(it, client.call(ping, it)) }
|
|
assertEquals(0L, currentTime - start, "Ready transports must not impose an artificial per-call delay")
|
|
} finally { jobs.forEach { it.cancelAndJoin() } }
|
|
}
|
|
|
|
@Test fun successfulPlainPushReturnsNormally() = runTest(timeout = 10.seconds) {
|
|
val notify by command<Int, Unit>()
|
|
val received = CompletableDeferred<Int>()
|
|
val (a, b) = createTestDevice()
|
|
val client = Transport(a, LocalInterface<Unit>(), Unit)
|
|
val server = Transport(b, LocalInterface<Unit>().apply { on(notify) { received.complete(it); Unit } }, Unit)
|
|
val jobs = listOf(launch { client.run() }, launch { server.run() })
|
|
try {
|
|
client.push(notify, 7)
|
|
assertEquals(7, received.await())
|
|
} finally { jobs.forEach { it.cancelAndJoin() } }
|
|
}
|
|
|
|
@Test fun encryptedPushDoesNotWaitForRemoteHandler() = runTest(timeout = 10.seconds) {
|
|
initCrypto()
|
|
val notify by command<Int, Unit>()
|
|
val ping by command<Int, Int>()
|
|
val entered = CompletableDeferred<Unit>()
|
|
val release = CompletableDeferred<Unit>()
|
|
val ready = CompletableDeferred<Unit>()
|
|
val (a, b) = createTestDevice()
|
|
val server = KiloServerConnection(KiloInterface<Unit>().apply {
|
|
on(notify) { entered.complete(Unit); release.await() }
|
|
on(ping) { it }
|
|
}, b, Unit)
|
|
val client = KiloClientConnection(KiloInterface<Unit>(), a, Unit)
|
|
val jobs = listOf(launch { server.run() }, launch { client.run { if (it) ready.complete(Unit) } })
|
|
try {
|
|
ready.await()
|
|
val notification = async { client.push(notify, 7) }
|
|
entered.await()
|
|
runCurrent()
|
|
assertTrue(notification.isCompleted, "Push must return before the remote handler finishes")
|
|
notification.await()
|
|
assertEquals(9, client.call(ping, 9), "A pending notification must not block ordinary RPC")
|
|
} finally {
|
|
release.complete(Unit)
|
|
jobs.forEach { it.cancelAndJoin() }
|
|
}
|
|
}
|
|
}
|