improvements to the jetty-websocket configuration testing

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan Roberts 2019-05-16 15:43:22 +10:00
parent c68a1b6066
commit 455cc3d2e2
4 changed files with 385 additions and 109 deletions

View File

@ -148,8 +148,7 @@ public class JettyWebSocketFrameHandler implements FrameHandler
textSink = JettyWebSocketFrameHandlerFactory.createMessageSink(textHandle, textSinkClass, executor, coreSession.getMaxTextMessageSize());
if (binaryHandle != null)
binarySink = JettyWebSocketFrameHandlerFactory
.createMessageSink(binaryHandle, binarySinkClass, executor, coreSession.getMaxBinaryMessageSize());
binarySink = JettyWebSocketFrameHandlerFactory.createMessageSink(binaryHandle, binarySinkClass, executor, coreSession.getMaxBinaryMessageSize());
if (openHandle != null)
openHandle.invoke();

View File

@ -74,7 +74,7 @@ public class JettyWebSocketServletFactory
public long getMaxBinaryMessageSize()
{
return factory.getMaxFrameSize();
return factory.getMaxBinaryMessageSize();
}
public void setMaxBinaryMessageSize(long bufferSize)
@ -89,7 +89,7 @@ public class JettyWebSocketServletFactory
public void setMaxTextMessageSize(long bufferSize)
{
factory.setMaxBinaryMessageSize(bufferSize);
factory.setMaxTextMessageSize(bufferSize);
}
public int getOutputBufferSize()

View File

