diff --git a/test/org/apache/catalina/startup/TomcatBaseTest.java b/test/org/apache/catalina/startup/TomcatBaseTest.java index 9a4db5819119..10c7c3a4b439 100644 --- a/test/org/apache/catalina/startup/TomcatBaseTest.java +++ b/test/org/apache/catalina/startup/TomcatBaseTest.java @@ -76,6 +76,15 @@ public Tomcat getTomcatInstance() { return tomcat; } + + public Context getProgrammaticRootContext() { + // No file system docBase required + Context ctx = tomcat.addContext("", null); + // Disable class path scanning - it slows the tests down by almost an order of magnitude + ((StandardJarScanner) ctx.getJarScanner()).setScanClassPath(false); + return ctx; + } + /** * Sub-classes need to know port so they can connect */ diff --git a/test/org/apache/tomcat/websocket/TestWsWebSocketContainerSessionExpiryContainerClient.java b/test/org/apache/tomcat/websocket/TestWsWebSocketContainerSessionExpiryContainerClient.java new file mode 100644 index 000000000000..3b39d64108ad --- /dev/null +++ b/test/org/apache/tomcat/websocket/TestWsWebSocketContainerSessionExpiryContainerClient.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.websocket; + +import java.util.Set; + +import javax.websocket.ContainerProvider; +import javax.websocket.Session; + +import org.junit.Assert; +import org.junit.Test; + +import org.apache.catalina.Context; +import org.apache.catalina.servlets.DefaultServlet; +import org.apache.catalina.startup.Tomcat; +import org.apache.tomcat.websocket.TestWsWebSocketContainer.EndpointA; + +/* + * Moved to separate test class to improve test concurrency. These tests are + * some of the last tests to start and having them all in a single class + * significantly extends the length of a test run when using multiple test + * threads. + */ +public class TestWsWebSocketContainerSessionExpiryContainerClient extends WsWebSocketContainerBaseTest { + + @Test + public void testSessionExpiryContainer() throws Exception { + + Tomcat tomcat = getTomcatInstance(); + // No file system docBase required + Context ctx = getProgrammaticRootContext(); + ctx.addApplicationListener(TesterEchoServer.Config.class.getName()); + Tomcat.addServlet(ctx, "default", new DefaultServlet()); + ctx.addServletMapping("/", "default"); + + tomcat.start(); + + // Need access to implementation methods for configuring unit tests + WsWebSocketContainer wsContainer = (WsWebSocketContainer) ContainerProvider.getWebSocketContainer(); + + // 5 second timeout + wsContainer.setDefaultMaxSessionIdleTimeout(5000); + wsContainer.setProcessPeriod(1); + + EndpointA endpointA = new EndpointA(); + connectToEchoServer(wsContainer, endpointA, TesterEchoServer.Config.PATH_BASIC); + connectToEchoServer(wsContainer, endpointA, TesterEchoServer.Config.PATH_BASIC); + Session s3a = connectToEchoServer(wsContainer, endpointA, TesterEchoServer.Config.PATH_BASIC); + + // Check all three sessions are open + Set setA = s3a.getOpenSessions(); + Assert.assertEquals(3, setA.size()); + + int count = 0; + boolean isOpen = true; + while (isOpen && count < 100) { + count++; + Thread.sleep(100); + isOpen = false; + for (Session session : setA) { + if (session.isOpen()) { + isOpen = true; + break; + } + } + } + + if (isOpen) { + for (Session session : setA) { + if (session.isOpen()) { + System.err.println("Session with ID [" + session.getId() + "] is open"); + } + } + Assert.fail("There were open sessions"); + } + } +} \ No newline at end of file diff --git a/test/org/apache/tomcat/websocket/TestWsWebSocketContainerSessionExpiryContainerServer.java b/test/org/apache/tomcat/websocket/TestWsWebSocketContainerSessionExpiryContainerServer.java new file mode 100644 index 000000000000..be47909face0 --- /dev/null +++ b/test/org/apache/tomcat/websocket/TestWsWebSocketContainerSessionExpiryContainerServer.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.websocket; + +import java.util.Set; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.websocket.ContainerProvider; +import javax.websocket.Session; + +import org.junit.Assert; +import org.junit.Test; + +import org.apache.catalina.Context; +import org.apache.catalina.servlets.DefaultServlet; +import org.apache.catalina.startup.Tomcat; +import org.apache.tomcat.websocket.TestWsWebSocketContainer.EndpointA; +import org.apache.tomcat.websocket.server.Constants; +import org.apache.tomcat.websocket.server.WsServerContainer; + +/* + * Moved to separate test class to improve test concurrency. These tests are + * some of the last tests to start and having them all in a single class + * significantly extends the length of a test run when using multiple test + * threads. + */ +public class TestWsWebSocketContainerSessionExpiryContainerServer extends WsWebSocketContainerBaseTest { + + @Test + public void testSessionExpiryContainer() throws Exception { + + Tomcat tomcat = getTomcatInstance(); + // No file system docBase required + Context ctx = getProgrammaticRootContext(); + ctx.addApplicationListener(TesterEchoServer.Config.class.getName()); + Tomcat.addServlet(ctx, "default", new DefaultServlet()); + ctx.addServletMapping("/", "default"); + + ctx.addApplicationListener(WebSocketServerTimeoutConfig.class.getName()); + + tomcat.start(); + + // Need access to implementation methods for configuring unit tests + WsWebSocketContainer wsContainer = (WsWebSocketContainer) ContainerProvider.getWebSocketContainer(); + + EndpointA endpointA = new EndpointA(); + connectToEchoServer(wsContainer, endpointA, TesterEchoServer.Config.PATH_BASIC); + connectToEchoServer(wsContainer, endpointA, TesterEchoServer.Config.PATH_BASIC); + Session s3a = connectToEchoServer(wsContainer, endpointA, TesterEchoServer.Config.PATH_BASIC); + + // Check all three sessions are open + Set setA = s3a.getOpenSessions(); + Assert.assertEquals(3, setA.size()); + + int count = 0; + boolean isOpen = true; + while (isOpen && count < 100) { + count++; + Thread.sleep(100); + isOpen = false; + for (Session session : setA) { + if (session.isOpen()) { + isOpen = true; + break; + } + } + } + + if (isOpen) { + for (Session session : setA) { + if (session.isOpen()) { + System.err.println("Session with ID [" + session.getId() + "] is open"); + } + } + Assert.fail("There were open sessions"); + } + } + + + public static class WebSocketServerTimeoutConfig implements ServletContextListener { + + @Override + public void contextInitialized(ServletContextEvent sce) { + WsServerContainer container = (WsServerContainer) sce.getServletContext().getAttribute( + Constants.SERVER_CONTAINER_SERVLET_CONTEXT_ATTRIBUTE); + // Process timeouts on every run of the background thread + container.setProcessPeriod(0); + // Set session timeout to 5s + container.setDefaultMaxSessionIdleTimeout(5000); + } + + @Override + public void contextDestroyed(ServletContextEvent sce) { + // NO-OP + } + } +} diff --git a/test/org/apache/tomcat/websocket/WsWebSocketContainerBaseTest.java b/test/org/apache/tomcat/websocket/WsWebSocketContainerBaseTest.java new file mode 100644 index 000000000000..157deb940c5c --- /dev/null +++ b/test/org/apache/tomcat/websocket/WsWebSocketContainerBaseTest.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.websocket; + +import java.net.URI; + +import javax.websocket.ClientEndpointConfig; +import javax.websocket.Endpoint; +import javax.websocket.Session; +import javax.websocket.WebSocketContainer; + +public class WsWebSocketContainerBaseTest extends WebSocketBaseTest { + + protected static final byte[] MESSAGE_BINARY_4K = new byte[4096]; + + protected static final long TIMEOUT_MS = 5 * 1000; + protected static final long MARGIN = 500; + + + /* + * Make this possible to override so sub-class can more easily test proxy + */ + protected String getHostName() { + return "localhost"; + } + + + protected Session connectToEchoServer(WebSocketContainer wsContainer, Endpoint endpoint, String path) + throws Exception { + return wsContainer.connectToServer(endpoint, ClientEndpointConfig.Builder.create().build(), + new URI("ws://" + getHostName() + ":" + getPort() + path)); + } +} \ No newline at end of file