This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/main by this push: new 28f5e29 Refactor tests to reduce running time when using multiple threads 28f5e29 is described below commit 28f5e2967824d67a85b0fab4370e3dc25bf9b07e Author: Mark Thomas <ma...@apache.org> AuthorDate: Mon Dec 6 11:54:52 2021 +0000 Refactor tests to reduce running time when using multiple threads Splits up long running tests into multiple tests to improve concurrency towards the end of the test run where a small number of long running tests were dominating the test execution time. Generally, the more threads the test use, the more pronounced this effect. --- .../el/TestImportHandlerStandardPackages.java | 2 +- ...tDoHead.java => HttpServletDoHeadBaseTest.java} | 39 +-- .../http/TestHttpServletDoHeadValidWrite0.java | 52 +++ .../http/TestHttpServletDoHeadValidWrite1.java | 52 +++ .../http/TestHttpServletDoHeadValidWrite1023.java | 52 +++ .../http/TestHttpServletDoHeadValidWrite1024.java | 52 +++ .../http/TestHttpServletDoHeadValidWrite1025.java | 52 +++ .../http/TestHttpServletDoHeadValidWrite511.java | 52 +++ .../http/TestHttpServletDoHeadValidWrite512.java | 52 +++ .../http/TestHttpServletDoHeadValidWrite513.java | 52 +++ ...java => TestWebdavServletOptionCollection.java} | 15 +- ...ions.java => TestWebdavServletOptionsFile.java} | 15 +- ...s.java => TestWebdavServletOptionsUnknown.java} | 15 +- .../tomcat/websocket/TestWsWebSocketContainer.java | 372 +-------------------- ...WsWebSocketContainerSessionExpiryContainer.java | 96 ++++++ ...stWsWebSocketContainerSessionExpirySession.java | 100 ++++++ .../TestWsWebSocketContainerTimeoutClient.java | 123 +++++++ .../TestWsWebSocketContainerTimeoutServer.java | 201 +++++++++++ .../websocket/WsWebSocketContainerBaseTest.java | 48 +++ 19 files changed, 1018 insertions(+), 424 deletions(-) diff --git a/test/jakarta/el/TestImportHandlerStandardPackages.java b/test/jakarta/el/TestImportHandlerStandardPackages.java index 5a8ca7f..28ba400 100644 --- a/test/jakarta/el/TestImportHandlerStandardPackages.java +++ b/test/jakarta/el/TestImportHandlerStandardPackages.java @@ -98,7 +98,7 @@ public class TestImportHandlerStandardPackages { // Skip non-class resources continue; } - if (file.startsWith("Test")) { + if (file.startsWith("Test") || file.endsWith("BaseTest.class")) { // Skip test resources continue; } diff --git a/test/jakarta/servlet/http/TestHttpServletDoHead.java b/test/jakarta/servlet/http/HttpServletDoHeadBaseTest.java similarity index 87% rename from test/jakarta/servlet/http/TestHttpServletDoHead.java rename to test/jakarta/servlet/http/HttpServletDoHeadBaseTest.java index 973c9cd..51516ad 100644 --- a/test/jakarta/servlet/http/TestHttpServletDoHead.java +++ b/test/jakarta/servlet/http/HttpServletDoHeadBaseTest.java @@ -21,8 +21,6 @@ import java.io.OutputStream; import java.io.PrintWriter; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -31,8 +29,6 @@ import jakarta.servlet.ServletException; import org.junit.Assert; import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; import org.apache.catalina.LifecycleException; @@ -43,8 +39,11 @@ import org.apache.coyote.http2.Http2TestBase; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.collections.CaseInsensitiveKeyMap; -@RunWith(Parameterized.class) -public class TestHttpServletDoHead extends Http2TestBase { +/* + * Split into multiple tests as a single test takes so long it impacts the time + * of an entire test run. + */ +public class HttpServletDoHeadBaseTest extends Http2TestBase { // Tomcat has a minimum output buffer size of 8 * 1024. // (8 * 1024) /16 = 512 @@ -52,34 +51,12 @@ public class TestHttpServletDoHead extends Http2TestBase { private static final String VALID = "** valid data **"; private static final String INVALID = "* invalid data *"; - private static final Integer BUFFERS[] = new Integer[] { Integer.valueOf (16), Integer.valueOf(8 * 1024), Integer.valueOf(16 * 1024) }; + protected static final Integer BUFFERS[] = new Integer[] { Integer.valueOf (16), Integer.valueOf(8 * 1024), Integer.valueOf(16 * 1024) }; - private static final Integer COUNTS[] = new Integer[] { Integer.valueOf(0), Integer.valueOf(1), + protected static final Integer COUNTS[] = new Integer[] { Integer.valueOf(0), Integer.valueOf(1), Integer.valueOf(511), Integer.valueOf(512), Integer.valueOf(513), Integer.valueOf(1023), Integer.valueOf(1024), Integer.valueOf(1025) }; - @Parameterized.Parameters(name = "{index}: {0} {1} {2} {3} {4} {5} {6}") - public static Collection<Object[]> parameters() { - - List<Object[]> parameterSets = new ArrayList<>(); - for (Boolean l : booleans) { - for (Integer buf : BUFFERS) { - for (Boolean w : booleans) { - for (Integer c1 : COUNTS) { - for (ResetType rt : ResetType.values()) { - for (Integer c2 : COUNTS) { - for (Boolean f : booleans) { - parameterSets.add(new Object[] { l, buf, w, c1, rt, c2, f }); - } - } - } - } - } - } - } - return parameterSets; - } - @Parameter(0) public boolean useLegacy; @Parameter(1) @@ -296,7 +273,7 @@ public class TestHttpServletDoHead extends Http2TestBase { } - private static enum ResetType { + static enum ResetType { NONE, BUFFER, FULL diff --git a/test/jakarta/servlet/http/TestHttpServletDoHeadValidWrite0.java b/test/jakarta/servlet/http/TestHttpServletDoHeadValidWrite0.java new file mode 100644 index 0000000..147d879 --- /dev/null +++ b/test/jakarta/servlet/http/TestHttpServletDoHeadValidWrite0.java @@ -0,0 +1,52 @@ +/* + * 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 jakarta.servlet.http; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +/* + * Split into multiple tests as a single test takes so long it impacts the time + * of an entire test run. + */ +@RunWith(Parameterized.class) +public class TestHttpServletDoHeadValidWrite0 extends HttpServletDoHeadBaseTest { + + @Parameterized.Parameters(name = "{index}: {0} {1} {2} {3} {4} {5} {6}") + public static Collection<Object[]> parameters() { + + List<Object[]> parameterSets = new ArrayList<>(); + for (Boolean l : booleans) { + for (Integer buf : BUFFERS) { + for (Boolean w : booleans) { + for (Integer c1 : COUNTS) { + for (ResetType rt : ResetType.values()) { + for (Boolean f : booleans) { + parameterSets.add(new Object[] { l, buf, w, c1, rt, Integer.valueOf(0), f }); + } + } + } + } + } + } + return parameterSets; + } +} diff --git a/test/jakarta/servlet/http/TestHttpServletDoHeadValidWrite1.java b/test/jakarta/servlet/http/TestHttpServletDoHeadValidWrite1.java new file mode 100644 index 0000000..0b47b58 --- /dev/null +++ b/test/jakarta/servlet/http/TestHttpServletDoHeadValidWrite1.java @@ -0,0 +1,52 @@ +/* + * 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 jakarta.servlet.http; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +/* + * Split into multiple tests as a single test takes so long it impacts the time + * of an entire test run. + */ +@RunWith(Parameterized.class) +public class TestHttpServletDoHeadValidWrite1 extends HttpServletDoHeadBaseTest { + + @Parameterized.Parameters(name = "{index}: {0} {1} {2} {3} {4} {5} {6}") + public static Collection<Object[]> parameters() { + + List<Object[]> parameterSets = new ArrayList<>(); + for (Boolean l : booleans) { + for (Integer buf : BUFFERS) { + for (Boolean w : booleans) { + for (Integer c1 : COUNTS) { + for (ResetType rt : ResetType.values()) { + for (Boolean f : booleans) { + parameterSets.add(new Object[] { l, buf, w, c1, rt, Integer.valueOf(1), f }); + } + } + } + } + } + } + return parameterSets; + } +} diff --git a/test/jakarta/servlet/http/TestHttpServletDoHeadValidWrite1023.java b/test/jakarta/servlet/http/TestHttpServletDoHeadValidWrite1023.java new file mode 100644 index 0000000..84466d5 --- /dev/null +++ b/test/jakarta/servlet/http/TestHttpServletDoHeadValidWrite1023.java @@ -0,0 +1,52 @@ +/* + * 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 jakarta.servlet.http; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +/* + * Split into multiple tests as a single test takes so long it impacts the time + * of an entire test run. + */ +@RunWith(Parameterized.class) +public class TestHttpServletDoHeadValidWrite1023 extends HttpServletDoHeadBaseTest { + + @Parameterized.Parameters(name = "{index}: {0} {1} {2} {3} {4} {5} {6}") + public static Collection<Object[]> parameters() { + + List<Object[]> parameterSets = new ArrayList<>(); + for (Boolean l : booleans) { + for (Integer buf : BUFFERS) { + for (Boolean w : booleans) { + for (Integer c1 : COUNTS) { + for (ResetType rt : ResetType.values()) { + for (Boolean f : booleans) { + parameterSets.add(new Object[] { l, buf, w, c1, rt, Integer.valueOf(1023), f }); + } + } + } + } + } + } + return parameterSets; + } +} diff --git a/test/jakarta/servlet/http/TestHttpServletDoHeadValidWrite1024.java b/test/jakarta/servlet/http/TestHttpServletDoHeadValidWrite1024.java new file mode 100644 index 0000000..2f76939 --- /dev/null +++ b/test/jakarta/servlet/http/TestHttpServletDoHeadValidWrite1024.java @@ -0,0 +1,52 @@ +/* + * 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 jakarta.servlet.http; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +/* + * Split into multiple tests as a single test takes so long it impacts the time + * of an entire test run. + */ +@RunWith(Parameterized.class) +public class TestHttpServletDoHeadValidWrite1024 extends HttpServletDoHeadBaseTest { + + @Parameterized.Parameters(name = "{index}: {0} {1} {2} {3} {4} {5} {6}") + public static Collection<Object[]> parameters() { + + List<Object[]> parameterSets = new ArrayList<>(); + for (Boolean l : booleans) { + for (Integer buf : BUFFERS) { + for (Boolean w : booleans) { + for (Integer c1 : COUNTS) { + for (ResetType rt : ResetType.values()) { + for (Boolean f : booleans) { + parameterSets.add(new Object[] { l, buf, w, c1, rt, Integer.valueOf(1024), f }); + } + } + } + } + } + } + return parameterSets; + } +} diff --git a/test/jakarta/servlet/http/TestHttpServletDoHeadValidWrite1025.java b/test/jakarta/servlet/http/TestHttpServletDoHeadValidWrite1025.java new file mode 100644 index 0000000..a95cd8d --- /dev/null +++ b/test/jakarta/servlet/http/TestHttpServletDoHeadValidWrite1025.java @@ -0,0 +1,52 @@ +/* + * 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 jakarta.servlet.http; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +/* + * Split into multiple tests as a single test takes so long it impacts the time + * of an entire test run. + */ +@RunWith(Parameterized.class) +public class TestHttpServletDoHeadValidWrite1025 extends HttpServletDoHeadBaseTest { + + @Parameterized.Parameters(name = "{index}: {0} {1} {2} {3} {4} {5} {6}") + public static Collection<Object[]> parameters() { + + List<Object[]> parameterSets = new ArrayList<>(); + for (Boolean l : booleans) { + for (Integer buf : BUFFERS) { + for (Boolean w : booleans) { + for (Integer c1 : COUNTS) { + for (ResetType rt : ResetType.values()) { + for (Boolean f : booleans) { + parameterSets.add(new Object[] { l, buf, w, c1, rt, Integer.valueOf(1025), f }); + } + } + } + } + } + } + return parameterSets; + } +} diff --git a/test/jakarta/servlet/http/TestHttpServletDoHeadValidWrite511.java b/test/jakarta/servlet/http/TestHttpServletDoHeadValidWrite511.java new file mode 100644 index 0000000..b201e7a --- /dev/null +++ b/test/jakarta/servlet/http/TestHttpServletDoHeadValidWrite511.java @@ -0,0 +1,52 @@ +/* + * 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 jakarta.servlet.http; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +/* + * Split into multiple tests as a single test takes so long it impacts the time + * of an entire test run. + */ +@RunWith(Parameterized.class) +public class TestHttpServletDoHeadValidWrite511 extends HttpServletDoHeadBaseTest { + + @Parameterized.Parameters(name = "{index}: {0} {1} {2} {3} {4} {5} {6}") + public static Collection<Object[]> parameters() { + + List<Object[]> parameterSets = new ArrayList<>(); + for (Boolean l : booleans) { + for (Integer buf : BUFFERS) { + for (Boolean w : booleans) { + for (Integer c1 : COUNTS) { + for (ResetType rt : ResetType.values()) { + for (Boolean f : booleans) { + parameterSets.add(new Object[] { l, buf, w, c1, rt, Integer.valueOf(511), f }); + } + } + } + } + } + } + return parameterSets; + } +} diff --git a/test/jakarta/servlet/http/TestHttpServletDoHeadValidWrite512.java b/test/jakarta/servlet/http/TestHttpServletDoHeadValidWrite512.java new file mode 100644 index 0000000..0075eef --- /dev/null +++ b/test/jakarta/servlet/http/TestHttpServletDoHeadValidWrite512.java @@ -0,0 +1,52 @@ +/* + * 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 jakarta.servlet.http; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +/* + * Split into multiple tests as a single test takes so long it impacts the time + * of an entire test run. + */ +@RunWith(Parameterized.class) +public class TestHttpServletDoHeadValidWrite512 extends HttpServletDoHeadBaseTest { + + @Parameterized.Parameters(name = "{index}: {0} {1} {2} {3} {4} {5} {6}") + public static Collection<Object[]> parameters() { + + List<Object[]> parameterSets = new ArrayList<>(); + for (Boolean l : booleans) { + for (Integer buf : BUFFERS) { + for (Boolean w : booleans) { + for (Integer c1 : COUNTS) { + for (ResetType rt : ResetType.values()) { + for (Boolean f : booleans) { + parameterSets.add(new Object[] { l, buf, w, c1, rt, Integer.valueOf(512), f }); + } + } + } + } + } + } + return parameterSets; + } +} diff --git a/test/jakarta/servlet/http/TestHttpServletDoHeadValidWrite513.java b/test/jakarta/servlet/http/TestHttpServletDoHeadValidWrite513.java new file mode 100644 index 0000000..e65e5aa --- /dev/null +++ b/test/jakarta/servlet/http/TestHttpServletDoHeadValidWrite513.java @@ -0,0 +1,52 @@ +/* + * 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 jakarta.servlet.http; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +/* + * Split into multiple tests as a single test takes so long it impacts the time + * of an entire test run. + */ +@RunWith(Parameterized.class) +public class TestHttpServletDoHeadValidWrite513 extends HttpServletDoHeadBaseTest { + + @Parameterized.Parameters(name = "{index}: {0} {1} {2} {3} {4} {5} {6}") + public static Collection<Object[]> parameters() { + + List<Object[]> parameterSets = new ArrayList<>(); + for (Boolean l : booleans) { + for (Integer buf : BUFFERS) { + for (Boolean w : booleans) { + for (Integer c1 : COUNTS) { + for (ResetType rt : ResetType.values()) { + for (Boolean f : booleans) { + parameterSets.add(new Object[] { l, buf, w, c1, rt, Integer.valueOf(513), f }); + } + } + } + } + } + } + return parameterSets; + } +} diff --git a/test/org/apache/catalina/servlets/TestWebdavServletOptions.java b/test/org/apache/catalina/servlets/TestWebdavServletOptionCollection.java similarity index 80% copy from test/org/apache/catalina/servlets/TestWebdavServletOptions.java copy to test/org/apache/catalina/servlets/TestWebdavServletOptionCollection.java index ef511ea..c57408c 100644 --- a/test/org/apache/catalina/servlets/TestWebdavServletOptions.java +++ b/test/org/apache/catalina/servlets/TestWebdavServletOptionCollection.java @@ -26,12 +26,15 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; +/* + * Split into multiple tests as a single test takes so long it impacts the time + * of an entire test run. + */ @RunWith(Parameterized.class) -public class TestWebdavServletOptions extends ServletOptionsBaseTest { +public class TestWebdavServletOptionCollection extends ServletOptionsBaseTest { @Parameters public static Collection<Object[]> inputs() { - String[] urls = new String[] { COLLECTION_NAME, FILE_NAME, UNKNOWN_NAME }; String[] methods = new String[] { "GET", "POST", "HEAD", "TRACE", "PUT", "DELETE", "MKCOL", "LOCK", "UNLOCK", "COPY", "MOVE", "PROPFIND", "PROPPATCH" }; @@ -40,11 +43,9 @@ public class TestWebdavServletOptions extends ServletOptionsBaseTest { for (Boolean listingsValue : booleans) { for (Boolean readOnlyValue : booleans) { for (Boolean traceValue : booleans) { - for (String url : urls) { - for (String method : methods) { - result.add(new Object[] { - listingsValue, readOnlyValue, traceValue, url, method } ); - } + for (String method : methods) { + result.add(new Object[] { + listingsValue, readOnlyValue, traceValue, COLLECTION_NAME, method } ); } } } diff --git a/test/org/apache/catalina/servlets/TestWebdavServletOptions.java b/test/org/apache/catalina/servlets/TestWebdavServletOptionsFile.java similarity index 80% copy from test/org/apache/catalina/servlets/TestWebdavServletOptions.java copy to test/org/apache/catalina/servlets/TestWebdavServletOptionsFile.java index ef511ea..7085c7b 100644 --- a/test/org/apache/catalina/servlets/TestWebdavServletOptions.java +++ b/test/org/apache/catalina/servlets/TestWebdavServletOptionsFile.java @@ -26,12 +26,15 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; +/* + * Split into multiple tests as a single test takes so long it impacts the time + * of an entire test run. + */ @RunWith(Parameterized.class) -public class TestWebdavServletOptions extends ServletOptionsBaseTest { +public class TestWebdavServletOptionsFile extends ServletOptionsBaseTest { @Parameters public static Collection<Object[]> inputs() { - String[] urls = new String[] { COLLECTION_NAME, FILE_NAME, UNKNOWN_NAME }; String[] methods = new String[] { "GET", "POST", "HEAD", "TRACE", "PUT", "DELETE", "MKCOL", "LOCK", "UNLOCK", "COPY", "MOVE", "PROPFIND", "PROPPATCH" }; @@ -40,11 +43,9 @@ public class TestWebdavServletOptions extends ServletOptionsBaseTest { for (Boolean listingsValue : booleans) { for (Boolean readOnlyValue : booleans) { for (Boolean traceValue : booleans) { - for (String url : urls) { - for (String method : methods) { - result.add(new Object[] { - listingsValue, readOnlyValue, traceValue, url, method } ); - } + for (String method : methods) { + result.add(new Object[] { + listingsValue, readOnlyValue, traceValue, FILE_NAME, method } ); } } } diff --git a/test/org/apache/catalina/servlets/TestWebdavServletOptions.java b/test/org/apache/catalina/servlets/TestWebdavServletOptionsUnknown.java similarity index 80% rename from test/org/apache/catalina/servlets/TestWebdavServletOptions.java rename to test/org/apache/catalina/servlets/TestWebdavServletOptionsUnknown.java index ef511ea..f5ca12c 100644 --- a/test/org/apache/catalina/servlets/TestWebdavServletOptions.java +++ b/test/org/apache/catalina/servlets/TestWebdavServletOptionsUnknown.java @@ -26,12 +26,15 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; +/* + * Split into multiple tests as a single test takes so long it impacts the time + * of an entire test run. + */ @RunWith(Parameterized.class) -public class TestWebdavServletOptions extends ServletOptionsBaseTest { +public class TestWebdavServletOptionsUnknown extends ServletOptionsBaseTest { @Parameters public static Collection<Object[]> inputs() { - String[] urls = new String[] { COLLECTION_NAME, FILE_NAME, UNKNOWN_NAME }; String[] methods = new String[] { "GET", "POST", "HEAD", "TRACE", "PUT", "DELETE", "MKCOL", "LOCK", "UNLOCK", "COPY", "MOVE", "PROPFIND", "PROPPATCH" }; @@ -40,11 +43,9 @@ public class TestWebdavServletOptions extends ServletOptionsBaseTest { for (Boolean listingsValue : booleans) { for (Boolean readOnlyValue : booleans) { for (Boolean traceValue : booleans) { - for (String url : urls) { - for (String method : methods) { - result.add(new Object[] { - listingsValue, readOnlyValue, traceValue, url, method } ); - } + for (String method : methods) { + result.add(new Object[] { + listingsValue, readOnlyValue, traceValue, UNKNOWN_NAME, method } ); } } } diff --git a/test/org/apache/tomcat/websocket/TestWsWebSocketContainer.java b/test/org/apache/tomcat/websocket/TestWsWebSocketContainer.java index 347fa20..de86314 100644 --- a/test/org/apache/tomcat/websocket/TestWsWebSocketContainer.java +++ b/test/org/apache/tomcat/websocket/TestWsWebSocketContainer.java @@ -17,7 +17,6 @@ package org.apache.tomcat.websocket; import java.io.IOException; -import java.net.SocketTimeoutException; import java.net.URI; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -25,8 +24,6 @@ import java.util.List; import java.util.Queue; import java.util.Set; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import jakarta.servlet.ServletContextEvent; @@ -42,7 +39,6 @@ import jakarta.websocket.Session; import jakarta.websocket.WebSocketContainer; import jakarta.websocket.server.ServerContainer; import jakarta.websocket.server.ServerEndpoint; -import jakarta.websocket.server.ServerEndpointConfig; import org.junit.Assert; import org.junit.Test; @@ -57,15 +53,11 @@ import org.apache.tomcat.websocket.TesterMessageCountClient.TesterEndpoint; import org.apache.tomcat.websocket.TesterMessageCountClient.TesterProgrammaticEndpoint; import org.apache.tomcat.websocket.server.WsContextListener; -public class TestWsWebSocketContainer extends WebSocketBaseTest { +public class TestWsWebSocketContainer extends WsWebSocketContainerBaseTest { private static final String MESSAGE_EMPTY = ""; private static final String MESSAGE_STRING_1 = "qwerty"; private static final String MESSAGE_TEXT_4K; - private static final byte[] MESSAGE_BINARY_4K = new byte[4096]; - - private static final long TIMEOUT_MS = 5 * 1000; - private static final long MARGIN = 500; // 5s should be plenty but Gump can be a lot slower private static final long START_STOP_WAIT = 60 * 1000; @@ -296,159 +288,6 @@ public class TestWsWebSocketContainer extends WebSocketBaseTest { } - @Test - public void testWriteTimeoutClientContainer() throws Exception { - doTestWriteTimeoutClient(true); - } - - - @Test - public void testWriteTimeoutClientEndpoint() throws Exception { - doTestWriteTimeoutClient(false); - } - - - private void doTestWriteTimeoutClient(boolean setTimeoutOnContainer) - throws Exception { - - Tomcat tomcat = getTomcatInstance(); - // No file system docBase required - Context ctx = tomcat.addContext("", null); - ctx.addApplicationListener(BlockingConfig.class.getName()); - Tomcat.addServlet(ctx, "default", new DefaultServlet()); - ctx.addServletMappingDecoded("/", "default"); - - WebSocketContainer wsContainer = - ContainerProvider.getWebSocketContainer(); - - // Set the async timeout - if (setTimeoutOnContainer) { - wsContainer.setAsyncSendTimeout(TIMEOUT_MS); - } - - tomcat.start(); - - Session wsSession = wsContainer.connectToServer( - TesterProgrammaticEndpoint.class, - ClientEndpointConfig.Builder.create().build(), - new URI("ws://" + getHostName() + ":" + getPort() + BlockingConfig.PATH)); - - if (!setTimeoutOnContainer) { - wsSession.getAsyncRemote().setSendTimeout(TIMEOUT_MS); - } - - long lastSend = 0; - - // Should send quickly until the network buffers fill up and then block - // until the timeout kicks in - Exception exception = null; - try { - while (true) { - lastSend = System.currentTimeMillis(); - Future<Void> f = wsSession.getAsyncRemote().sendBinary( - ByteBuffer.wrap(MESSAGE_BINARY_4K)); - f.get(); - } - } catch (Exception e) { - exception = e; - } - - long timeout = System.currentTimeMillis() - lastSend; - - // Clear the server side block and prevent further blocks to allow the - // server to shutdown cleanly - BlockingPojo.clearBlock(); - - // Close the client session, primarily to allow the - // BackgroundProcessManager to shut down. - wsSession.close(); - - String msg = "Time out was [" + timeout + "] ms"; - - // Check correct time passed - Assert.assertTrue(msg, timeout >= TIMEOUT_MS - MARGIN ); - - // Check the timeout wasn't too long - Assert.assertTrue(msg, timeout < TIMEOUT_MS * 2); - - Assert.assertNotNull(exception); - } - - - @Test - public void testWriteTimeoutServerContainer() throws Exception { - doTestWriteTimeoutServer(true); - } - - - @Test - public void testWriteTimeoutServerEndpoint() throws Exception { - doTestWriteTimeoutServer(false); - } - - - private static volatile boolean timeoutOnContainer = false; - - private void doTestWriteTimeoutServer(boolean setTimeoutOnContainer) - throws Exception { - - /* - * Note: There are all sorts of horrible uses of statics in this test - * because the API uses classes and the tests really need access - * to the instances which simply isn't possible. - */ - timeoutOnContainer = setTimeoutOnContainer; - - Tomcat tomcat = getTomcatInstance(); - - // No file system docBase required - Context ctx = tomcat.addContext("", null); - ctx.addApplicationListener(ConstantTxConfig.class.getName()); - Tomcat.addServlet(ctx, "default", new DefaultServlet()); - ctx.addServletMappingDecoded("/", "default"); - - WebSocketContainer wsContainer = - ContainerProvider.getWebSocketContainer(); - - tomcat.start(); - - Session wsSession = wsContainer.connectToServer( - TesterProgrammaticEndpoint.class, - ClientEndpointConfig.Builder.create().build(), - new URI("ws://" + getHostName() + ":" + getPort() + - ConstantTxConfig.PATH)); - - wsSession.addMessageHandler(new BlockingBinaryHandler()); - - int loops = 0; - while (loops < 15) { - Thread.sleep(1000); - if (!ConstantTxEndpoint.getRunning()) { - break; - } - loops++; - } - - // Close the client session, primarily to allow the - // BackgroundProcessManager to shut down. - wsSession.close(); - - // Check the right exception was thrown - Assert.assertNotNull(ConstantTxEndpoint.getException()); - Assert.assertEquals(ExecutionException.class, - ConstantTxEndpoint.getException().getClass()); - Assert.assertNotNull(ConstantTxEndpoint.getException().getCause()); - Assert.assertEquals(SocketTimeoutException.class, - ConstantTxEndpoint.getException().getCause().getClass()); - - // Check correct time passed - Assert.assertTrue(ConstantTxEndpoint.getTimeout() >= TIMEOUT_MS); - - // Check the timeout wasn't too long - Assert.assertTrue(ConstantTxEndpoint.getTimeout() < TIMEOUT_MS*2); - } - - public static class BlockingConfig extends WsContextListener { public static final String PATH = "/block"; @@ -538,81 +377,6 @@ public class TestWsWebSocketContainer extends WebSocketBaseTest { } - public static class ConstantTxEndpoint extends Endpoint { - - // Have to be static to be able to retrieve results from test case - private static volatile long timeout = -1; - private static volatile Exception exception = null; - private static volatile boolean running = true; - - - @Override - public void onOpen(Session session, EndpointConfig config) { - - // Reset everything - timeout = -1; - exception = null; - running = true; - - if (!TestWsWebSocketContainer.timeoutOnContainer) { - session.getAsyncRemote().setSendTimeout(TIMEOUT_MS); - } - - long lastSend = 0; - - // Should send quickly until the network buffers fill up and then - // block until the timeout kicks in - try { - while (true) { - lastSend = System.currentTimeMillis(); - Future<Void> f = session.getAsyncRemote().sendBinary( - ByteBuffer.wrap(MESSAGE_BINARY_4K)); - f.get(); - } - } catch (ExecutionException | InterruptedException e) { - exception = e; - } - timeout = System.currentTimeMillis() - lastSend; - running = false; - } - - public static long getTimeout() { - return timeout; - } - - public static Exception getException() { - return exception; - } - - public static boolean getRunning() { - return running; - } - } - - - public static class ConstantTxConfig extends WsContextListener { - - private static final String PATH = "/test"; - - @Override - public void contextInitialized(ServletContextEvent sce) { - super.contextInitialized(sce); - ServerContainer sc = - (ServerContainer) sce.getServletContext().getAttribute( - org.apache.tomcat.websocket.server.Constants.SERVER_CONTAINER_SERVLET_CONTEXT_ATTRIBUTE); - try { - sc.addEndpoint(ServerEndpointConfig.Builder.create( - ConstantTxEndpoint.class, PATH).build()); - if (TestWsWebSocketContainer.timeoutOnContainer) { - sc.setAsyncSendTimeout(TIMEOUT_MS); - } - } catch (DeploymentException e) { - throw new IllegalStateException(e); - } - } - } - - @Test public void testGetOpenSessions() throws Exception { Tomcat tomcat = getTomcatInstance(); @@ -670,115 +434,6 @@ public class TestWsWebSocketContainer extends WebSocketBaseTest { @Test - public void testSessionExpiryContainer() throws Exception { - - Tomcat tomcat = getTomcatInstance(); - // No file system docBase required - Context ctx = tomcat.addContext("", null); - ctx.addApplicationListener(TesterEchoServer.Config.class.getName()); - Tomcat.addServlet(ctx, "default", new DefaultServlet()); - ctx.addServletMappingDecoded("/", "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<Session> setA = s3a.getOpenSessions(); - Assert.assertEquals(3, setA.size()); - - int count = 0; - boolean isOpen = true; - while (isOpen && count < 8) { - count ++; - Thread.sleep(1000); - 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"); - } - } - - - @Test - public void testSessionExpirySession() throws Exception { - - Tomcat tomcat = getTomcatInstance(); - // No file system docBase required - Context ctx = tomcat.addContext("", null); - ctx.addApplicationListener(TesterEchoServer.Config.class.getName()); - Tomcat.addServlet(ctx, "default", new DefaultServlet()); - ctx.addServletMappingDecoded("/", "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(); - Session s1a = connectToEchoServer(wsContainer, endpointA, - TesterEchoServer.Config.PATH_BASIC); - s1a.setMaxIdleTimeout(3000); - Session s2a = connectToEchoServer(wsContainer, endpointA, - TesterEchoServer.Config.PATH_BASIC); - s2a.setMaxIdleTimeout(6000); - Session s3a = connectToEchoServer(wsContainer, endpointA, - TesterEchoServer.Config.PATH_BASIC); - s3a.setMaxIdleTimeout(9000); - - // Check all three sessions are open - Set<Session> setA = s3a.getOpenSessions(); - - int expected = 3; - while (expected > 0) { - Assert.assertEquals(expected, getOpenCount(setA)); - - int count = 0; - while (getOpenCount(setA) == expected && count < 50) { - count ++; - Thread.sleep(100); - } - - expected--; - } - - Assert.assertEquals(0, getOpenCount(setA)); - } - - - @Test public void testSessionExpiryOnUserPropertyReadIdleTimeout() throws Exception { Tomcat tomcat = getTomcatInstance(); // No file system docBase required @@ -858,23 +513,6 @@ public class TestWsWebSocketContainer extends WebSocketBaseTest { } - private int getOpenCount(Set<Session> sessions) { - int result = 0; - for (Session session : sessions) { - if (session.isOpen()) { - result++; - } - } - return result; - } - - private Session connectToEchoServer(WebSocketContainer wsContainer, - Endpoint endpoint, String path) throws Exception { - return wsContainer.connectToServer(endpoint, - ClientEndpointConfig.Builder.create().build(), - new URI("ws://" + getHostName() + ":" + getPort() + path)); - } - public static final class EndpointA extends Endpoint { @Override @@ -1058,12 +696,4 @@ public class TestWsWebSocketContainer extends WebSocketBaseTest { ((WsWebSocketContainer) wsContainer).destroy(); } - - - /* - * Make this possible to override so sub-class can more easily test proxy - */ - protected String getHostName() { - return "localhost"; - } } diff --git a/test/org/apache/tomcat/websocket/TestWsWebSocketContainerSessionExpiryContainer.java b/test/org/apache/tomcat/websocket/TestWsWebSocketContainerSessionExpiryContainer.java new file mode 100644 index 0000000..8f5dfb6 --- /dev/null +++ b/test/org/apache/tomcat/websocket/TestWsWebSocketContainerSessionExpiryContainer.java @@ -0,0 +1,96 @@ +/* + * 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 jakarta.websocket.ContainerProvider; +import jakarta.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 TestWsWebSocketContainerSessionExpiryContainer extends WsWebSocketContainerBaseTest { + + @Test + public void testSessionExpiryContainer() throws Exception { + + Tomcat tomcat = getTomcatInstance(); + // No file system docBase required + Context ctx = tomcat.addContext("", null); + ctx.addApplicationListener(TesterEchoServer.Config.class.getName()); + Tomcat.addServlet(ctx, "default", new DefaultServlet()); + ctx.addServletMappingDecoded("/", "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<Session> setA = s3a.getOpenSessions(); + Assert.assertEquals(3, setA.size()); + + int count = 0; + boolean isOpen = true; + while (isOpen && count < 8) { + count ++; + Thread.sleep(1000); + 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"); + } + } +} diff --git a/test/org/apache/tomcat/websocket/TestWsWebSocketContainerSessionExpirySession.java b/test/org/apache/tomcat/websocket/TestWsWebSocketContainerSessionExpirySession.java new file mode 100644 index 0000000..b265e08 --- /dev/null +++ b/test/org/apache/tomcat/websocket/TestWsWebSocketContainerSessionExpirySession.java @@ -0,0 +1,100 @@ +/* + * 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 jakarta.websocket.ContainerProvider; +import jakarta.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 TestWsWebSocketContainerSessionExpirySession extends WsWebSocketContainerBaseTest { + + @Test + public void testSessionExpirySession() throws Exception { + + Tomcat tomcat = getTomcatInstance(); + // No file system docBase required + Context ctx = tomcat.addContext("", null); + ctx.addApplicationListener(TesterEchoServer.Config.class.getName()); + Tomcat.addServlet(ctx, "default", new DefaultServlet()); + ctx.addServletMappingDecoded("/", "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(); + Session s1a = connectToEchoServer(wsContainer, endpointA, + TesterEchoServer.Config.PATH_BASIC); + s1a.setMaxIdleTimeout(3000); + Session s2a = connectToEchoServer(wsContainer, endpointA, + TesterEchoServer.Config.PATH_BASIC); + s2a.setMaxIdleTimeout(6000); + Session s3a = connectToEchoServer(wsContainer, endpointA, + TesterEchoServer.Config.PATH_BASIC); + s3a.setMaxIdleTimeout(9000); + + // Check all three sessions are open + Set<Session> setA = s3a.getOpenSessions(); + + int expected = 3; + while (expected > 0) { + Assert.assertEquals(expected, getOpenCount(setA)); + + int count = 0; + while (getOpenCount(setA) == expected && count < 50) { + count ++; + Thread.sleep(100); + } + + expected--; + } + + Assert.assertEquals(0, getOpenCount(setA)); + } + + + private int getOpenCount(Set<Session> sessions) { + int result = 0; + for (Session session : sessions) { + if (session.isOpen()) { + result++; + } + } + return result; + } +} diff --git a/test/org/apache/tomcat/websocket/TestWsWebSocketContainerTimeoutClient.java b/test/org/apache/tomcat/websocket/TestWsWebSocketContainerTimeoutClient.java new file mode 100644 index 0000000..b917506 --- /dev/null +++ b/test/org/apache/tomcat/websocket/TestWsWebSocketContainerTimeoutClient.java @@ -0,0 +1,123 @@ +/* + * 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 java.nio.ByteBuffer; +import java.util.concurrent.Future; + +import jakarta.websocket.ClientEndpointConfig; +import jakarta.websocket.ContainerProvider; +import jakarta.websocket.Session; +import jakarta.websocket.WebSocketContainer; + +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.BlockingConfig; +import org.apache.tomcat.websocket.TestWsWebSocketContainer.BlockingPojo; +import org.apache.tomcat.websocket.TesterMessageCountClient.TesterProgrammaticEndpoint; + +/* + * 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 TestWsWebSocketContainerTimeoutClient extends WsWebSocketContainerBaseTest { + + @Test + public void testWriteTimeoutClientContainer() throws Exception { + doTestWriteTimeoutClient(true); + } + + + @Test + public void testWriteTimeoutClientEndpoint() throws Exception { + doTestWriteTimeoutClient(false); + } + + + private void doTestWriteTimeoutClient(boolean setTimeoutOnContainer) + throws Exception { + + Tomcat tomcat = getTomcatInstance(); + // No file system docBase required + Context ctx = tomcat.addContext("", null); + ctx.addApplicationListener(BlockingConfig.class.getName()); + Tomcat.addServlet(ctx, "default", new DefaultServlet()); + ctx.addServletMappingDecoded("/", "default"); + + WebSocketContainer wsContainer = + ContainerProvider.getWebSocketContainer(); + + // Set the async timeout + if (setTimeoutOnContainer) { + wsContainer.setAsyncSendTimeout(TIMEOUT_MS); + } + + tomcat.start(); + + Session wsSession = wsContainer.connectToServer( + TesterProgrammaticEndpoint.class, + ClientEndpointConfig.Builder.create().build(), + new URI("ws://" + getHostName() + ":" + getPort() + BlockingConfig.PATH)); + + if (!setTimeoutOnContainer) { + wsSession.getAsyncRemote().setSendTimeout(TIMEOUT_MS); + } + + long lastSend = 0; + + // Should send quickly until the network buffers fill up and then block + // until the timeout kicks in + Exception exception = null; + try { + while (true) { + lastSend = System.currentTimeMillis(); + Future<Void> f = wsSession.getAsyncRemote().sendBinary( + ByteBuffer.wrap(MESSAGE_BINARY_4K)); + f.get(); + } + } catch (Exception e) { + exception = e; + } + + long timeout = System.currentTimeMillis() - lastSend; + + // Clear the server side block and prevent further blocks to allow the + // server to shutdown cleanly + BlockingPojo.clearBlock(); + + // Close the client session, primarily to allow the + // BackgroundProcessManager to shut down. + wsSession.close(); + + String msg = "Time out was [" + timeout + "] ms"; + + // Check correct time passed + Assert.assertTrue(msg, timeout >= TIMEOUT_MS - MARGIN ); + + // Check the timeout wasn't too long + Assert.assertTrue(msg, timeout < TIMEOUT_MS * 2); + + Assert.assertNotNull(exception); + } +} diff --git a/test/org/apache/tomcat/websocket/TestWsWebSocketContainerTimeoutServer.java b/test/org/apache/tomcat/websocket/TestWsWebSocketContainerTimeoutServer.java new file mode 100644 index 0000000..f275324 --- /dev/null +++ b/test/org/apache/tomcat/websocket/TestWsWebSocketContainerTimeoutServer.java @@ -0,0 +1,201 @@ +/* + * 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.SocketTimeoutException; +import java.net.URI; +import java.nio.ByteBuffer; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +import jakarta.servlet.ServletContextEvent; +import jakarta.websocket.ClientEndpointConfig; +import jakarta.websocket.ContainerProvider; +import jakarta.websocket.DeploymentException; +import jakarta.websocket.Endpoint; +import jakarta.websocket.EndpointConfig; +import jakarta.websocket.Session; +import jakarta.websocket.WebSocketContainer; +import jakarta.websocket.server.ServerContainer; +import jakarta.websocket.server.ServerEndpointConfig; + +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.BlockingBinaryHandler; +import org.apache.tomcat.websocket.TesterMessageCountClient.TesterProgrammaticEndpoint; +import org.apache.tomcat.websocket.server.WsContextListener; + +/* + * 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 TestWsWebSocketContainerTimeoutServer extends WsWebSocketContainerBaseTest { + + @Test + public void testWriteTimeoutServerContainer() throws Exception { + doTestWriteTimeoutServer(true); + } + + + @Test + public void testWriteTimeoutServerEndpoint() throws Exception { + doTestWriteTimeoutServer(false); + } + + + private static volatile boolean timeoutOnContainer = false; + + private void doTestWriteTimeoutServer(boolean setTimeoutOnContainer) + throws Exception { + + /* + * Note: There are all sorts of horrible uses of statics in this test + * because the API uses classes and the tests really need access + * to the instances which simply isn't possible. + */ + timeoutOnContainer = setTimeoutOnContainer; + + Tomcat tomcat = getTomcatInstance(); + + // No file system docBase required + Context ctx = tomcat.addContext("", null); + ctx.addApplicationListener(ConstantTxConfig.class.getName()); + Tomcat.addServlet(ctx, "default", new DefaultServlet()); + ctx.addServletMappingDecoded("/", "default"); + + WebSocketContainer wsContainer = + ContainerProvider.getWebSocketContainer(); + + tomcat.start(); + + Session wsSession = wsContainer.connectToServer( + TesterProgrammaticEndpoint.class, + ClientEndpointConfig.Builder.create().build(), + new URI("ws://" + getHostName() + ":" + getPort() + + ConstantTxConfig.PATH)); + + wsSession.addMessageHandler(new BlockingBinaryHandler()); + + int loops = 0; + while (loops < 15) { + Thread.sleep(1000); + if (!ConstantTxEndpoint.getRunning()) { + break; + } + loops++; + } + + // Close the client session, primarily to allow the + // BackgroundProcessManager to shut down. + wsSession.close(); + + // Check the right exception was thrown + Assert.assertNotNull(ConstantTxEndpoint.getException()); + Assert.assertEquals(ExecutionException.class, + ConstantTxEndpoint.getException().getClass()); + Assert.assertNotNull(ConstantTxEndpoint.getException().getCause()); + Assert.assertEquals(SocketTimeoutException.class, + ConstantTxEndpoint.getException().getCause().getClass()); + + // Check correct time passed + Assert.assertTrue(ConstantTxEndpoint.getTimeout() >= TIMEOUT_MS); + + // Check the timeout wasn't too long + Assert.assertTrue(ConstantTxEndpoint.getTimeout() < TIMEOUT_MS*2); + } + + + public static class ConstantTxConfig extends WsContextListener { + + private static final String PATH = "/test"; + + @Override + public void contextInitialized(ServletContextEvent sce) { + super.contextInitialized(sce); + ServerContainer sc = + (ServerContainer) sce.getServletContext().getAttribute( + org.apache.tomcat.websocket.server.Constants.SERVER_CONTAINER_SERVLET_CONTEXT_ATTRIBUTE); + try { + sc.addEndpoint(ServerEndpointConfig.Builder.create( + ConstantTxEndpoint.class, PATH).build()); + if (timeoutOnContainer) { + sc.setAsyncSendTimeout(TIMEOUT_MS); + } + } catch (DeploymentException e) { + throw new IllegalStateException(e); + } + } + } + + + public static class ConstantTxEndpoint extends Endpoint { + + // Have to be static to be able to retrieve results from test case + private static volatile long timeout = -1; + private static volatile Exception exception = null; + private static volatile boolean running = true; + + + @Override + public void onOpen(Session session, EndpointConfig config) { + + // Reset everything + timeout = -1; + exception = null; + running = true; + + if (!timeoutOnContainer) { + session.getAsyncRemote().setSendTimeout(TIMEOUT_MS); + } + + long lastSend = 0; + + // Should send quickly until the network buffers fill up and then + // block until the timeout kicks in + try { + while (true) { + lastSend = System.currentTimeMillis(); + Future<Void> f = session.getAsyncRemote().sendBinary( + ByteBuffer.wrap(MESSAGE_BINARY_4K)); + f.get(); + } + } catch (ExecutionException | InterruptedException e) { + exception = e; + } + timeout = System.currentTimeMillis() - lastSend; + running = false; + } + + public static long getTimeout() { + return timeout; + } + + public static Exception getException() { + return exception; + } + + public static boolean getRunning() { + return running; + } + } +} diff --git a/test/org/apache/tomcat/websocket/WsWebSocketContainerBaseTest.java b/test/org/apache/tomcat/websocket/WsWebSocketContainerBaseTest.java new file mode 100644 index 0000000..e245c4e --- /dev/null +++ b/test/org/apache/tomcat/websocket/WsWebSocketContainerBaseTest.java @@ -0,0 +1,48 @@ +/* + * 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 jakarta.websocket.ClientEndpointConfig; +import jakarta.websocket.Endpoint; +import jakarta.websocket.Session; +import jakarta.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)); + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org