@ -22,6 +22,7 @@ import java.net.URI;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
@ -30,6 +31,7 @@ import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.websocket.api.BatchMode;
import org.eclipse.jetty.websocket.api.MessageTooLargeException;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.api.WebSocketTimeoutException;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.client.WebSocketClient;
@ -42,7 +44,9 @@ import org.eclipse.jetty.websocket.tests.EchoSocket;
import org.eclipse.jetty.websocket.tests.EventSocket;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.instanceOf;
@ -54,19 +58,25 @@ public class ClientConfigTest
{
private Server server;
private WebSocketClient client;
private ServerConnector connector;
private EchoSocket serverSocket = new EchoSocket();
private static String message = "this message is over 20 characters long";
private final int inputBufferSize = 200;
private final int maxMessageSize = 20;
private final int idleTimeout = 500;
public static Stream<Arguments> data()
{
return Stream.of("clientConfig", "annotatedConfig", "sessionConfig").map(Arguments::of);
}
@BeforeEach
public void start() throws Exception
{
server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(8080);
connector = new ServerConnector(server);
server.addConnector(connector);
ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
@ -74,7 +84,7 @@ public class ClientConfigTest
server.setHandler(contextHandler);
JettyWebSocketServerContainer container = JettyWebSocketServletContainerInitializer.configureContext(contextHandler);
container.addMapping("/", (req, resp)->new EchoSocket());
container.addMapping("/", (req, resp)->serverSocket);
server.start();
client = new WebSocketClient();
@ -93,13 +103,48 @@ public class ClientConfigTest
{
}
@Test
public void testInputBufferSize() throws Exception
@WebSocket
public class SessionConfigEndpoint extends EventSocket
{
client.setInputBufferSize(inputBufferSize);
@Override
public void onOpen(Session session)
{
session.setIdleTimeout(Duration.ofMillis(idleTimeout));
session.setMaxTextMessageSize(maxMessageSize);
session.setMaxBinaryMessageSize(maxMessageSize);
session.setInputBufferSize(inputBufferSize);
super.onOpen(session);
}
}
URI uri = URI.create("ws://localhost:8080/");
EventSocket clientEndpoint = new EventSocket();
public EventSocket getClientSocket(String param)
{
switch (param)
{
case "clientConfig":
client.setInputBufferSize(inputBufferSize);
client.setMaxBinaryMessageSize(maxMessageSize);
client.setIdleTimeout(Duration.ofMillis(idleTimeout));
client.setMaxTextMessageSize(maxMessageSize);
return new EventSocket();
case "annotatedConfig":
return new AnnotatedConfigEndpoint();
case "sessionConfig":
return new SessionConfigEndpoint();
default:
throw new IllegalStateException();
}
}
@ParameterizedTest
@MethodSource("data")
public void testInputBufferSize(String param) throws Exception
{
URI uri = URI.create("ws://localhost:" + connector.getLocalPort() + "/");
EventSocket clientEndpoint = getClientSocket(param);
CompletableFuture<Session> connect = client.connect(clientEndpoint, uri);
connect.get(5, TimeUnit.SECONDS);
@ -112,15 +157,17 @@ public class ClientConfigTest
clientEndpoint.session.close();
assertTrue(clientEndpoint.closeLatch.await(5, TimeUnit.SECONDS));
assertNull(clientEndpoint.error);
assertTrue(serverSocket.closeLatch.await(5, TimeUnit.SECONDS));
assertThat(serverSocket.statusCode, is(StatusCode.NO_CODE));
}
@Test
public void testMaxBinaryMessageSize() throws Exception
@ParameterizedTest
@MethodSource("data")
public void testMaxBinaryMessageSize(String param) throws Exception
{
client.setMaxBinaryMessageSize(maxMessageSize);
URI uri = URI.create("ws://localhost:8080/");
EventSocket clientEndpoint = new EventSocket();
URI uri = URI.create("ws://localhost:" + connector.getLocalPort() + "/");
EventSocket clientEndpoint = getClientSocket(param);
CompletableFuture<Session> connect = client.connect(clientEndpoint, uri);
connect.get(5, TimeUnit.SECONDS);
@ -128,15 +175,17 @@ public class ClientConfigTest
assertTrue(clientEndpoint.closeLatch.await(5, TimeUnit.SECONDS));
assertThat(clientEndpoint.error, instanceOf(MessageTooLargeException.class));
assertTrue(serverSocket.closeLatch.await(5, TimeUnit.SECONDS));
assertThat(serverSocket.statusCode, is(StatusCode.MESSAGE_TOO_LARGE));
}
@Test
public void testMaxIdleTime() throws Exception
@ParameterizedTest
@MethodSource("data")
public void testMaxIdleTime(String param) throws Exception
{
client.setIdleTimeout(Duration.ofMillis(idleTimeout));
URI uri = URI.create("ws://localhost:8080/");
EventSocket clientEndpoint = new EventSocket();
URI uri = URI.create("ws://localhost:" + connector.getLocalPort() + "/");
EventSocket clientEndpoint = getClientSocket(param);
CompletableFuture<Session> connect = client.connect(clientEndpoint, uri);
connect.get(5, TimeUnit.SECONDS);
@ -145,15 +194,17 @@ public class ClientConfigTest
assertTrue(clientEndpoint.closeLatch.await(5, TimeUnit.SECONDS));
assertThat(clientEndpoint.error, instanceOf(WebSocketTimeoutException.class));
assertTrue(serverSocket.closeLatch.await(5, TimeUnit.SECONDS));
assertThat(serverSocket.statusCode, is(StatusCode.SHUTDOWN));
}
@Test
public void testMaxTextMessageSize() throws Exception
@ParameterizedTest
@MethodSource("data")
public void testMaxTextMessageSize(String param) throws Exception
{
client.setMaxTextMessageSize(maxMessageSize);
URI uri = URI.create("ws://localhost:8080/");
EventSocket clientEndpoint = new EventSocket();
URI uri = URI.create("ws://localhost:" + connector.getLocalPort() + "/");
EventSocket clientEndpoint = getClientSocket(param);
CompletableFuture<Session> connect = client.connect(clientEndpoint, uri);
connect.get(5, TimeUnit.SECONDS);
@ -161,83 +212,8 @@ public class ClientConfigTest
assertTrue(clientEndpoint.closeLatch.await(5, TimeUnit.SECONDS));
assertThat(clientEndpoint.error, instanceOf(MessageTooLargeException.class));
}
@Test
public void testInputBufferSizeAnnotation() throws Exception
{
URI uri = URI.create("ws://localhost:8080/");
AnnotatedConfigEndpoint clientEndpoint = new AnnotatedConfigEndpoint();
CompletableFuture<Session> connect = client.connect(clientEndpoint, uri);
connect.get(5, TimeUnit.SECONDS);
WebSocketChannel channel = (WebSocketChannel)((WebSocketSession)clientEndpoint.session).getCoreSession();
WebSocketConnection connection = channel.getConnection();
assertThat(connection.getInputBufferSize(), is(inputBufferSize));
clientEndpoint.session.close();
assertTrue(clientEndpoint.closeLatch.await(5, TimeUnit.SECONDS));
assertNull(clientEndpoint.error);
}
@Test
public void testMaxBinaryMessageSizeAnnotation() throws Exception
{
URI uri = URI.create("ws://localhost:8080/");
AnnotatedConfigEndpoint clientEndpoint = new AnnotatedConfigEndpoint();
CompletableFuture<Session> connect = client.connect(clientEndpoint, uri);
connect.get(5, TimeUnit.SECONDS);
clientEndpoint.session.getRemote().sendBytes(BufferUtil.toBuffer(message));
assertTrue(clientEndpoint.closeLatch.await(5, TimeUnit.SECONDS));
assertThat(clientEndpoint.error, instanceOf(MessageTooLargeException.class));
}
@Test
public void testMaxIdleTimeAnnotation() throws Exception
{
URI uri = URI.create("ws://localhost:8080/");
AnnotatedConfigEndpoint clientEndpoint = new AnnotatedConfigEndpoint();
CompletableFuture<Session> connect = client.connect(clientEndpoint, uri);
connect.get(5, TimeUnit.SECONDS);
clientEndpoint.session.getRemote().sendString("hello world");
Thread.sleep(idleTimeout + 500);
assertTrue(clientEndpoint.closeLatch.await(5, TimeUnit.SECONDS));
assertThat(clientEndpoint.error, instanceOf(WebSocketTimeoutException.class));
}
@Test
public void testMaxTextMessageSizeAnnotation() throws Exception
{
URI uri = URI.create("ws://localhost:8080/");
AnnotatedConfigEndpoint clientEndpoint = new AnnotatedConfigEndpoint();
CompletableFuture<Session> connect = client.connect(clientEndpoint, uri);
connect.get(5, TimeUnit.SECONDS);
clientEndpoint.session.getRemote().sendString(message);
assertTrue(clientEndpoint.closeLatch.await(5, TimeUnit.SECONDS));
assertThat(clientEndpoint.error, instanceOf(MessageTooLargeException.class));
}
@Test
public void testBatchModeAnnotation() throws Exception
{
URI uri = URI.create("ws://localhost:8080/");
AnnotatedConfigEndpoint clientEndpoint = new AnnotatedConfigEndpoint();
CompletableFuture<Session> connect = client.connect(clientEndpoint, uri);
connect.get(5, TimeUnit.SECONDS);
assertThat(clientEndpoint.session.getRemote().getBatchMode(), is(BatchMode.ON));
clientEndpoint.session.close();
assertTrue(clientEndpoint.closeLatch.await(5, TimeUnit.SECONDS));
assertNull(clientEndpoint.error);
assertTrue(serverSocket.closeLatch.await(5, TimeUnit.SECONDS));
assertThat(serverSocket.statusCode, is(StatusCode.MESSAGE_TOO_LARGE));
}
}

View File

@ -0,0 +1,301 @@
//
// ========================================================================
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.websocket.tests.server;
import java.net.URI;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.websocket.api.BatchMode;
import org.eclipse.jetty.websocket.api.MessageTooLargeException;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.api.WebSocketTimeoutException;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.eclipse.jetty.websocket.common.WebSocketSession;
import org.eclipse.jetty.websocket.core.internal.WebSocketChannel;
import org.eclipse.jetty.websocket.core.internal.WebSocketConnection;
import org.eclipse.jetty.websocket.server.JettyWebSocketServerContainer;
import org.eclipse.jetty.websocket.server.JettyWebSocketServlet;
import org.eclipse.jetty.websocket.server.JettyWebSocketServletContainerInitializer;
import org.eclipse.jetty.websocket.server.JettyWebSocketServletFactory;
import org.eclipse.jetty.websocket.tests.EventSocket;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ServerConfigTest
{
private Server server;
private WebSocketClient client;
private ServerConnector connector;
private ConnectionListener listener = new ConnectionListener();
private static String message = "this message is over 20 characters long";
private final static int inputBufferSize = 200;
private final static int maxMessageSize = 20;
private final static int idleTimeout = 500;
private EventSocket annotatedEndpoint = new AnnotatedConfigEndpoint();
private EventSocket sessionConfigEndpoint = new SessionConfigEndpoint();
private EventSocket standardEndpoint = new EventSocket();
private EventSocket getServerEndpoint(String path)
{
switch (path)
{
case "servletConfig":
case "containerConfig":
return standardEndpoint;
case "annotatedConfig":
return annotatedEndpoint;
case "sessionConfig":
return sessionConfigEndpoint;
default:
throw new IllegalStateException();
}
}
public static Stream<Arguments> data()
{
return Stream.of("servletConfig", "annotatedConfig", "containerConfig", "sessionConfig").map(Arguments::of);
}
@WebSocket(maxIdleTime=idleTimeout, maxTextMessageSize=maxMessageSize, maxBinaryMessageSize=maxMessageSize, inputBufferSize=inputBufferSize, batchMode=BatchMode.ON)
public static class AnnotatedConfigEndpoint extends EventSocket
{
}
@WebSocket
public static class SessionConfigEndpoint extends EventSocket
{
@Override
public void onOpen(Session session)
{
session.setIdleTimeout(Duration.ofMillis(idleTimeout));
session.setMaxTextMessageSize(maxMessageSize);
session.setMaxBinaryMessageSize(maxMessageSize);
session.setInputBufferSize(inputBufferSize);
super.onOpen(session);
}
}
public class WebSocketFactoryConfigServlet extends JettyWebSocketServlet
{
@Override
public void configure(JettyWebSocketServletFactory factory)
{
factory.setIdleTimeout(Duration.ofMillis(idleTimeout));
factory.setMaxTextMessageSize(maxMessageSize);
factory.setMaxBinaryMessageSize(maxMessageSize);
factory.setInputBufferSize(inputBufferSize);
factory.addMapping("/",(req, resp)->standardEndpoint);
}
}
public class WebSocketAnnotatedConfigServlet extends JettyWebSocketServlet
{
@Override
public void configure(JettyWebSocketServletFactory factory)
{
factory.addMapping("/",(req, resp)->annotatedEndpoint);
}
}
public class WebSocketSessionConfigServlet extends JettyWebSocketServlet
{
@Override
public void configure(JettyWebSocketServletFactory factory)
{
factory.addMapping("/",(req, resp)->sessionConfigEndpoint);
}
}
public class ConnectionListener implements Connection.Listener
{
private AtomicInteger opened = new AtomicInteger(0);
private CountDownLatch closed = new CountDownLatch(1);
@Override
public void onOpened(Connection connection)
{
if (connection instanceof WebSocketConnection)
opened.incrementAndGet();
}
@Override
public void onClosed(Connection connection)
{
if (connection instanceof WebSocketConnection)
closed.countDown();
}
public void assertClosed() throws Exception
{
assertTrue(closed.await(5, TimeUnit.SECONDS));
assertThat(opened.get(), is(1));
}
}
@BeforeEach
public void start() throws Exception
{
server = new Server();
connector = new ServerConnector(server);
connector.addBean(listener);
server.addConnector(connector);
ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
contextHandler.setContextPath("/");
contextHandler.addServlet(new ServletHolder(new WebSocketFactoryConfigServlet()), "/servletConfig");
contextHandler.addServlet(new ServletHolder(new WebSocketAnnotatedConfigServlet()), "/annotatedConfig");
contextHandler.addServlet(new ServletHolder(new WebSocketSessionConfigServlet()), "/sessionConfig");
server.setHandler(contextHandler);
JettyWebSocketServerContainer container = JettyWebSocketServletContainerInitializer.configureContext(contextHandler);
container.setIdleTimeout(Duration.ofMillis(idleTimeout));
container.setMaxTextMessageSize(maxMessageSize);
container.setMaxBinaryMessageSize(maxMessageSize);
container.setInputBufferSize(inputBufferSize);
container.addMapping("/containerConfig", (req, resp)->standardEndpoint);
server.start();
client = new WebSocketClient();
client.start();
}
@AfterEach
public void stop() throws Exception
{
client.stop();
server.stop();
}
@ParameterizedTest
@MethodSource("data")
public void testInputBufferSize(String path) throws Exception
{
URI uri = URI.create("ws://localhost:" + connector.getLocalPort() + "/" + path);
EventSocket clientEndpoint = new EventSocket();
EventSocket serverEndpoint = getServerEndpoint(path);
CompletableFuture<Session> connect = client.connect(clientEndpoint, uri);
connect.get(5, TimeUnit.SECONDS);
WebSocketChannel channel = (WebSocketChannel)((WebSocketSession)serverEndpoint.session).getCoreSession();
WebSocketConnection connection = channel.getConnection();
assertThat(connection.getInputBufferSize(), is(inputBufferSize));
serverEndpoint.session.close();
assertTrue(serverEndpoint.closeLatch.await(5, TimeUnit.SECONDS));
assertNull(serverEndpoint.error);
assertTrue(clientEndpoint.closeLatch.await(5, TimeUnit.SECONDS));
assertThat(clientEndpoint.statusCode, is(StatusCode.NO_CODE));
listener.assertClosed();
}
@ParameterizedTest
@MethodSource("data")
public void testMaxBinaryMessageSize(String path) throws Exception
{
URI uri = URI.create("ws://localhost:" + connector.getLocalPort() + "/" + path);
EventSocket clientEndpoint = new EventSocket();
EventSocket serverEndpoint = getServerEndpoint(path);
CompletableFuture<Session> connect = client.connect(clientEndpoint, uri);
connect.get(5, TimeUnit.SECONDS);
clientEndpoint.session.getRemote().sendBytes(BufferUtil.toBuffer(message));
assertTrue(serverEndpoint.closeLatch.await(5, TimeUnit.SECONDS));
assertThat(serverEndpoint.error, instanceOf(MessageTooLargeException.class));
assertTrue(clientEndpoint.closeLatch.await(5, TimeUnit.SECONDS));
assertThat(clientEndpoint.statusCode, is(StatusCode.MESSAGE_TOO_LARGE));
listener.assertClosed();
}
@ParameterizedTest
@MethodSource("data")
public void testMaxIdleTime(String path) throws Exception
{
URI uri = URI.create("ws://localhost:" + connector.getLocalPort() + "/" + path);
EventSocket clientEndpoint = new EventSocket();
EventSocket serverEndpoint = getServerEndpoint(path);
CompletableFuture<Session> connect = client.connect(clientEndpoint, uri);
connect.get(5, TimeUnit.SECONDS);
clientEndpoint.session.getRemote().sendString("hello world");
String msg = serverEndpoint.messageQueue.poll(500, TimeUnit.MILLISECONDS);
assertThat(msg, is("hello world"));
Thread.sleep(idleTimeout + 500);
assertTrue(serverEndpoint.closeLatch.await(5, TimeUnit.SECONDS));
assertThat(serverEndpoint.error, instanceOf(WebSocketTimeoutException.class));
assertTrue(clientEndpoint.closeLatch.await(5, TimeUnit.SECONDS));
assertThat(clientEndpoint.statusCode, is(StatusCode.SHUTDOWN));
listener.assertClosed();
}
@ParameterizedTest
@MethodSource("data")
public void testMaxTextMessageSize(String path) throws Exception
{
URI uri = URI.create("ws://localhost:" + connector.getLocalPort() + "/" + path);
EventSocket clientEndpoint = new EventSocket();
EventSocket serverEndpoint = getServerEndpoint(path);
CompletableFuture<Session> connect = client.connect(clientEndpoint, uri);
connect.get(5, TimeUnit.SECONDS);
clientEndpoint.session.getRemote().sendString(message);
assertTrue(serverEndpoint.closeLatch.await(5, TimeUnit.SECONDS));
assertThat(serverEndpoint.error, instanceOf(MessageTooLargeException.class));
assertTrue(clientEndpoint.closeLatch.await(5, TimeUnit.SECONDS));
assertThat(clientEndpoint.statusCode, is(StatusCode.MESSAGE_TOO_LARGE));
listener.assertClosed();
}
}