From ca2c2c812ef3d481e88d301ee7b5f50b540fd54a Mon Sep 17 00:00:00 2001 From: l2yuPa Date: Fri, 20 Feb 2026 22:30:00 +0900 Subject: [PATCH] Add regression test for writer invocation lock scope Signed-off-by: l2yuPa --- .../reactive/ChannelSendOperatorTests.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/spring-web/src/test/java/org/springframework/http/server/reactive/ChannelSendOperatorTests.java b/spring-web/src/test/java/org/springframework/http/server/reactive/ChannelSendOperatorTests.java index ef730a3f6ed..f2d972ce9e1 100644 --- a/spring-web/src/test/java/org/springframework/http/server/reactive/ChannelSendOperatorTests.java +++ b/spring-web/src/test/java/org/springframework/http/server/reactive/ChannelSendOperatorTests.java @@ -21,6 +21,7 @@ import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @@ -216,6 +217,44 @@ class ChannelSendOperatorTests { .verify(Duration.ofMillis(5000)); } + @Test + void writeFunctionIsNotInvokedUnderMonitorLock() { + ChannelSendOperator operator = new ChannelSendOperator<>( + Mono.just("one"), + publisher -> { + CountDownLatch acquired = new CountDownLatch(1); + Thread t = new Thread(() -> { + synchronized (publisher) { + acquired.countDown(); + } + }); + t.start(); + + try { + if (!acquired.await(1, TimeUnit.SECONDS)) { + throw new IllegalStateException("writeFunction appears to be invoked under monitor lock"); + } + } + catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + throw new IllegalStateException(ex); + } + finally { + try { + t.join(1_000); + } + catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + + return Mono.empty(); + }); + + StepVerifier.create(operator) + .expectComplete() + .verify(Duration.ofSeconds(2)); + } private Mono sendOperator(Publisher source){ return new ChannelSendOperator<>(source, writer::send);