Polishing contribution

Closes gh-36650
This commit is contained in:
rstoyanchev
2026-05-27 17:19:00 +01:00
parent f9b75b02da
commit 6fd45c118d
@@ -19,6 +19,7 @@ package org.springframework.web.reactive.socket.adapter;
import java.net.URI; import java.net.URI;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
@@ -45,51 +46,45 @@ import static org.mockito.Mockito.verify;
/** /**
* Tests for {@link JettyWebSocketSession}. * Tests for {@link JettyWebSocketSession}.
*
* @author Max Guiking * @author Max Guiking
*/ */
class JettyWebSocketSessionTests { class JettyWebSocketSessionTests {
private final DefaultDataBufferFactory bufferFactory = DefaultDataBufferFactory.sharedInstance; private final Session nativeSession = mock(Session.class);
private final Session jettySession = mock(Session.class); private final JettyWebSocketSession webSocketSession = new JettyWebSocketSession(
this.nativeSession, new HandshakeInfo(URI.create("ws://example.org"),
private final JettyWebSocketSession session = new JettyWebSocketSession(this.jettySession, new HttpHeaders(), Mono.empty(), null), DefaultDataBufferFactory.sharedInstance);
new HandshakeInfo(URI.create("ws://example.org"), new HttpHeaders(), Mono.empty(), null),
this.bufferFactory);
@Test @Test
void sendBinaryMessageWithSingleFragmentMarksFragmentAsLast() { void sendBinaryMessageWithSingleBuffer() {
succeedOnSendPartialBinary(); succeedOnSendPartialBinary();
DataBuffer payload = this.bufferFactory.wrap("hello".getBytes(StandardCharsets.UTF_8)); DataBuffer payload = DefaultDataBufferFactory.sharedInstance.wrap("hello".getBytes(StandardCharsets.UTF_8));
WebSocketMessage message = new WebSocketMessage(WebSocketMessage.Type.BINARY, payload); WebSocketMessage message = new WebSocketMessage(WebSocketMessage.Type.BINARY, payload);
this.session.sendMessage(message).block(); this.webSocketSession.sendMessage(message).block();
ArgumentCaptor<Boolean> lastCaptor = ArgumentCaptor.forClass(Boolean.class); ArgumentCaptor<Boolean> last = ArgumentCaptor.forClass(Boolean.class);
verify(this.jettySession).sendPartialBinary(any(ByteBuffer.class), lastCaptor.capture(), any(Callback.class)); verify(this.nativeSession).sendPartialBinary(any(ByteBuffer.class), last.capture(), any(Callback.class));
assertThat(lastCaptor.getValue()).as("FIN bit must be set for the final (and only) fragment").isTrue(); assertThat(last.getValue()).isTrue();
} }
@Test @Test
void sendBinaryMessageWithMultipleFragmentsMarksOnlyFinalFragmentAsLast() { void sendBinaryMessageWithMultipleBuffers() {
succeedOnSendPartialBinary(); succeedOnSendPartialBinary();
List<ByteBuffer> fragments = List.of( WebSocketMessage message = new WebSocketMessage(WebSocketMessage.Type.BINARY, new MultiBufferDataBuffer(
ByteBuffer.wrap("one".getBytes(StandardCharsets.UTF_8)), ByteBuffer.wrap("one".getBytes(StandardCharsets.UTF_8)),
ByteBuffer.wrap("two".getBytes(StandardCharsets.UTF_8)), ByteBuffer.wrap("two".getBytes(StandardCharsets.UTF_8)),
ByteBuffer.wrap("three".getBytes(StandardCharsets.UTF_8))); ByteBuffer.wrap("three".getBytes(StandardCharsets.UTF_8))));
WebSocketMessage message = new WebSocketMessage(WebSocketMessage.Type.BINARY,
new MultiBufferDataBuffer(this.bufferFactory, fragments));
this.session.sendMessage(message).block(); this.webSocketSession.sendMessage(message).block();
ArgumentCaptor<Boolean> lastCaptor = ArgumentCaptor.forClass(Boolean.class); ArgumentCaptor<Boolean> last = ArgumentCaptor.forClass(Boolean.class);
verify(this.jettySession, times(fragments.size())) verify(this.nativeSession, times(3)).sendPartialBinary(any(ByteBuffer.class), last.capture(), any(Callback.class));
.sendPartialBinary(any(ByteBuffer.class), lastCaptor.capture(), any(Callback.class)); assertThat(last.getAllValues()).containsExactly(false, false, true);
assertThat(lastCaptor.getAllValues()).containsExactly(false, false, true);
} }
private void succeedOnSendPartialBinary() { private void succeedOnSendPartialBinary() {
@@ -97,22 +92,20 @@ class JettyWebSocketSessionTests {
Callback callback = invocation.getArgument(2); Callback callback = invocation.getArgument(2);
callback.succeed(); callback.succeed();
return null; return null;
}).when(this.jettySession).sendPartialBinary(any(ByteBuffer.class), anyBoolean(), any(Callback.class)); }).when(this.nativeSession).sendPartialBinary(any(ByteBuffer.class), anyBoolean(), any(Callback.class));
} }
/** /**
* Minimal {@link DataBuffer} whose {@link #readableByteBuffers()} yields a * Minimal DataBuffer that returns a given list of buffers from {@link #readableByteBuffers()}.
* caller-supplied list of buffers, exercising the multi-fragment branch of
* {@link JettyWebSocketSession#sendMessage(WebSocketMessage)}.
*/ */
private static final class MultiBufferDataBuffer extends DataBufferWrapper { private static final class MultiBufferDataBuffer extends DataBufferWrapper {
private final List<ByteBuffer> buffers; private final List<ByteBuffer> buffers;
MultiBufferDataBuffer(DefaultDataBufferFactory factory, List<ByteBuffer> buffers) { MultiBufferDataBuffer(ByteBuffer... buffers) {
super(factory.allocateBuffer(0)); super(DefaultDataBufferFactory.sharedInstance.allocateBuffer(0));
this.buffers = buffers; this.buffers = Arrays.asList(buffers);
} }
@Override @Override
@@ -123,7 +116,7 @@ class JettyWebSocketSessionTests {
@Override @Override
public boolean hasNext() { public boolean hasNext() {
return this.index < MultiBufferDataBuffer.this.buffers.size(); return (this.index < MultiBufferDataBuffer.this.buffers.size());
} }
@Override @Override