test/jdk/java/net/httpclient/websocket/WebSocketTest.java
branchhttp-client-branch
changeset 56318 2a96e88888b2
parent 56317 52a9f6b74e43
child 56320 f82729ca8660
--- a/test/jdk/java/net/httpclient/websocket/WebSocketTest.java	Sat Mar 17 18:01:01 2018 +0000
+++ b/test/jdk/java/net/httpclient/websocket/WebSocketTest.java	Sun Mar 18 14:31:36 2018 +0000
@@ -24,27 +24,27 @@
 /*
  * @test
  * @build DummyWebSocketServer
- * @run testng/othervm
+ * @run testng/othervm/timeout=600
  *      -Djdk.internal.httpclient.websocket.debug=true
  *       WebSocketTest
  */
 
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
 import java.io.IOException;
 import java.net.http.WebSocket;
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
-import java.nio.channels.SocketChannel;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CompletionStage;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.stream.Collectors;
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
+
 import static java.net.http.HttpClient.newHttpClient;
 import static java.net.http.WebSocket.NORMAL_CLOSURE;
 import static org.testng.Assert.assertEquals;
@@ -65,65 +65,8 @@
         Support.assertCompletesExceptionally(clazz, stage);
     }
 
-    private static DummyWebSocketServer serverWithCannedData(int... data) {
-        byte[] copy = new byte[data.length];
-        for (int i = 0; i < data.length; i++) {
-            copy[i] = (byte) data[i];
-        }
-        return serverWithCannedData(copy);
-    }
-
-    private static DummyWebSocketServer serverWithCannedData(byte... data) {
-        byte[] copy = Arrays.copyOf(data, data.length);
-        return new DummyWebSocketServer() {
-            @Override
-            protected void serve(SocketChannel channel) throws IOException {
-                ByteBuffer closeMessage = ByteBuffer.wrap(copy);
-                channel.write(closeMessage);
-                super.serve(channel);
-            }
-        };
-    }
-
-    /*
-     * This server does not read from the wire, allowing its client to fill up
-     * their send buffer. Used to test scenarios with outstanding send
-     * operations.
-     */
-    private static DummyWebSocketServer notReadingServer() {
-        return new DummyWebSocketServer() {
-            @Override
-            protected void serve(SocketChannel channel) throws IOException {
-                try {
-                    Thread.sleep(Long.MAX_VALUE);
-                } catch (InterruptedException e) {
-                    throw new IOException(e);
-                }
-            }
-        };
-    }
-
-    private static String stringWith2NBytes(int n) {
-        // -- Russian Alphabet (33 characters, 2 bytes per char) --
-        char[] abc = {
-                0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0401, 0x0416,
-                0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
-                0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426,
-                0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E,
-                0x042F,
-        };
-        // repeat cyclically
-        StringBuilder sb = new StringBuilder(n);
-        for (int i = 0, j = 0; i < n; i++, j = (j + 1) % abc.length) {
-            sb.append(abc[j]);
-        }
-        String s = sb.toString();
-        assert s.length() == n && s.getBytes(StandardCharsets.UTF_8).length == 2 * n;
-        return s;
-    }
-
     @Test
