Refine Coroutines annotated controller support
This commit refines Coroutines annotated controller support by considering Kotlin Unit as Java void and using the right ReactiveAdapter to support all use cases, including suspending functions that return Flow (usual when using APIs like WebClient). It also fixes RSocket fire and forget handling and adds related tests for that use case. Closes gh-24057 Closes gh-23866
This commit is contained in:
@@ -39,6 +39,7 @@ import org.springframework.messaging.handler.annotation.MessageMapping
|
||||
import org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler
|
||||
import org.springframework.stereotype.Controller
|
||||
import reactor.core.publisher.Flux
|
||||
import reactor.core.publisher.ReplayProcessor
|
||||
import reactor.test.StepVerifier
|
||||
import java.time.Duration
|
||||
|
||||
@@ -50,6 +51,34 @@ import java.time.Duration
|
||||
*/
|
||||
class RSocketClientToServerCoroutinesIntegrationTests {
|
||||
|
||||
@Test
|
||||
fun fireAndForget() {
|
||||
Flux.range(1, 3)
|
||||
.concatMap { requester.route("receive").data("Hello $it").send() }
|
||||
.blockLast()
|
||||
StepVerifier.create(context.getBean(ServerController::class.java).fireForgetPayloads)
|
||||
.expectNext("Hello 1")
|
||||
.expectNext("Hello 2")
|
||||
.expectNext("Hello 3")
|
||||
.thenAwait(Duration.ofMillis(50))
|
||||
.thenCancel()
|
||||
.verify(Duration.ofSeconds(5))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun fireAndForgetAsync() {
|
||||
Flux.range(1, 3)
|
||||
.concatMap { i: Int -> requester.route("receive-async").data("Hello $i").send() }
|
||||
.blockLast()
|
||||
StepVerifier.create(context.getBean(ServerController::class.java).fireForgetPayloads)
|
||||
.expectNext("Hello 1")
|
||||
.expectNext("Hello 2")
|
||||
.expectNext("Hello 3")
|
||||
.thenAwait(Duration.ofMillis(50))
|
||||
.thenCancel()
|
||||
.verify(Duration.ofSeconds(5))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun echoAsync() {
|
||||
val result = Flux.range(1, 3).concatMap { i -> requester.route("echo-async").data("Hello " + i!!).retrieveMono(String::class.java) }
|
||||
@@ -70,6 +99,16 @@ class RSocketClientToServerCoroutinesIntegrationTests {
|
||||
.verify(Duration.ofSeconds(5))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun echoStreamAsync() {
|
||||
val result = requester.route("echo-stream-async").data("Hello").retrieveFlux(String::class.java)
|
||||
|
||||
StepVerifier.create(result)
|
||||
.expectNext("Hello 0").expectNextCount(6).expectNext("Hello 7")
|
||||
.thenCancel()
|
||||
.verify(Duration.ofSeconds(5))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun echoChannel() {
|
||||
val result = requester.route("echo-channel")
|
||||
@@ -106,6 +145,19 @@ class RSocketClientToServerCoroutinesIntegrationTests {
|
||||
@Controller
|
||||
class ServerController {
|
||||
|
||||
val fireForgetPayloads = ReplayProcessor.create<String>()
|
||||
|
||||
@MessageMapping("receive")
|
||||
fun receive(payload: String) {
|
||||
fireForgetPayloads.onNext(payload)
|
||||
}
|
||||
|
||||
@MessageMapping("receive-async")
|
||||
suspend fun receiveAsync(payload: String) {
|
||||
delay(10)
|
||||
fireForgetPayloads.onNext(payload)
|
||||
}
|
||||
|
||||
@MessageMapping("echo-async")
|
||||
suspend fun echoAsync(payload: String): String {
|
||||
delay(10)
|
||||
@@ -123,6 +175,18 @@ class RSocketClientToServerCoroutinesIntegrationTests {
|
||||
}
|
||||
}
|
||||
|
||||
@MessageMapping("echo-stream-async")
|
||||
suspend fun echoStreamAsync(payload: String): Flow<String> {
|
||||
delay(10)
|
||||
var i = 0
|
||||
return flow {
|
||||
while(true) {
|
||||
delay(10)
|
||||
emit("$payload ${i++}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@MessageMapping("echo-channel")
|
||||
fun echoChannel(payloads: Flow<String>) = payloads.map {
|
||||
delay(10)
|
||||
@@ -185,8 +249,6 @@ class RSocketClientToServerCoroutinesIntegrationTests {
|
||||
|
||||
private lateinit var server: CloseableChannel
|
||||
|
||||
private val interceptor = FireAndForgetCountingInterceptor()
|
||||
|
||||
private lateinit var requester: RSocketRequester
|
||||
|
||||
|
||||
@@ -196,7 +258,6 @@ class RSocketClientToServerCoroutinesIntegrationTests {
|
||||
context = AnnotationConfigApplicationContext(ServerConfig::class.java)
|
||||
|
||||
server = RSocketFactory.receive()
|
||||
.addResponderPlugin(interceptor)
|
||||
.frameDecoder(PayloadDecoder.ZERO_COPY)
|
||||
.acceptor(context.getBean(RSocketMessageHandler::class.java).responder())
|
||||
.transport(TcpServerTransport.create("localhost", 7000))
|
||||
|
||||
Reference in New Issue
Block a user