*/
package org.opendaylight.restconf.nb.rfc8040.streams;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
-import java.io.IOException;
-import java.util.List;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.websocket.api.RemoteEndpoint;
import org.eclipse.jetty.websocket.api.Session;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
-
-public class WebSocketSessionHandlerTest {
-
- private static final class WebSocketTestSessionState {
- private final BaseListenerInterface listener;
- private final ScheduledExecutorService executorService;
- private final WebSocketSessionHandler webSocketSessionHandler;
- private final int heartbeatInterval;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.opendaylight.restconf.server.spi.RestconfStream;
+import org.opendaylight.restconf.server.spi.RestconfStream.EncodingName;
+import org.opendaylight.yangtools.concepts.Registration;
+
+@ExtendWith(MockitoExtension.class)
+class WebSocketSessionHandlerTest {
+ private final class WebSocketTestSessionState {
+ private final WebSocketSender webSocketSessionHandler;
+ private final long heartbeatInterval;
private final int maxFragmentSize;
- private final ScheduledFuture pingFuture;
- private WebSocketTestSessionState(final int maxFragmentSize, final int heartbeatInterval) {
- listener = mock(BaseListenerInterface.class);
- executorService = mock(ScheduledExecutorService.class);
+ WebSocketTestSessionState(final int maxFragmentSize, final long heartbeatInterval) {
this.heartbeatInterval = heartbeatInterval;
this.maxFragmentSize = maxFragmentSize;
- webSocketSessionHandler = new WebSocketSessionHandler(executorService, listener, maxFragmentSize,
- heartbeatInterval);
- pingFuture = mock(ScheduledFuture.class);
- when(executorService.scheduleWithFixedDelay(any(Runnable.class), eq((long) heartbeatInterval),
- eq((long) heartbeatInterval), eq(TimeUnit.MILLISECONDS))).thenReturn(pingFuture);
+ webSocketSessionHandler = new WebSocketSender(pingExecutor, stream, ENCODING, null, maxFragmentSize,
+ heartbeatInterval);
+
+ if (heartbeatInterval != 0) {
+ doReturn(pingRegistration).when(pingExecutor).startPingProcess(any(Runnable.class),
+ eq(heartbeatInterval), eq(TimeUnit.MILLISECONDS));
+ }
}
}
+ static final EncodingName ENCODING = new EncodingName("encoding");
+
+ @Mock
+ private RestconfStream<?> stream;
+ @Mock
+ private PingExecutor pingExecutor;
+ @Mock
+ private Registration pingRegistration;
+ @Mock
+ private Session session;
+
@Test
- public void onWebSocketConnectedWithEnabledPing() {
+ void onWebSocketConnectedWithEnabledPing() throws Exception {
final int heartbeatInterval = 1000;
- final WebSocketTestSessionState webSocketTestSessionState = new WebSocketTestSessionState(
- 1000, heartbeatInterval);
- final Session session = mock(Session.class);
+ final var webSocketTestSessionState = new WebSocketTestSessionState(1000, heartbeatInterval);
webSocketTestSessionState.webSocketSessionHandler.onWebSocketConnected(session);
- verify(webSocketTestSessionState.listener).addSubscriber(
- webSocketTestSessionState.webSocketSessionHandler);
- verify(webSocketTestSessionState.executorService).scheduleWithFixedDelay(any(Runnable.class),
- eq((long) webSocketTestSessionState.heartbeatInterval),
- eq((long) webSocketTestSessionState.heartbeatInterval), eq(TimeUnit.MILLISECONDS));
+ verify(stream).addSubscriber(webSocketTestSessionState.webSocketSessionHandler, ENCODING, null);
+ verify(pingExecutor).startPingProcess(any(Runnable.class), eq(webSocketTestSessionState.heartbeatInterval),
+ eq(TimeUnit.MILLISECONDS));
}
@Test
- public void onWebSocketConnectedWithDisabledPing() {
+ void onWebSocketConnectedWithDisabledPing() throws Exception {
final int heartbeatInterval = 0;
- final WebSocketTestSessionState webSocketTestSessionState = new WebSocketTestSessionState(
- 1000, heartbeatInterval);
- final Session session = mock(Session.class);
+ final var webSocketTestSessionState = new WebSocketTestSessionState(1000, heartbeatInterval);
webSocketTestSessionState.webSocketSessionHandler.onWebSocketConnected(session);
- verify(webSocketTestSessionState.listener).addSubscriber(
- webSocketTestSessionState.webSocketSessionHandler);
- verifyNoMoreInteractions(webSocketTestSessionState.executorService);
+ verify(stream).addSubscriber(webSocketTestSessionState.webSocketSessionHandler, ENCODING, null);
+ verifyNoMoreInteractions(pingExecutor);
}
@Test
- public void onWebSocketConnectedWithAlreadyOpenSession() {
- final WebSocketTestSessionState webSocketTestSessionState = new WebSocketTestSessionState(150, 8000);
- final Session session = mock(Session.class);
+ void onWebSocketConnectedWithAlreadyOpenSession() throws Exception {
+ final var webSocketTestSessionState = new WebSocketTestSessionState(150, 8000);
when(session.isOpen()).thenReturn(true);
webSocketTestSessionState.webSocketSessionHandler.onWebSocketConnected(session);
webSocketTestSessionState.webSocketSessionHandler.onWebSocketConnected(session);
- verify(webSocketTestSessionState.listener, times(1)).addSubscriber(any());
+ verify(stream).addSubscriber(any(), any(), any());
}
@Test
- public void onWebSocketClosedWithOpenSession() {
- final WebSocketTestSessionState webSocketTestSessionState = new WebSocketTestSessionState(200, 10000);
- final Session session = mock(Session.class);
+ void onWebSocketClosedWithOpenSession() throws Exception {
+ final var webSocketTestSessionState = new WebSocketTestSessionState(200, 10000);
+ final var reg = mock(Registration.class);
+ doReturn(reg).when(stream).addSubscriber(webSocketTestSessionState.webSocketSessionHandler, ENCODING, null);
webSocketTestSessionState.webSocketSessionHandler.onWebSocketConnected(session);
- verify(webSocketTestSessionState.listener).addSubscriber(
- webSocketTestSessionState.webSocketSessionHandler);
webSocketTestSessionState.webSocketSessionHandler.onWebSocketClosed(200, "Simulated close");
- verify(webSocketTestSessionState.listener).removeSubscriber(
- webSocketTestSessionState.webSocketSessionHandler);
+ verify(reg).close();
}
@Test
- public void onWebSocketClosedWithNotInitialisedSession() {
- final WebSocketTestSessionState webSocketTestSessionState = new WebSocketTestSessionState(300, 12000);
+ void onWebSocketClosedWithNotInitialisedSession() {
+ final var webSocketTestSessionState = new WebSocketTestSessionState(0, 0);
webSocketTestSessionState.webSocketSessionHandler.onWebSocketClosed(500, "Simulated close");
- verifyNoMoreInteractions(webSocketTestSessionState.listener);
+ verifyNoMoreInteractions(stream);
}
@Test
- public void onWebSocketErrorWithEnabledPingAndLivingSession() {
- final WebSocketTestSessionState webSocketTestSessionState = new WebSocketTestSessionState(150, 8000);
- final Session session = mock(Session.class);
+ void onWebSocketErrorWithEnabledPingAndLivingSession() throws Exception {
+ final var webSocketTestSessionState = new WebSocketTestSessionState(150, 8000);
+ final var reg = mock(Registration.class);
+
when(session.isOpen()).thenReturn(true);
- final Throwable sampleError = new IllegalStateException("Simulated error");
+ when(stream.addSubscriber(webSocketTestSessionState.webSocketSessionHandler, ENCODING, null))
+ .thenReturn(reg);
webSocketTestSessionState.webSocketSessionHandler.onWebSocketConnected(session);
- when(webSocketTestSessionState.pingFuture.isCancelled()).thenReturn(false);
- when(webSocketTestSessionState.pingFuture.isDone()).thenReturn(false);
+ final var sampleError = new IllegalStateException("Simulated error");
+ doNothing().when(reg).close();
+ doNothing().when(pingRegistration).close();
webSocketTestSessionState.webSocketSessionHandler.onWebSocketError(sampleError);
- verify(webSocketTestSessionState.listener).removeSubscriber(
- webSocketTestSessionState.webSocketSessionHandler);
verify(session).close();
- verify(webSocketTestSessionState.pingFuture).cancel(anyBoolean());
}
@Test
- public void onWebSocketErrorWithEnabledPingAndDeadSession() {
- final WebSocketTestSessionState webSocketTestSessionState = new WebSocketTestSessionState(150, 8000);
- final Session session = mock(Session.class);
+ void onWebSocketErrorWithEnabledPingAndDeadSession() throws Exception {
+ final var webSocketTestSessionState = new WebSocketTestSessionState(150, 8000);
+ final var reg = mock(Registration.class);
+
when(session.isOpen()).thenReturn(false);
- final Throwable sampleError = new IllegalStateException("Simulated error");
+ when(stream.addSubscriber(webSocketTestSessionState.webSocketSessionHandler, ENCODING, null))
+ .thenReturn(reg);
webSocketTestSessionState.webSocketSessionHandler.onWebSocketConnected(session);
+ final var sampleError = new IllegalStateException("Simulated error");
+ doNothing().when(reg).close();
+ doNothing().when(pingRegistration).close();
webSocketTestSessionState.webSocketSessionHandler.onWebSocketError(sampleError);
- verify(webSocketTestSessionState.listener).removeSubscriber(
- webSocketTestSessionState.webSocketSessionHandler);
verify(session, never()).close();
- verify(webSocketTestSessionState.pingFuture).cancel(anyBoolean());
}
@Test
- public void onWebSocketErrorWithDisabledPingAndDeadSession() {
- final WebSocketTestSessionState webSocketTestSessionState = new WebSocketTestSessionState(150, 8000);
- final Session session = mock(Session.class);
+ void onWebSocketErrorWithDisabledPingAndDeadSession() throws Exception {
+ final var webSocketTestSessionState = new WebSocketTestSessionState(150, 8000);
+ final var reg = mock(Registration.class);
+
when(session.isOpen()).thenReturn(false);
- final Throwable sampleError = new IllegalStateException("Simulated error");
+ when(stream.addSubscriber(webSocketTestSessionState.webSocketSessionHandler, ENCODING, null))
+ .thenReturn(reg);
webSocketTestSessionState.webSocketSessionHandler.onWebSocketConnected(session);
- when(webSocketTestSessionState.pingFuture.isCancelled()).thenReturn(false);
- when(webSocketTestSessionState.pingFuture.isDone()).thenReturn(true);
+ final var sampleError = new IllegalStateException("Simulated error");
webSocketTestSessionState.webSocketSessionHandler.onWebSocketError(sampleError);
- verify(webSocketTestSessionState.listener).removeSubscriber(
- webSocketTestSessionState.webSocketSessionHandler);
+ verify(reg).close();
verify(session, never()).close();
- verify(webSocketTestSessionState.pingFuture, never()).cancel(anyBoolean());
}
@Test
- public void sendDataMessageWithDisabledFragmentation() throws IOException {
- final WebSocketTestSessionState webSocketTestSessionState = new WebSocketTestSessionState(0, 0);
- final Session session = mock(Session.class);
- final RemoteEndpoint remoteEndpoint = mock(RemoteEndpoint.class);
+ void sendDataMessageWithDisabledFragmentation() throws Exception {
+ final var webSocketTestSessionState = new WebSocketTestSessionState(0, 0);
+ final var remoteEndpoint = mock(RemoteEndpoint.class);
when(session.isOpen()).thenReturn(true);
when(session.getRemote()).thenReturn(remoteEndpoint);
webSocketTestSessionState.webSocketSessionHandler.onWebSocketConnected(session);
}
@Test
- public void sendDataMessageWithDisabledFragAndDeadSession() {
- final WebSocketTestSessionState webSocketTestSessionState = new WebSocketTestSessionState(0, 0);
- final Session session = mock(Session.class);
- final RemoteEndpoint remoteEndpoint = mock(RemoteEndpoint.class);
+ void sendDataMessageWithDisabledFragAndDeadSession() {
+ final var webSocketTestSessionState = new WebSocketTestSessionState(0, 0);
+ final var remoteEndpoint = mock(RemoteEndpoint.class);
when(session.isOpen()).thenReturn(false);
- when(session.getRemote()).thenReturn(remoteEndpoint);
webSocketTestSessionState.webSocketSessionHandler.onWebSocketConnected(session);
final String testMessage = generateRandomStringOfLength(11);
}
@Test
- public void sendDataMessageWithEnabledFragAndSmallMessage() throws IOException {
- final WebSocketTestSessionState webSocketTestSessionState = new WebSocketTestSessionState(100, 0);
- final Session session = mock(Session.class);
- final RemoteEndpoint remoteEndpoint = mock(RemoteEndpoint.class);
+ void sendDataMessageWithEnabledFragAndSmallMessage() throws Exception {
+ final var webSocketTestSessionState = new WebSocketTestSessionState(100, 0);
+ final var remoteEndpoint = mock(RemoteEndpoint.class);
when(session.isOpen()).thenReturn(true);
when(session.getRemote()).thenReturn(remoteEndpoint);
webSocketTestSessionState.webSocketSessionHandler.onWebSocketConnected(session);
}
@Test
- public void sendDataMessageWithZeroLength() {
- final WebSocketTestSessionState webSocketTestSessionState = new WebSocketTestSessionState(100, 0);
- final Session session = mock(Session.class);
- final RemoteEndpoint remoteEndpoint = mock(RemoteEndpoint.class);
- when(session.isOpen()).thenReturn(true);
- when(session.getRemote()).thenReturn(remoteEndpoint);
+ void sendDataMessageWithZeroLength() {
+ final var webSocketTestSessionState = new WebSocketTestSessionState(100, 0);
+ final var remoteEndpoint = mock(RemoteEndpoint.class);
webSocketTestSessionState.webSocketSessionHandler.onWebSocketConnected(session);
webSocketTestSessionState.webSocketSessionHandler.sendDataMessage("");
}
@Test
- public void sendDataMessageWithEnabledFragAndLargeMessage1() throws IOException {
- final WebSocketTestSessionState webSocketTestSessionState = new WebSocketTestSessionState(100, 0);
- final Session session = mock(Session.class);
- final RemoteEndpoint remoteEndpoint = mock(RemoteEndpoint.class);
+ void sendDataMessageWithEnabledFragAndLargeMessage1() throws Exception {
+ final var webSocketTestSessionState = new WebSocketTestSessionState(100, 0);
+ final var remoteEndpoint = mock(RemoteEndpoint.class);
when(session.isOpen()).thenReturn(true);
when(session.getRemote()).thenReturn(remoteEndpoint);
webSocketTestSessionState.webSocketSessionHandler.onWebSocketConnected(session);
// there should be 10 fragments of length 100 characters
final String testMessage = generateRandomStringOfLength(1000);
webSocketTestSessionState.webSocketSessionHandler.sendDataMessage(testMessage);
- final ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
- final ArgumentCaptor<Boolean> isLastCaptor = ArgumentCaptor.forClass(Boolean.class);
+ final var messageCaptor = ArgumentCaptor.forClass(String.class);
+ final var isLastCaptor = ArgumentCaptor.forClass(Boolean.class);
verify(remoteEndpoint, times(10)).sendPartialString(
messageCaptor.capture(), isLastCaptor.capture());
- final List<String> allMessages = messageCaptor.getAllValues();
- final List<Boolean> isLastFlags = isLastCaptor.getAllValues();
+ final var allMessages = messageCaptor.getAllValues();
+ final var isLastFlags = isLastCaptor.getAllValues();
assertTrue(allMessages.stream().allMatch(s -> s.length() == webSocketTestSessionState.maxFragmentSize));
assertTrue(isLastFlags.subList(0, 9).stream().noneMatch(isLast -> isLast));
assertTrue(isLastFlags.get(9));
}
@Test
- public void sendDataMessageWithEnabledFragAndLargeMessage2() throws IOException {
- final WebSocketTestSessionState webSocketTestSessionState = new WebSocketTestSessionState(100, 0);
- final Session session = mock(Session.class);
- final RemoteEndpoint remoteEndpoint = mock(RemoteEndpoint.class);
+ void sendDataMessageWithEnabledFragAndLargeMessage2() throws Exception {
+ final var webSocketTestSessionState = new WebSocketTestSessionState(100, 0);
+ final var remoteEndpoint = mock(RemoteEndpoint.class);
when(session.isOpen()).thenReturn(true);
when(session.getRemote()).thenReturn(remoteEndpoint);
webSocketTestSessionState.webSocketSessionHandler.onWebSocketConnected(session);
// there should be 10 fragments, the last fragment should be the shortest one
final String testMessage = generateRandomStringOfLength(950);
webSocketTestSessionState.webSocketSessionHandler.sendDataMessage(testMessage);
- final ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
- final ArgumentCaptor<Boolean> isLastCaptor = ArgumentCaptor.forClass(Boolean.class);
+ final var messageCaptor = ArgumentCaptor.forClass(String.class);
+ final var isLastCaptor = ArgumentCaptor.forClass(Boolean.class);
verify(remoteEndpoint, times(10)).sendPartialString(
messageCaptor.capture(), isLastCaptor.capture());
- final List<String> allMessages = messageCaptor.getAllValues();
- final List<Boolean> isLastFlags = isLastCaptor.getAllValues();
+ final var allMessages = messageCaptor.getAllValues();
+ final var isLastFlags = isLastCaptor.getAllValues();
assertTrue(allMessages.subList(0, 9).stream().allMatch(s ->
s.length() == webSocketTestSessionState.maxFragmentSize));
assertEquals(50, allMessages.get(9).length());
private static String generateRandomStringOfLength(final int length) {
final String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvxyz";
- final StringBuilder sb = new StringBuilder(length);
+ final var sb = new StringBuilder(length);
for (int i = 0; i < length; i++) {
int index = (int) (alphabet.length() * Math.random());
sb.append(alphabet.charAt(index));