-    public void testIllegalArgument() throws IOException {
+    public void illegalArgument() throws IOException {
         try (DummyWebSocketServer server = new DummyWebSocketServer()) {
             server.open();
             WebSocket ws = newHttpClient()
@@ -143,19 +86,19 @@
             assertFails(IAE, ws.sendPong(ByteBuffer.allocate(129)));
             assertFails(IAE, ws.sendPong(ByteBuffer.allocate(256)));
 
-            assertFails(IOE, ws.sendText(incompleteString(), true));
-            assertFails(IOE, ws.sendText(incompleteString(), false));
-            assertFails(IOE, ws.sendText(malformedString(), true));
-            assertFails(IOE, ws.sendText(malformedString(), false));
+            assertFails(IOE, ws.sendText(Support.incompleteString(), true));
+            assertFails(IOE, ws.sendText(Support.incompleteString(), false));
+            assertFails(IOE, ws.sendText(Support.malformedString(), true));
+            assertFails(IOE, ws.sendText(Support.malformedString(), false));
 
-            assertFails(IAE, ws.sendClose(NORMAL_CLOSURE, stringWithNBytes(124)));
-            assertFails(IAE, ws.sendClose(NORMAL_CLOSURE, stringWithNBytes(125)));
-            assertFails(IAE, ws.sendClose(NORMAL_CLOSURE, stringWithNBytes(128)));
-            assertFails(IAE, ws.sendClose(NORMAL_CLOSURE, stringWithNBytes(256)));
-            assertFails(IAE, ws.sendClose(NORMAL_CLOSURE, stringWithNBytes(257)));
-            assertFails(IAE, ws.sendClose(NORMAL_CLOSURE, stringWith2NBytes((123 / 2) + 1)));
-            assertFails(IAE, ws.sendClose(NORMAL_CLOSURE, malformedString()));
-            assertFails(IAE, ws.sendClose(NORMAL_CLOSURE, incompleteString()));
+            assertFails(IAE, ws.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(124)));
+            assertFails(IAE, ws.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(125)));
+            assertFails(IAE, ws.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(128)));
+            assertFails(IAE, ws.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(256)));
+            assertFails(IAE, ws.sendClose(NORMAL_CLOSURE, Support.stringWithNBytes(257)));
+            assertFails(IAE, ws.sendClose(NORMAL_CLOSURE, Support.stringWith2NBytes((123 / 2) + 1)));
+            assertFails(IAE, ws.sendClose(NORMAL_CLOSURE, Support.malformedString()));
+            assertFails(IAE, ws.sendClose(NORMAL_CLOSURE, Support.incompleteString()));
 
             assertFails(IAE, ws.sendClose(-2, "a reason"));
             assertFails(IAE, ws.sendClose(-1, "a reason"));
@@ -187,23 +130,98 @@
         }
     }
 
