Introduce restconf.server.{api,spi,mdsal}
[netconf.git] / restconf / restconf-nb / src / test / java / org / opendaylight / restconf / nb / rfc8040 / streams / WebSocketSessionHandlerTest.java
index b8c1da9fcbcb68c4817ab040bdbe1e5178fa4460..cc385d9fe0a4e0c62b4393dab908946afddd998c 100644 (file)
@@ -7,12 +7,14 @@
  */
 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;
@@ -20,153 +22,153 @@ import static org.mockito.Mockito.verify;
 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);
@@ -177,12 +179,10 @@ public class WebSocketSessionHandlerTest {
     }
 
     @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);
@@ -191,10 +191,9 @@ public class WebSocketSessionHandlerTest {
     }
 
     @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);
@@ -210,12 +209,9 @@ public class WebSocketSessionHandlerTest {
     }
 
     @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("");
@@ -223,10 +219,9 @@ public class WebSocketSessionHandlerTest {
     }
 
     @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);
@@ -234,23 +229,22 @@ public class WebSocketSessionHandlerTest {
         // 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);
@@ -258,13 +252,13 @@ public class WebSocketSessionHandlerTest {
         // 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());
@@ -274,7 +268,7 @@ public class WebSocketSessionHandlerTest {
 
     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));