This is an automated email from the ASF dual-hosted git repository. remm pushed a commit to branch 10.1.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 245710c973e639e4bc232e0c98a584436db0d69c Author: Dimitris Soumis <jimsou...@gmail.com> AuthorDate: Sun Jun 23 03:00:09 2024 +0300 Increase test coverage of WsServerContainer --- .../catalina/filters/TesterHttpServletRequest.java | 63 ++++- .../websocket/server/TestWsServerContainer.java | 307 ++++++++++++++++++++- 2 files changed, 346 insertions(+), 24 deletions(-) diff --git a/test/org/apache/catalina/filters/TesterHttpServletRequest.java b/test/org/apache/catalina/filters/TesterHttpServletRequest.java index 449963e6ec..2f24746cfa 100644 --- a/test/org/apache/catalina/filters/TesterHttpServletRequest.java +++ b/test/org/apache/catalina/filters/TesterHttpServletRequest.java @@ -19,6 +19,7 @@ package org.apache.catalina.filters; import java.io.BufferedReader; import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.lang.reflect.InvocationTargetException; import java.security.Principal; import java.util.ArrayList; import java.util.Collection; @@ -49,8 +50,8 @@ import jakarta.servlet.http.PushBuilder; public class TesterHttpServletRequest implements HttpServletRequest { - private Map<String, Object> attributes = new HashMap<>(); - private Map<String, List<String>> headers = new HashMap<>(); + private final Map<String, Object> attributes = new HashMap<>(); + private final Map<String, List<String>> headers = new HashMap<>(); private String method; private String scheme; private String serverName; @@ -111,9 +112,14 @@ public class TesterHttpServletRequest implements HttpServletRequest { throw new RuntimeException("Not implemented"); } + /** + * {@inheritDoc} + * <p> + * This test implementation is hard coded to return an empty Hashmap. + */ @Override public Map<String, String[]> getParameterMap() { - throw new RuntimeException("Not implemented"); + return new HashMap<>(); } @Override @@ -184,9 +190,14 @@ public class TesterHttpServletRequest implements HttpServletRequest { throw new RuntimeException("Not implemented"); } + /** + * {@inheritDoc} + * <p> + * This test implementation is hard coded to return false. + */ @Override public boolean isSecure() { - throw new RuntimeException("Not implemented"); + return false; } @Override @@ -247,7 +258,7 @@ public class TesterHttpServletRequest implements HttpServletRequest { @Override public Enumeration<String> getHeaders(String name) { - throw new RuntimeException("Not implemented"); + return Collections.enumeration(headers.get(name)); } @Override @@ -289,9 +300,14 @@ public class TesterHttpServletRequest implements HttpServletRequest { throw new RuntimeException("Not implemented"); } + /** + * {@inheritDoc} + * <p> + * This test implementation is hard coded to return null. + */ @Override public String getQueryString() { - throw new RuntimeException("Not implemented"); + return null; } @Override @@ -304,9 +320,14 @@ public class TesterHttpServletRequest implements HttpServletRequest { throw new RuntimeException("Not implemented"); } + /** + * {@inheritDoc} + * <p> + * This test implementation is hard coded to return null. + */ @Override public Principal getUserPrincipal() { - throw new RuntimeException("Not implemented"); + return null; } @Override @@ -314,9 +335,14 @@ public class TesterHttpServletRequest implements HttpServletRequest { throw new RuntimeException("Not implemented"); } + /** + * {@inheritDoc} + * <p> + * This test implementation is hard coded to return null. + */ @Override public String getRequestURI() { - throw new RuntimeException("Not implemented"); + return null; } @Override @@ -329,9 +355,14 @@ public class TesterHttpServletRequest implements HttpServletRequest { throw new RuntimeException("Not implemented"); } + /** + * {@inheritDoc} + * <p> + * This test implementation is hard coded to return null. + */ @Override public HttpSession getSession(boolean create) { - throw new RuntimeException("Not implemented"); + return null; } @Override @@ -425,10 +456,20 @@ public class TesterHttpServletRequest implements HttpServletRequest { throw new RuntimeException("Not implemented"); } + /** + * {@inheritDoc} + * <p> + * This test implementation is hard coded to return a new instance of the httpUpgradeHandlerClass. + */ @Override public <T extends HttpUpgradeHandler> T upgrade(Class<T> httpUpgradeHandlerClass) - throws IOException, ServletException { - throw new RuntimeException("Not implemented"); + throws IOException, ServletException { + try { + return httpUpgradeHandlerClass.getDeclaredConstructor().newInstance(); + }catch (NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException ignore){ + + } + return null; } @Override diff --git a/test/org/apache/tomcat/websocket/server/TestWsServerContainer.java b/test/org/apache/tomcat/websocket/server/TestWsServerContainer.java index 8bc0094131..24bae4bd7a 100644 --- a/test/org/apache/tomcat/websocket/server/TestWsServerContainer.java +++ b/test/org/apache/tomcat/websocket/server/TestWsServerContainer.java @@ -16,30 +16,36 @@ */ package org.apache.tomcat.websocket.server; -import java.net.URI; -import java.util.Queue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import jakarta.websocket.ContainerProvider; -import jakarta.websocket.DeploymentException; -import jakarta.websocket.Session; -import jakarta.websocket.WebSocketContainer; +import jakarta.servlet.Filter; +import jakarta.servlet.FilterRegistration; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.websocket.*; import jakarta.websocket.server.ServerEndpoint; import jakarta.websocket.server.ServerEndpointConfig; - -import org.junit.Assert; -import org.junit.Test; - import org.apache.catalina.Context; import org.apache.catalina.LifecycleState; +import org.apache.catalina.filters.TesterHttpServletRequest; +import org.apache.catalina.filters.TesterHttpServletResponse; import org.apache.catalina.servlets.DefaultServlet; import org.apache.catalina.startup.Tomcat; import org.apache.tomcat.unittest.TesterServletContext; +import org.apache.tomcat.websocket.Constants; import org.apache.tomcat.websocket.TesterEchoServer; import org.apache.tomcat.websocket.TesterMessageCountClient.BasicText; import org.apache.tomcat.websocket.WebSocketBaseTest; import org.apache.tomcat.websocket.pojo.TesterUtil.SimpleClient; +import org.junit.Assert; +import org.junit.Test; + +import java.lang.reflect.Field; +import java.net.URI; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.concurrent.ConcurrentSkipListMap; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; public class TestWsServerContainer extends WebSocketBaseTest { @@ -135,6 +141,46 @@ public class TestWsServerContainer extends WebSocketBaseTest { Assert.assertEquals(configB, sc.findMapping("/b/d").getConfig()); } + @Test + public void testSpecExample5() throws Exception { + WsServerContainer sc = new WsServerContainer(new TesterServletContext()); + + ServerEndpointConfig configA = ServerEndpointConfig.Builder.create(Object.class, "/a").build(); + + sc.addEndpoint(configA); + + Assert.assertNull(sc.findMapping("invalidPath")); + } + + @Test + public void testSpecExample6() throws Exception { + WsServerContainer sc = new WsServerContainer(new TesterServletContext()); + + ServerEndpointConfig configA = ServerEndpointConfig.Builder.create(Object.class, "/a").build(); + + sc.addEndpoint(configA); + + Assert.assertNull(sc.findMapping("/b")); + } + + @Test + public void testSpecExample7() throws Exception { + WsServerContainer sc = new WsServerContainer(new TesterServletContext()); + + // Use reflection to set the configTemplateMatchMap field to have a key "2" with value an empty ConcurrentSkipListMap + Field configTemplateMatchMapField = WsServerContainer.class.getDeclaredField("configTemplateMatchMap"); + configTemplateMatchMapField.setAccessible(true); + @SuppressWarnings("unchecked") + Map<Integer, ConcurrentSkipListMap<String, Object>> configTemplateMatchMap = + (Map<Integer, ConcurrentSkipListMap<String, Object>>) configTemplateMatchMapField.get(sc); + + ConcurrentSkipListMap<String, Object> newSkipListMap = new ConcurrentSkipListMap<>(); + + configTemplateMatchMap.put(Integer.valueOf(2), newSkipListMap); + + Assert.assertNull(sc.findMapping("/a/0")); + } + @Test(expected = DeploymentException.class) public void testDuplicatePaths01() throws Exception { @@ -244,6 +290,43 @@ public class TestWsServerContainer extends WebSocketBaseTest { sc.addEndpoint(configA); } + @Test(expected = DeploymentException.class) + public void testDuplicatePaths15() throws Exception { + WsServerContainer sc = new WsServerContainer(new TesterServletContext()); + + ServerEndpointConfig configA = ServerEndpointConfig.Builder.create(Object.class, "/foo").build(); + + sc.addEndpoint(configA); + sc.addEndpoint(Pojo.class, true); + } + + @Test(expected = DeploymentException.class) + public void testDuplicatePaths16() throws Exception { + WsServerContainer sc = new WsServerContainer(new TesterServletContext()); + + ServerEndpointConfig configA = ServerEndpointConfig.Builder.create(Object.class, "/foo").build(); + + sc.addEndpoint(configA); + sc.addEndpoint(Pojo.class, false); + } + + @Test(expected = DeploymentException.class) + public void testDuplicatePaths17() throws Exception { + WsServerContainer sc = new WsServerContainer(new TesterServletContext()); + + sc.addEndpoint(Pojo.class, true); + sc.addEndpoint(Pojo.class, true); + } + + @Test(expected = DeploymentException.class) + public void testDuplicatePaths18() throws Exception { + WsServerContainer sc = new WsServerContainer(new TesterServletContext()); + + ServerEndpointConfig configA = ServerEndpointConfig.Builder.create(Object.class, "/foo").build(); + + sc.addEndpoint(Pojo.class, true); + sc.addEndpoint(configA, true); + } /* * Simulates a class that gets picked up for extending Endpoint and for being annotated. @@ -302,6 +385,43 @@ public class TestWsServerContainer extends WebSocketBaseTest { sc.addEndpoint(configA); } + @Test(expected = DeploymentException.class) + public void testDuplicatePaths25() throws Exception { + WsServerContainer sc = new WsServerContainer(new TesterServletContext()); + + ServerEndpointConfig configA = ServerEndpointConfig.Builder.create(Object.class, "/foo/{a}").build(); + + sc.addEndpoint(configA); + sc.addEndpoint(PojoTemplate.class, true); + } + + @Test(expected = DeploymentException.class) + public void testDuplicatePaths26() throws Exception { + WsServerContainer sc = new WsServerContainer(new TesterServletContext()); + + ServerEndpointConfig configA = ServerEndpointConfig.Builder.create(Object.class, "/foo/{a}").build(); + + sc.addEndpoint(configA); + sc.addEndpoint(PojoTemplate.class, false); + } + + @Test(expected = DeploymentException.class) + public void testDuplicatePaths27() throws Exception { + WsServerContainer sc = new WsServerContainer(new TesterServletContext()); + + sc.addEndpoint(PojoTemplate.class, true); + sc.addEndpoint(PojoTemplate.class, true); + } + + @Test(expected = DeploymentException.class) + public void testDuplicatePaths28() throws Exception { + WsServerContainer sc = new WsServerContainer(new TesterServletContext()); + + ServerEndpointConfig configA = ServerEndpointConfig.Builder.create(Object.class, "/foo/{a}").build(); + + sc.addEndpoint(PojoTemplate.class, true); + sc.addEndpoint(configA, true); + } @ServerEndpoint("/foo") public static class Pojo { @@ -312,4 +432,165 @@ public class TestWsServerContainer extends WebSocketBaseTest { public static class PojoTemplate { } + @Test + public void testUpgradeHttpToWebSocket01() throws Exception { + TesterHttpServletRequest request = new TesterHttpServletRequest(); + + request.setScheme("http"); + + request.setHeader(Constants.CONNECTION_HEADER_NAME, Constants.CONNECTION_HEADER_VALUE); + request.setHeader(Constants.WS_VERSION_HEADER_NAME, Constants.WS_VERSION_HEADER_VALUE); + //Random 16-byte value encoded in 24 base64 characters. + request.setHeader(Constants.WS_KEY_HEADER_NAME, "1b4pqvztbM4cor6UUZSDqw=="); + request.setHeader(Constants.WS_PROTOCOL_HEADER_NAME, "testProtocol"); + request.setHeader(Constants.WS_EXTENSIONS_HEADER_NAME, "testExtension"); + + HttpServletResponse response = new TesterHttpServletResponse(); + + ServerEndpointConfig sec = ServerEndpointConfig.Builder.create(Object.class, "/").subprotocols(List.of("testProtocol")).build(); + + WsServerContainer container = new WsServerContainer(new TesterServletContext()); + + container.upgradeHttpToWebSocket(request, response, sec, new HashMap<>()); + + Assert.assertEquals(Constants.UPGRADE_HEADER_VALUE, response.getHeader(Constants.UPGRADE_HEADER_NAME)); + Assert.assertEquals("aJvXj0bbnSSeXm32ngvbBilP0lE=", response.getHeader(HandshakeResponse.SEC_WEBSOCKET_ACCEPT)); + } + + @Test(expected = DeploymentException.class) + public void testUpgradeHttpToWebSocket02() throws Exception { + TesterHttpServletRequest request = new TesterHttpServletRequest(); + + request.setHeader(Constants.CONNECTION_HEADER_NAME, Constants.CONNECTION_HEADER_VALUE); + request.setHeader(Constants.WS_VERSION_HEADER_NAME, Constants.WS_VERSION_HEADER_VALUE); + //Random 16-byte value encoded in 24 base64 characters. + request.setHeader(Constants.WS_KEY_HEADER_NAME, "1b4pqvztbM4cor6UUZSDqw=="); + request.setHeader(Constants.WS_PROTOCOL_HEADER_NAME, "testProtocol"); + request.setHeader(Constants.WS_EXTENSIONS_HEADER_NAME, "testExtension"); + + HttpServletResponse response = new TesterHttpServletResponse(); + + ServerEndpointConfig sec = ServerEndpointConfig.Builder.create(Object.class, "/").decoders(List.of(DummyDecoder.class)).build(); + + WsServerContainer container = new WsServerContainer(new TesterServletContext()); + + container.upgradeHttpToWebSocket(request, response, sec, new HashMap<>()); + } + + private static class DummyDecoder implements Decoder { + public DummyDecoder(String ignoredParam) { + } + } + + @Test + public void testFilterRegistrationFailure() { + new WsServerContainer(new TesterServletContext(){ + @Override + public FilterRegistration.Dynamic addFilter(String filterName, Filter filter) { + return null; + } + }); + + } + + @Test(expected = DeploymentException.class) + public void testAddEndpointNullServletContext() throws Exception { + WsServerContainer sc = new WsServerContainer(new TesterServletContext()); + + ServerEndpointConfig configA = ServerEndpointConfig.Builder.create(Object.class, "/").build(); + + // Use reflection to set the servletContext field to null + Field servletContextField = WsServerContainer.class.getDeclaredField("servletContext"); + servletContextField.setAccessible(true); + servletContextField.set(sc, null); + + sc.addEndpoint(configA); + } + + @Test(expected = DeploymentException.class) + public void testAddEndpointDeploymentFailed01() throws Exception { + WsServerContainer sc = new WsServerContainer(new TesterServletContext()); + + ServerEndpointConfig configA = ServerEndpointConfig.Builder.create(Object.class, "/a/b/c").build(); + ServerEndpointConfig configB = ServerEndpointConfig.Builder.create(Object.class, "/a/b/c").build(); + + try { + sc.addEndpoint(configA); + sc.addEndpoint(configB); + }catch (DeploymentException ignore){ + sc.addEndpoint(configB); + } + + } + + @Test(expected = DeploymentException.class) + public void testAddEndpointDeploymentFailed02() throws Exception { + WsServerContainer sc = new WsServerContainer(new TesterServletContext()); + + try { + sc.addEndpoint(Pojo.class, true); + sc.addEndpoint(Pojo.class, true); + }catch (DeploymentException ignore){ + sc.addEndpoint(Pojo.class, true); + } + + } + + @Test(expected = DeploymentException.class) + public void testAddEndpointMissingAnnotationFromPojoClass() throws Exception { + WsServerContainer sc = new WsServerContainer(new TesterServletContext()); + + sc.addEndpoint(DummyPojo.class, true); + + } + + public static class DummyPojo { + } + + @Test(expected = DeploymentException.class) + public void testAddEndpointConfiguratorFail() throws Exception { + WsServerContainer sc = new WsServerContainer(new TesterServletContext()); + + sc.addEndpoint(DummyPojo2.class, true); + + } + + @ServerEndpoint(value = "/foo", configurator = DummyConfigurator.class) + public static class DummyPojo2 { + } + + private static class DummyConfigurator extends ServerEndpointConfig.Configurator { + public DummyConfigurator(String ignoredParam) { + } + + } + @Test + public void testValidateEncoders01() throws Exception { + WsServerContainer sc = new WsServerContainer(new TesterServletContext()); + + sc.addEndpoint(DummyPojo3.class); + + } + + @ServerEndpoint(value = "/foo", encoders = DummyEncoder.class) + public static class DummyPojo3 { + } + + private static class DummyEncoder implements Encoder { + public DummyEncoder() { + } + } + + @Test(expected = DeploymentException.class) + public void testValidateEncoders02() throws Exception { + WsServerContainer sc = new WsServerContainer(new TesterServletContext()); + + sc.addEndpoint(DummyPojo4.class); + + } + + @ServerEndpoint(value = "/foo", encoders = Encoder.class) + public static class DummyPojo4 { + } + } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org