-    private static String malformedString() {
-        return new String(new char[]{0xDC00, 0xD800});
-    }
+    @Test(dataProvider = "booleans")
+    public void pendingTextPingClose(boolean last) throws Exception {
+        try (DummyWebSocketServer server = Support.notReadingServer()) {
+            server.open();
+            WebSocket ws = newHttpClient()
+                    .newWebSocketBuilder()
+                    .buildAsync(server.getURI(), new WebSocket.Listener() { })
+                    .join();
 
-    private static String incompleteString() {
-        return new String(new char[]{0xD800});
+            CharBuffer data = CharBuffer.allocate(65536);
+            CompletableFuture<WebSocket> cfText;
+            for (int i = 0; ; i++) {  // fill up the send buffer
+                System.out.printf("begin cycle #%s at %s%n",
+                                  i, System.currentTimeMillis());
+                cfText = ws.sendText(data, last);
+                try {
+                    cfText.get(5, TimeUnit.SECONDS);
+                    data.clear();
+                } catch (TimeoutException e) {
+                    break;
+                } finally {
+                    System.out.printf("end cycle #%s at %s%n",
+                                      i, System.currentTimeMillis());
+                }
+            }
+            assertFails(ISE, ws.sendText("", true));
+            assertFails(ISE, ws.sendText("", false));
+            assertFails(ISE, ws.sendBinary(ByteBuffer.allocate(0), true));
+            assertFails(ISE, ws.sendBinary(ByteBuffer.allocate(0), false));
+            CompletableFuture<WebSocket> cfPing = ws.sendPing(ByteBuffer.allocate(125));
+            assertHangs(cfPing);
+            assertFails(ISE, ws.sendPing(ByteBuffer.allocate(125)));
+            assertFails(ISE, ws.sendPong(ByteBuffer.allocate(125)));
+            CompletableFuture<WebSocket> cfClose = ws.sendClose(WebSocket.NORMAL_CLOSURE, "ok");
+            assertHangs(cfClose);
+            ws.abort();
+            assertFails(IOE, cfText);
+            assertFails(IOE, cfPing);
+            assertFails(IOE, cfClose);
+        }
     }
 
-    private static String stringWithNBytes(int n) {
-        char[] chars = new char[n];
-        Arrays.fill(chars, 'A');
-        return new String(chars);
+    /* shortcut */
+    public static void assertHangs(CompletionStage<?> stage) {
+        Support.assertHangs(stage);
     }
 
-    @Test
-    public void outstanding1() throws Exception {
-        try (DummyWebSocketServer server = notReadingServer()) {
+    @Test(dataProvider = "booleans")
+    public void pendingTextPongClose(boolean last) throws Exception {
+        try (DummyWebSocketServer server = Support.notReadingServer()) {
+            server.open();
+            WebSocket ws = newHttpClient()
+                    .newWebSocketBuilder()
+                    .buildAsync(server.getURI(), new WebSocket.Listener() { })
+                    .join();
+
+            CharBuffer data = CharBuffer.allocate(65536);
+            CompletableFuture<WebSocket> cfText;
+            for (int i = 0; ; i++) {  // fill up the send buffer
+                System.out.printf("begin cycle #%s at %s%n",
+                                  i, System.currentTimeMillis());
+                cfText = ws.sendText(data, last);
+                try {
+                    cfText.get(5, TimeUnit.SECONDS);
+                    data.clear();
+                } catch (TimeoutException e) {
+                    break;
+                } finally {
+                    System.out.printf("end cycle #%s at %s%n",
+                                      i, System.currentTimeMillis());
+                }
+            }
+            assertFails(ISE, ws.sendText("", true));
+            assertFails(ISE, ws.sendText("", false));
+            assertFails(ISE, ws.sendBinary(ByteBuffer.allocate(0), true));
+            assertFails(ISE, ws.sendBinary(ByteBuffer.allocate(0), false));
+            CompletableFuture<WebSocket> cfPong = ws.sendPong(ByteBuffer.allocate(125));
+            assertHangs(cfPong);
+            assertFails(ISE, ws.sendPing(ByteBuffer.allocate(125)));
+            assertFails(ISE, ws.sendPong(ByteBuffer.allocate(125)));
+            CompletableFuture<WebSocket> cfClose = ws.sendClose(WebSocket.NORMAL_CLOSURE, "ok");
+            assertHangs(cfClose);
+            ws.abort();
+            assertFails(IOE, cfText);
+            assertFails(IOE, cfPong);
+            assertFails(IOE, cfClose);
+        }
+    }
+
+    @Test(dataProvider = "booleans")
+    public void pendingBinaryPingClose(boolean last) throws Exception {
+        try (DummyWebSocketServer server = Support.notReadingServer()) {
             server.open();
             WebSocket ws = newHttpClient()
                     .newWebSocketBuilder()
@@ -211,35 +229,55 @@
                     .join();
 
             ByteBuffer data = ByteBuffer.allocate(65536);
+            CompletableFuture<WebSocket> cfBinary;
             for (int i = 0; ; i++) {  // fill up the send buffer
-                System.out.println("cycle #" + i);
+                System.out.printf("begin cycle #%s at %s%n",
+                                  i, System.currentTimeMillis());
+                cfBinary = ws.sendBinary(data, last);
                 try {
-                    ws.sendBinary(data, true).get(10, TimeUnit.SECONDS);
+                    cfBinary.get(5, TimeUnit.SECONDS);
                     data.clear();
                 } catch (TimeoutException e) {
                     break;
+                } finally {
+                    System.out.printf("end cycle #%s at %s%n",
+                                      i, System.currentTimeMillis());
                 }
             }
+            assertFails(ISE, ws.sendText("", true));
+            assertFails(ISE, ws.sendText("", false));
             assertFails(ISE, ws.sendBinary(ByteBuffer.allocate(0), true));
-            assertFails(ISE, ws.sendText("", true));
+            assertFails(ISE, ws.sendBinary(ByteBuffer.allocate(0), false));
+            CompletableFuture<WebSocket> cfPing = ws.sendPing(ByteBuffer.allocate(125));
+            assertHangs(cfPing);
+            assertFails(ISE, ws.sendPing(ByteBuffer.allocate(125)));
+            assertFails(ISE, ws.sendPong(ByteBuffer.allocate(125)));
+            CompletableFuture<WebSocket> cfClose = ws.sendClose(WebSocket.NORMAL_CLOSURE, "ok");
+            assertHangs(cfClose);
+            ws.abort();
+            assertFails(IOE, cfBinary);
+            assertFails(IOE, cfPing);
+            assertFails(IOE, cfClose);
         }
     }
 
-    @Test
-    public void outstanding2() throws Exception {
-        try (DummyWebSocketServer server = notReadingServer()) {
+    @Test(dataProvider = "booleans")
+    public void pendingBinaryPongClose(boolean last) throws Exception {
+        try (DummyWebSocketServer server = Support.notReadingServer()) {
             server.open();
             WebSocket ws = newHttpClient()
                     .newWebSocketBuilder()
                     .buildAsync(server.getURI(), new WebSocket.Listener() { })
                     .join();
 
-            CharBuffer data = CharBuffer.allocate(65536);
+            ByteBuffer data = ByteBuffer.allocate(65536);
+            CompletableFuture<WebSocket> cfBinary;
             for (int i = 0; ; i++) {  // fill up the send buffer
                 System.out.printf("begin cycle #%s at %s%n",
                                   i, System.currentTimeMillis());
+                cfBinary = ws.sendBinary(data, last);
                 try {
-                    ws.sendText(data, true).get(10, TimeUnit.SECONDS);
+                    cfBinary.get(5, TimeUnit.SECONDS);
                     data.clear();
                 } catch (TimeoutException e) {
                     break;
@@ -249,12 +287,166 @@
                 }
             }
             assertFails(ISE, ws.sendText("", true));
+            assertFails(ISE, ws.sendText("", false));
             assertFails(ISE, ws.sendBinary(ByteBuffer.allocate(0), true));
+            assertFails(ISE, ws.sendBinary(ByteBuffer.allocate(0), false));
+            CompletableFuture<WebSocket> cfPong = ws.sendPong(ByteBuffer.allocate(125));
+            assertHangs(cfPong);
+            assertFails(ISE, ws.sendPing(ByteBuffer.allocate(125)));
+            assertFails(ISE, ws.sendPong(ByteBuffer.allocate(125)));
+            CompletableFuture<WebSocket> cfClose = ws.sendClose(WebSocket.NORMAL_CLOSURE, "ok");
+            assertHangs(cfClose);
+            ws.abort();
+            assertFails(IOE, cfBinary);
+            assertFails(IOE, cfPong);
+            assertFails(IOE, cfClose);
+        }
+    }
+
+    @Test(dataProvider = "booleans")
+    public void pendingPingTextClose(boolean last) throws Exception {
+        try (DummyWebSocketServer server = Support.notReadingServer()) {
+            server.open();
+            WebSocket ws = newHttpClient()
+                    .newWebSocketBuilder()
+                    .buildAsync(server.getURI(), new WebSocket.Listener() { })
+                    .join();
+
+            ByteBuffer data = ByteBuffer.allocate(125);
+            CompletableFuture<WebSocket> cfPing;
+            for (int i = 0; ; i++) {  // fill up the send buffer
+                System.out.println("cycle #" + i);
+                cfPing = ws.sendPing(data);
+                try {
+                    cfPing.get(5, TimeUnit.SECONDS);
+                    data.clear();
+                } catch (TimeoutException e) {
+                    break;
+                }
+            }
+            assertFails(ISE, ws.sendPing(ByteBuffer.allocate(125)));
+            assertFails(ISE, ws.sendPong(ByteBuffer.allocate(125)));
+            CompletableFuture<WebSocket> cfText = ws.sendText("hello", last);
+            assertHangs(cfText);
+            CompletableFuture<WebSocket> cfClose
+                    = ws.sendClose(WebSocket.NORMAL_CLOSURE, "ok");
+            assertHangs(cfClose);
+            ws.abort();
+            assertFails(IOE, cfPing);
+            assertFails(IOE, cfText);
+            assertFails(IOE, cfClose);
+        }
+    }
+
+    @Test(dataProvider = "booleans")
+    public void pendingPingBinaryClose(boolean last) throws Exception {
+        try (DummyWebSocketServer server = Support.notReadingServer()) {
+            server.open();
+            WebSocket ws = newHttpClient()
+                    .newWebSocketBuilder()
+                    .buildAsync(server.getURI(), new WebSocket.Listener() { })
+                    .join();
+
+            ByteBuffer data = ByteBuffer.allocate(125);
+            CompletableFuture<WebSocket> cfPing;
+            for (int i = 0; ; i++) {  // fill up the send buffer
+                System.out.println("cycle #" + i);
+                cfPing = ws.sendPing(data);
+                try {
+                    cfPing.get(5, TimeUnit.SECONDS);
+                    data.clear();
+                } catch (TimeoutException e) {
+                    break;
+                }
+            }
+            assertFails(ISE, ws.sendPing(ByteBuffer.allocate(125)));
+            assertFails(ISE, ws.sendPong(ByteBuffer.allocate(125)));
+            CompletableFuture<WebSocket> cfBinary
+                    = ws.sendBinary(ByteBuffer.allocate(4), last);
+            assertHangs(cfBinary);
+            CompletableFuture<WebSocket> cfClose
+                    = ws.sendClose(WebSocket.NORMAL_CLOSURE, "ok");
+            assertHangs(cfClose);
+            ws.abort();
+            assertFails(IOE, cfPing);
+            assertFails(IOE, cfBinary);
+            assertFails(IOE, cfClose);
+        }
+    }
+
+    @Test(dataProvider = "booleans")
+    public void pendingPongTextClose(boolean last) throws Exception {
+        try (DummyWebSocketServer server = Support.notReadingServer()) {
+            server.open();
+            WebSocket ws = newHttpClient()
+                    .newWebSocketBuilder()
+                    .buildAsync(server.getURI(), new WebSocket.Listener() { })
+                    .join();
+
+            ByteBuffer data = ByteBuffer.allocate(125);
+            CompletableFuture<WebSocket> cfPong;
+            for (int i = 0; ; i++) {  // fill up the send buffer
+                System.out.println("cycle #" + i);
+                cfPong = ws.sendPong(data);
+                try {
+                    cfPong.get(5, TimeUnit.SECONDS);
+                    data.clear();
+                } catch (TimeoutException e) {
+                    break;
+                }
+            }
+            assertFails(ISE, ws.sendPing(ByteBuffer.allocate(125)));
+            assertFails(ISE, ws.sendPong(ByteBuffer.allocate(125)));
+            CompletableFuture<WebSocket> cfText = ws.sendText("hello", last);
+            assertHangs(cfText);
+            CompletableFuture<WebSocket> cfClose
+                    = ws.sendClose(WebSocket.NORMAL_CLOSURE, "ok");
+            assertHangs(cfClose);
+            ws.abort();
+            assertFails(IOE, cfPong);
+            assertFails(IOE, cfText);
+            assertFails(IOE, cfClose);
+        }
+    }
+
+    @Test(dataProvider = "booleans")
+    public void pendingPongBinaryClose(boolean last) throws Exception {
+        try (DummyWebSocketServer server = Support.notReadingServer()) {
+            server.open();
+            WebSocket ws = newHttpClient()
+                    .newWebSocketBuilder()
+                    .buildAsync(server.getURI(), new WebSocket.Listener() { })
+                    .join();
+
+            ByteBuffer data = ByteBuffer.allocate(125);
+            CompletableFuture<WebSocket> cfPong;
+            for (int i = 0; ; i++) {  // fill up the send buffer
+                System.out.println("cycle #" + i);
+                cfPong = ws.sendPong(data);
+                try {
+                    cfPong.get(5, TimeUnit.SECONDS);
+                    data.clear();
+                } catch (TimeoutException e) {
+                    break;
+                }
+            }
+            assertFails(ISE, ws.sendPing(ByteBuffer.allocate(125)));
+            assertFails(ISE, ws.sendPong(ByteBuffer.allocate(125)));
+            CompletableFuture<WebSocket> cfBinary
+                    = ws.sendBinary(ByteBuffer.allocate(4), last);
+            assertHangs(cfBinary);
+            CompletableFuture<WebSocket> cfClose
+                    = ws.sendClose(WebSocket.NORMAL_CLOSURE, "ok");
+            assertHangs(cfClose);
+            ws.abort();
+            assertFails(IOE, cfPong);
+            assertFails(IOE, cfBinary);
+            assertFails(IOE, cfClose);
         }
     }
 
     @Test
-    public void interleavingTypes1() throws IOException {
+    public void partialBinaryThenText() throws IOException {
         try (DummyWebSocketServer server = new DummyWebSocketServer()) {
             server.open();
             WebSocket ws = newHttpClient()
@@ -265,11 +457,14 @@
             ws.sendBinary(ByteBuffer.allocate(16), false).join();
             assertFails(ISE, ws.sendText("text", false));
             assertFails(ISE, ws.sendText("text", true));
+            // Pings & Pongs are fine
+            ws.sendPing(ByteBuffer.allocate(125)).join();
+            ws.sendPong(ByteBuffer.allocate(125)).join();
         }
     }
 
     @Test
-    public void interleavingTypes2() throws IOException {
+    public void partialTextThenBinary() throws IOException {
         try (DummyWebSocketServer server = new DummyWebSocketServer()) {
             server.open();
             WebSocket ws = newHttpClient()
@@ -280,6 +475,9 @@
             ws.sendText("text", false).join();
             assertFails(ISE, ws.sendBinary(ByteBuffer.allocate(16), false));
             assertFails(ISE, ws.sendBinary(ByteBuffer.allocate(16), true));
+            // Pings & Pongs are fine
+            ws.sendPing(ByteBuffer.allocate(125)).join();
+            ws.sendPong(ByteBuffer.allocate(125)).join();
         }
     }
 
@@ -319,7 +517,7 @@
 
     @Test
     public void sendMethodsThrowIOE2() throws Exception {
-        try (DummyWebSocketServer server = serverWithCannedData(0x88, 0x00)) {
+        try (DummyWebSocketServer server = Support.serverWithCannedData(0x88, 0x00)) {
             server.open();
             CompletableFuture<Void> onCloseCalled = new CompletableFuture<>();
             CompletableFuture<Void> canClose = new CompletableFuture<>();
@@ -396,7 +594,7 @@
         };
         CompletableFuture<List<byte[]>> actual = new CompletableFuture<>();
 
-        try (DummyWebSocketServer server = serverWithCannedData(binary)) {
+        try (DummyWebSocketServer server = Support.serverWithCannedData(binary)) {
             server.open();
 
             WebSocket.Listener listener = new WebSocket.Listener() {
@@ -498,7 +696,7 @@
         };
         CompletableFuture<List<String>> actual = new CompletableFuture<>();
 
-        try (DummyWebSocketServer server = serverWithCannedData(binary)) {
+        try (DummyWebSocketServer server = Support.serverWithCannedData(binary)) {
             server.open();
 
             WebSocket.Listener listener = new WebSocket.Listener() {
@@ -588,7 +786,7 @@
         CompletableFuture<List<String>> actual = new CompletableFuture<>();
 
 
-        try (DummyWebSocketServer server = serverWithCannedData(binary)) {
+        try (DummyWebSocketServer server = Support.serverWithCannedData(binary)) {
             server.open();
 
             WebSocket.Listener listener = new WebSocket.Listener() {
@@ -668,13 +866,14 @@
     }
 
     /*
-     * The server sends Pong messages. The WebSocket replies to messages automatically.
-     * According to RFC 6455 The WebSocket is free
+     * The server sends Ping messages. The WebSocket replies to these messages
+     * automatically. According to RFC 6455 a WebSocket client is free to reply
+     * only to the most recent Pings.
      */
     @Test(dataProvider = "nPings")
     public void automaticPongs(int nPings) throws Exception {
         // big enough to not bother with resize
-        ByteBuffer buffer = ByteBuffer.allocate(16384);
+        ByteBuffer buffer = ByteBuffer.allocate(65536);
         Frame.HeaderWriter w = new Frame.HeaderWriter();
         for (int i = 0; i < nPings; i++) {
             w.fin(true)
@@ -691,7 +890,7 @@
          .write(buffer);
         buffer.putChar((char) 1000);
         buffer.flip();
-        try (DummyWebSocketServer server = serverWithCannedData(buffer.array())) {
+        try (DummyWebSocketServer server = Support.serverWithCannedData(buffer.array())) {
             MockListener listener = new MockListener();
             server.open();
             WebSocket ws = newHttpClient()
@@ -768,4 +967,9 @@
     public Object[][] nPings() {
         return new Object[][]{{1}, {2}, {4}, {8}, {9}, {1023}};
     }
+
+    @DataProvider(name = "booleans")
+    public Object[][] booleans() {
+        return new Object[][]{{Boolean.TRUE}, {Boolean.FALSE}};
+    }
 }